Skip to content

Conversation

@Seelengrab
Copy link
Contributor

Fixes #54397

What remains is that the effectively allowed input still needs to be convertible to Int and non-negative. So things like typemax(Int128) won't work.

Fixes JuliaLang#54397

What remains is that the effectively allowed input still needs
to be convertible to `Int`. So things like `typemax(Int128)` won't
work, and neither will negative values.
@Seelengrab Seelengrab added the randomness Random number generation and the Random stdlib label May 8, 2024
global randstring

function randstring(r::AbstractRNG, chars=b, n::Integer=8)
_n = convert(Int, n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure it is worth doing in this specific instance but presumably structuring it like:

f(x::Integer) = f(convert(Int, n))
f(x::Int) = ...

would reduce compilation time since you would not compile the main function body for multiple integer types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For cases where lots of different types are passed to randstring, that's certainly the case, yeah. I'm not sure how common that would be though, there's lots of better ways to control the length of a generated string other than through the type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @KristofferC is just referring to the amount of code that is generated by using function barriers or:
https://docs.julialang.org/en/v1/manual/performance-tips/#kernel-functions

Copy link
Contributor Author

@Seelengrab Seelengrab May 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm referring to the likelihood of hitting that & the additional compilation overhead being a significant slowdown. If this is a bottleneck, I'd first recommend switching to a different scheme for generating the length (with just Int) than optimize the compilation overhead.

Copy link
Contributor

@sjkelly sjkelly May 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, and the problem is that this PR would allow someone to have a type unstable call site with various Integer types for length, rather than error as it currently does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would that inherently be a problem? We don't prevent type instabilities in user code in other places either.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Krostoffer's convert approach is a good idea. Yes, it's ok to just allow a different integer type flow through but in this case Int covers the entire range of reasonable values and converting avoids additional compilation.

Copy link
Contributor Author

@Seelengrab Seelengrab Jun 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no other integer type flowing through though; the code in this PR already calls _convert(Int, ..), just directly instead of in a function barrier. This function is a total of 11 lines long, I seriously doubt that this leads to a bottleneck in either compilation time or binary size. At that size, I'm willing to bet that the inlining pass costs more than potential dual compilation if anyone calls this with an UInt8..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but every little bit counts. Why not just change it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I agree with the comment by Kristoffer that it's probably not worth doing in this case. Is it a problem that I agree with the reviewer? As it stands, this just seems like premature optimization of a hypothetical to me.

@sjkelly
Copy link
Contributor

sjkelly commented May 9, 2024 via email

@Seelengrab
Copy link
Contributor Author

Seelengrab commented May 9, 2024

Since Kristoffer mentioned that it's probably not worth it in this PR, I've chosen to keep the code simpler to follow without having to disentangle niche dispatch/compilation optimizations.

@Seelengrab
Copy link
Contributor Author

Does this need anything else (cc @KristofferC)?

@rfourquet
Copy link
Member

I'm inclined to merge as is, and if someone is motivated to make a follow-up PR to make the suggested change (a similar change could also be made to #58533 at the same time), that could be merged as well. This PR is somewhat a fix and doesn't make anything worse, so it should be included in the next release in some form or another.

global randstring

function randstring(r::AbstractRNG, chars=b, n::Integer=8)
_n = convert(Int, n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this:

Suggested change
_n = convert(Int, n)
n = convert(Int, n)::Int

Then the rest of the diff can be dropped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdyt @Seelengrab ?

Copy link
Contributor Author

@Seelengrab Seelengrab Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this cause a type instability, since the original argument was ::Integer? Or does this assertion override the originally inferred type for n?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it's fine yes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no type instability. When code like n = f(n) gets lowered to SSA form, there are two different variables, for example n@_1 and n@_2.

Copy link
Member

@nsajko nsajko Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See for yourself with code_lowered or code_typed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However I'd also suggest just calling the Int constructor instead of convert:

Suggested change
_n = convert(Int, n)
n = Int(n)::Int

return str
else
v = Vector{T}(undef, n)
v = Vector{T}(undef, _n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
v = Vector{T}(undef, _n)
v = Vector{T}(undef, n)

Comment on lines +77 to +78
str = Base._string_n(_n)
GC.@preserve str rand!(r, UnsafeView(pointer(str), _n), chars)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
str = Base._string_n(_n)
GC.@preserve str rand!(r, UnsafeView(pointer(str), _n), chars)
str = Base._string_n(n)
GC.@preserve str rand!(r, UnsafeView(pointer(str), n), chars)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

randomness Random number generation and the Random stdlib status: waiting for PR author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Random stdlib: randstring(rand(UInt8)) errors

7 participants