I enjoyed this talk. Thanks @gregvaughn.
I did want to add two small clarifications.
First, Greg mentions that the :rand
“could” allow you to manage passing the seeds around yourself, instead of using the process dictionary. In fact, it does that too! You can choose your API with :rand
. Here’s some usage without touching the process dictionary:
iex(1)> seed = :rand.seed_s(:exrop)
{%{
bits: 58,
jump: #Function<8.15449617/1 in :rand.mk_alg/1>,
next: #Function<5.15449617/1 in :rand.mk_alg/1>,
type: :exrop,
uniform: #Function<6.15449617/1 in :rand.mk_alg/1>,
uniform_n: #Function<7.15449617/2 in :rand.mk_alg/1>,
weak_low_bits: 1
}, [19318074725392827 | 240284246166041928]}
iex(2)> {num, new_seed} = :rand.uniform_s(seed)
{0.9006764809368724,
{%{
bits: 58,
jump: #Function<8.15449617/1 in :rand.mk_alg/1>,
next: #Function<5.15449617/1 in :rand.mk_alg/1>,
type: :exrop,
uniform: #Function<6.15449617/1 in :rand.mk_alg/1>,
uniform_n: #Function<7.15449617/2 in :rand.mk_alg/1>,
weak_low_bits: 1
}, [40790438808678228 | 56479292960350440]}}
iex(3)> Process.get_keys
[:iex_evaluator, :elixir_parser_columns, :iex_history, :"$initial_call",
:"$ancestors"]
The other thing I wanted to mention is that the existence of side-effect requiring concerns, like I/O (which Greg mentions), doesn’t prevent runtimes from keeping your code pure. If you want to perform I/O, you would instead ask the runtime to do it for you. The runtime would then call into your code with details about the success or failure of the operation. Languages like Elm work this way.
Shameless self-promotion: It just so happens that I wrote a blog post about both of these subjects a while back.
I’m being extremely nit picky in all of this though. I really did love Greg’s talk!