Skip to content

Commit b0b45de

Browse files
committed
introduce a Pair API (alternative to make)
1 parent 544d965 commit b0b45de

3 files changed

Lines changed: 50 additions & 1 deletion

File tree

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ is omitted). For example, `rand(make(Array, 2, 3), 3)` creates an array of matri
4141
Of course, `make` is not necessary, in that the same can be achieved with an ad hoc `struct`,
4242
which in some cases is clearer (e.g. `Normal(m, s)` rather than something like `make(Float64, Val(:Normal), m, s)`).
4343

44+
As an experimental feature, the following alternative API is available:
45+
- `rand(T => x)` is equivalent to `rand(make(T, x))`
46+
- `rand(T => (x, y, ...))` is equivalent to `rand(make(T, x, y, ...))`
47+
48+
This is for convenience only (it may be more readable), but may be less efficient due to the
49+
fact that the type of a pair containing a type doesn't know this exact type (e.g. `Pair => Int`
50+
has type `Pair{UnionAll,DataType}`), so `rand` can't infer the type of the generated value.
51+
Thanks to inlining, the inferred types can however be sufficiently tight in some cases
52+
(e.g. `rand(Complex => Int, 3)` is of type `Vector{Complex{Int64}}` instead of `Vector{Any}`).
53+
4454
Point 3) allows something like `rand(1:30, Set, 10)` to produce a `Set` of length `10` with values
4555
from `1:30`. The idea is that `rand([rng], [S], Cont, etc...)` should always be equivalent to
4656
`rand([rng], make(Cont, [S], etc...))`. This design goes somewhat against the trend in `Base` to create
@@ -204,6 +214,12 @@ julia> collect(Iterators.take(Uniform(1:10), 3)) # distributions can be iterated
204214
7
205215
10
206216
5
217+
218+
julia> rand(Complex => Int) # equivalent to rand(make(Complex, Int)) (experimental)
219+
4610038282330316390 + 4899086469899572461im
220+
221+
julia> rand(Pair => (String, Int8)) # equivalent to rand(make(Pair, String, Int8)) (experimental)
222+
"ODNXIePK" => 4
207223
```
208224

209225
In some cases, the `Rand` iterator can provide efficiency gains compared to

src/sampling.jl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,14 @@ Sampler(RNG::Type{<:AbstractRNG}, c::Categorical, n::Repetition) =
154154

155155
## random elements from pairs
156156

157+
#= disabled in favor of a special meaning for pairs
158+
157159
Sampler(RNG::Type{<:AbstractRNG}, t::Pair, n::Repetition) =
158160
SamplerSimple(t, Sampler(RNG, Bool, n))
159161
160162
rand(rng::AbstractRNG, sp::SamplerSimple{<:Pair}) =
161163
@inbounds return sp[][1 + rand(rng, sp.data)]
162-
164+
=#
163165

164166
## composite types
165167

@@ -559,3 +561,22 @@ let b = UInt8['0':'9';'A':'Z';'a':'z'],
559561

560562
rand(rng::AbstractRNG, sp::SamplerTag{Cont{String}}) = String(rand(rng, sp.data.first, sp.data.second))
561563
end
564+
565+
566+
## X => a / X => (a, as...) syntax as an alternative to make(X, a) / make(X, a, as...)
567+
568+
# this is experimental
569+
570+
@inline Sampler(RNG::Type{<:AbstractRNG}, (a, b)::Pair{<:Union{DataType,UnionAll}},
571+
r::Repetition) =
572+
b isa Tuple ?
573+
Sampler(RNG, make(a, b...), r) :
574+
Sampler(RNG, make(a, b), r)
575+
576+
# nothing can be inferred when only the pair type is available
577+
@inline gentype(::Type{<:Pair{<:Union{DataType,UnionAll}}}) = Any
578+
579+
@inline gentype((a, b)::Pair{<:Union{DataType,UnionAll}}) =
580+
b isa Tuple ?
581+
gentype(make(a, b...)) :
582+
gentype(make(a, b))

test/runtests.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,13 @@ end
280280
@test fieldtype(typeof(a), 2) == UInt64
281281
end
282282

283+
#=
283284
@testset "rand(::Pair)" begin
284285
@test rand(1=>3) ∈ (1, 3)
285286
@test rand(1=>2, 3) isa Vector{Int}
286287
@test rand(1=>'2', 3) isa Vector{Union{Char, Int}}
287288
end
289+
=#
288290

289291
@testset "rand(::AbstractFloat)" begin
290292
# check that overridden methods still work
@@ -565,6 +567,16 @@ end
565567
@test rand(make(Float64)) isa Float64
566568
end
567569

570+
@testset "rand(T => x) & rand(T => (x, y, ...))" begin
571+
@test rand(Complex => Int) isa Complex{Int}
572+
@test rand(Pair => (String, Int8)) isa Pair{String,Int8}
573+
@test_throws ArgumentError rand(1=>2) # should not call rand(make(1, 2))
574+
575+
@test rand(Complex => Int, 3) isa Vector{Complex{Int}}
576+
@test rand(Pair => (String, Int8), Set, 3) isa Set{Pair{String,Int8}}
577+
end
578+
579+
568580
## @rand
569581

570582
struct Die

0 commit comments

Comments
 (0)