Skip to content

Commit 67e3ad9

Browse files
authored
Set default random arg to nil instead of Random::DEFAULT (#16299)
Third step for internalizing `Random::DEFAULT`.
1 parent 99e5252 commit 67e3ad9

File tree

8 files changed

+92
-42
lines changed

8 files changed

+92
-42
lines changed

src/array.cr

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,9 +1604,10 @@ class Array(T)
16041604
shift { nil }
16051605
end
16061606

1607-
# Returns an array with all the elements in the collection randomized
1608-
# using the given *random* number generator.
1609-
def shuffle(random : Random = Random::DEFAULT) : Array(T)
1607+
# Returns a new instance with all elements in the collection randomized.
1608+
#
1609+
# See `Indexable::Mutable#shuffle!` for details.
1610+
def shuffle(random : Random? = nil) : Array(T)
16101611
dup.shuffle!(random)
16111612
end
16121613

src/crystal/system/file.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ module Crystal::System::File
5151

5252
LOWER_ALPHANUM = "0123456789abcdefghijklmnopqrstuvwxyz".to_slice
5353

54-
def self.mktemp(prefix : String?, suffix : String?, dir : String, random : ::Random = ::Random::DEFAULT) : {FileDescriptor::Handle, String, Bool}
54+
def self.mktemp(prefix : String?, suffix : String?, dir : String, random : ::Random? = nil) : {FileDescriptor::Handle, String, Bool}
5555
flags = LibC::O_RDWR | LibC::O_CREAT | LibC::O_EXCL
5656
perm = ::File::Permissions.new(0o600)
5757

src/enumerable.cr

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,19 +1565,27 @@ module Enumerable(T)
15651565
reject { |e| pattern === e }
15661566
end
15671567

1568-
# Returns an `Array` of *n* random elements from `self`, using the given
1569-
# *random* number generator. All elements have equal probability of being
1570-
# drawn. Sampling is done without replacement; if *n* is larger than the size
1571-
# of this collection, the returned `Array` has the same size as `self`.
1568+
# Returns an `Array` of *n* random elements from `self`. All elements have
1569+
# equal probability of being drawn. Sampling is done without replacement; if
1570+
# *n* is larger than the size of this collection, the returned `Array` has the
1571+
# same size as `self`.
15721572
#
15731573
# Raises `ArgumentError` if *n* is negative.
15741574
#
15751575
# ```
1576-
# [1, 2, 3, 4, 5].sample(2) # => [3, 5]
1577-
# {1, 2, 3, 4, 5}.sample(2) # => [3, 4]
1578-
# {1, 2, 3, 4, 5}.sample(2, Random.new(1)) # => [1, 5]
1576+
# [1, 2, 3, 4, 5].sample(2) # => [3, 5]
1577+
# {1, 2, 3, 4, 5}.sample(2) # => [3, 4]
15791578
# ```
1580-
def sample(n : Int, random : Random = Random::DEFAULT) : Array(T)
1579+
#
1580+
# Uses the *random* instance when provided if the randomness needs to be
1581+
# controlled or to follow some traits. For example the following calls use a
1582+
# custom seed or a secure random source:
1583+
#
1584+
# ```
1585+
# {1, 2, 3, 4, 5}.sample(2, Random.new(1)) # => [1, 5]
1586+
# {1, 2, 3, 4, 5}.sample(2, Random::Secure) # => [2, 5]
1587+
# ```
1588+
def sample(n : Int, random : Random? = nil) : Array(T)
15811589
raise ArgumentError.new("Can't sample negative number of elements") if n < 0
15821590

15831591
# Unweighted reservoir sampling:
@@ -1588,40 +1596,54 @@ module Enumerable(T)
15881596
ary = Array(T).new(n)
15891597
return ary if n == 0
15901598

1599+
# FIXME: thread unsafe (#each may yield and the fiber switch threads)
1600+
rng = random || Random::DEFAULT
1601+
15911602
each_with_index do |elem, i|
15921603
if i < n
15931604
ary << elem
15941605
else
1595-
j = random.rand(i + 1)
1606+
j = rng.rand(i + 1)
15961607
if j < n
15971608
ary.to_unsafe[j] = elem
15981609
end
15991610
end
16001611
end
16011612

1602-
ary.shuffle!(random)
1613+
ary.shuffle!(rng)
16031614
end
16041615

1605-
# Returns a random element from `self`, using the given *random* number
1606-
# generator. All elements have equal probability of being drawn.
1616+
# Returns a random element from `self`. All elements have equal probability of
1617+
# being drawn.
16071618
#
16081619
# Raises `IndexError` if `self` is empty.
16091620
#
16101621
# ```
16111622
# a = [1, 2, 3]
1612-
# a.sample # => 2
1613-
# a.sample # => 1
1614-
# a.sample(Random.new(1)) # => 3
1623+
# a.sample # => 2
1624+
# a.sample # => 1
16151625
# ```
1616-
def sample(random : Random = Random::DEFAULT) : T
1626+
#
1627+
# Uses the *random* instance when provided if the randomness needs to be
1628+
# controlled or to follow some traits. For example the following calls use a
1629+
# custom seed or a secure random source:
1630+
#
1631+
# ```
1632+
# a.sample(Random.new(1)) # => 3
1633+
# a.sample(Random::Secure) # => 1
1634+
# ```
1635+
def sample(random : Random? = nil) : T
16171636
value = uninitialized T
16181637
found = false
16191638

1639+
# FIXME: thread unsafe (#each may yield and the fiber switch threads)
1640+
rng = random || Random::DEFAULT
1641+
16201642
each_with_index do |elem, i|
16211643
if !found
16221644
value = elem
16231645
found = true
1624-
elsif random.rand(i + 1) == 0
1646+
elsif rng.rand(i + 1) == 0
16251647
value = elem
16261648
end
16271649
end

src/indexable.cr

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -950,21 +950,31 @@ module Indexable(T)
950950
#
951951
# ```
952952
# a = [1, 2, 3]
953-
# a.sample # => 3
954-
# a.sample # => 1
953+
# a.sample # => 3
954+
# a.sample # => 1
955+
# ```
956+
#
957+
# Uses the *random* instance when provided if the randomness needs to be
958+
# controlled or to follow some traits. For example the following sample will
959+
# always return the same value:
960+
#
961+
# ```
962+
# a = [1, 2, 3]
963+
# a.sample(Random.new(1)) # => 2
955964
# a.sample(Random.new(1)) # => 2
956965
# ```
957-
def sample(random : Random = Random::DEFAULT)
966+
def sample(random : Random? = nil)
958967
raise IndexError.new("Can't sample empty collection") if size == 0
959-
unsafe_fetch(random.rand(size))
968+
rng = random || Random::DEFAULT
969+
unsafe_fetch(rng.rand(size))
960970
end
961971

962972
# :inherit:
963973
#
964974
# If `self` is not empty and `n` is equal to 1, calls `sample(random)` exactly
965975
# once. Thus, *random* will be left in a different state compared to the
966976
# implementation in `Enumerable`.
967-
def sample(n : Int, random : Random = Random::DEFAULT) : Array(T)
977+
def sample(n : Int, random : Random? = nil) : Array(T)
968978
return super unless n == 1
969979

970980
if empty?

src/indexable/mutable.cr

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,17 +251,29 @@ module Indexable::Mutable(T)
251251
self
252252
end
253253

254-
# Modifies `self` by randomizing the order of elements in the collection
255-
# using the given *random* number generator. Returns `self`.
254+
# Modifies `self` by randomizing the order of elements in the collection.
255+
# Returns `self`.
256256
#
257257
# ```
258258
# a = [1, 2, 3, 4, 5]
259+
# a.shuffle! # => [3, 5, 2, 4, 1]
260+
# a # => [3, 5, 2, 4, 1]
261+
# ```
262+
#
263+
# Uses the *random* instance when provided if the randomness needs to be
264+
# controlled or to follow some traits. For example the following shuffle will
265+
# always result in the same order:
266+
#
267+
# ```
268+
# a = [1, 2, 3, 4, 5]
269+
# a.shuffle!(Random.new(42)) # => [3, 2, 4, 5, 1]
259270
# a.shuffle!(Random.new(42)) # => [3, 2, 4, 5, 1]
260271
# a # => [3, 2, 4, 5, 1]
261272
# ```
262-
def shuffle!(random : Random = Random::DEFAULT) : self
273+
def shuffle!(random : Random? = nil) : self
274+
rng = random || Random::DEFAULT
263275
(size - 1).downto(1) do |i|
264-
j = random.rand(i + 1)
276+
j = rng.rand(i + 1)
265277
swap(i, j)
266278
end
267279
self

src/pointer.cr

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,9 +382,10 @@ struct Pointer(T)
382382
# ptr.shuffle!(4)
383383
# ptr # [3, 4, 1, 2]
384384
# ```
385-
def shuffle!(count : Int, random = Random::DEFAULT)
385+
def shuffle!(count : Int, random : Random? = nil)
386+
rng = random || Random::DEFAULT
386387
(count - 1).downto(1) do |i|
387-
j = random.rand(i + 1)
388+
j = rng.rand(i + 1)
388389
swap(i, j)
389390
end
390391
self

src/range.cr

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,11 +344,13 @@ struct Range(B, E)
344344
# the method simply calls `random.rand(self)`.
345345
#
346346
# Raises `ArgumentError` if `self` is an open range.
347-
def sample(random : Random = Random::DEFAULT)
347+
def sample(random : Random? = nil)
348+
rng = random || Random::DEFAULT
349+
348350
{% if B < Int && E < Int %}
349-
random.rand(self)
351+
rng.rand(self)
350352
{% elsif B < Float && E < Float %}
351-
random.rand(self)
353+
rng.rand(self)
352354
{% elsif B.nilable? || E.nilable? %}
353355
b = self.begin
354356
e = self.end
@@ -357,7 +359,7 @@ struct Range(B, E)
357359
raise ArgumentError.new("Can't sample an open range")
358360
end
359361

360-
Range.new(b, e, @exclusive).sample(random)
362+
Range.new(b, e, @exclusive).sample(rng)
361363
{% else %}
362364
super
363365
{% end %}
@@ -368,7 +370,9 @@ struct Range(B, E)
368370
# If `self` is not empty and `n` is equal to 1, calls `sample(random)` exactly
369371
# once. Thus, *random* will be left in a different state compared to the
370372
# implementation in `Enumerable`.
371-
def sample(n : Int, random = Random::DEFAULT)
373+
def sample(n : Int, random : Random? = nil)
374+
rng = random || Random::DEFAULT
375+
372376
if self.begin.nil? || self.end.nil?
373377
raise ArgumentError.new("Can't sample an open range")
374378
end
@@ -402,11 +406,11 @@ struct Range(B, E)
402406
# If we must return all values in the range...
403407
if possible == available
404408
result = Array(B).new(possible) { |i| min + i }
405-
result.shuffle!(random)
409+
result.shuffle!(rng)
406410
return result
407411
end
408412

409-
range_sample(n, random)
413+
range_sample(n, rng)
410414
{% elsif B < Float && E < Float %}
411415
min = self.begin
412416
max = self.end
@@ -419,13 +423,13 @@ struct Range(B, E)
419423
return [min]
420424
end
421425

422-
range_sample(n, random)
426+
range_sample(n, rng)
423427
{% else %}
424428
case n
425429
when 0
426430
[] of B
427431
when 1
428-
[sample(random)]
432+
[sample(rng)]
429433
else
430434
super
431435
end

src/slice.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ struct Slice(T)
358358
# :inherit:
359359
#
360360
# Raises if this slice is read-only.
361-
def shuffle!(random : Random = Random::DEFAULT) : self
361+
def shuffle!(random : Random? = nil) : self
362362
check_writable
363363
super
364364
end

0 commit comments

Comments
 (0)