Hi,
I’ve just been fiddling with some bits of code and am still a bit blown away by some julian’ language-constructs. I’ve been doing oo-programming, mainly, for a considerable timespan & my (purely ever academic) exposure to Lisp + Haskell dates a few decades back. When I look at my own code, I’m not entirely sure, whether it is just super-simple or encredibly deep, so I need to stick to these pieces of code, to fix some thoughts in my brain, which are too fluid, atm…
This was my first go, at migrating a rng, from some java-code of mine…
# random-number-generator 1
Base.@kwdef mutable struct RNG
nextseed::UInt64
end
function (o::RNG)()
o.nextseed = rng(o.nextseed)
end
function rng(x::UInt64)
x ⊻= (x << 21)
x ⊻= (x >>> 35)
x ⊻= (x << 4)
return x % UInt64
end
…it allows me, to instantiate more than one rng, not sharing a common seed / state, and works like a charm (for generating UInt-random-numbers. So next thing I did, was porting some more related code, for an extension of the previous concept, reusing the core-rng-function, but extending the RNG to return numbers in a limited domain (not the full UInt64-domain)…
# random-number-generator 2
Base.@kwdef mutable struct RNGMasked
nextseed::UInt64
mask::UInt64
end
function (o::RNGMasked)()
o.nextseed = rng(o.nextseed)
return o.nextseed & o.mask
end
julia> r = RNGMasked( 0x1234567890abcdef, (1<<8)-1 ) # init with mask=0b11111111 (only produce rn with last 8 bits set)
RNGMasked(0x1234567890abcdef, 0x00000000000000ff)
julia> map( _ -> Int(r()), 1:6 )
6-element Vector{Int64}:
127
96
249
47
113
213
So far so good - this also works great, I’m very pleased, with how the function can have a private state and I can instantiate independent rngs, etc.
But now, I have 2 practical questions, how to go ahead, further:
-
I’ve defined r (an instance of the RNGMasked) by precomputing the mask, before passing the actual value to be stored in
o.mask
. Is there a way, that I can pass just the number of bits (nbits=8
, in the example) and have the rng do the computation (1<<nbits)-1
) for the actual mask-value?
I mean, without (!) the need, to pass a mask with every call for the next rn? -
(Possibly just a generalization of Q #1.: ) Is it somehow possible to have two different functions operate on the same state of a struct, in this context? For example, what if the instance of RNG-Masked should really be a
RNGWithOptionMasked
, could there be 2 different functions, saynext()
andnext_masked()
, accessing the same o.seed (I mean without sacrificing the elegancy of the current constructs - obviously, I could just have an “outside” reference of a state and pass it to any number of functions, to do something with it, but that would break this pattern)?
Apologies, for possibly using too much oo-vocabulary, naming things, that aren’t oo, at all, but as of now, I don’t even know, how exactly to call things, without using oo-words, for them, or becoming super-vague (I tried hard, not using “overloading”, “constructors” and “inheritance” in my questions, but I really can’t help having those words bump my brains, constantly).
And finally, just as a very general question: How are the things, I’ve been doing, accurately called? My vague understanding is, that the anonymous functions, mutating instances of the RNG-structs are either closures or functors or both. Is one of those correct? And if yes, why not the other?
(I’ve read numerous threads and guides, by now, but as soon as I think, that it’s the one, I get the idea, it could be the other, when I read the next thread).
PS: I know, there are likely great rngs, in julia, I just need these rngs, to be able to compare the julia-port (of my chess-engine) to the java pendant and quality of rngs really doesn’t matter, here - there is no statistical testing, etc., based on rngs, in this case.
PS #2: The details of my questions might seem overblown, for the simplistic purpose of those 2 rng-implementations, but this, for me, is something like a min.-example, of things I’ll be doing on a much larger scale (with more code, variables and state involved) and I need to get these basics straight, before I can even start thinking about porting more complicated stuff…