How would you do that in Rust (versus Java)

Hi everyone. I think I am too Java-minded....

In Java one would usually create a static instance of an object at class level and use it everywhere needed. So in Java I would do something like (pseudo-code)

if myobj == null {
         myobj = new MyObject(); // create object only once
}
myobj.hello();

So in Rust I have the feeling to do something wrong with this piece of code:

let mut rng = rand::thread_rng(); // should I call this only once and "keep rng somewhere" ??? 
let n1: u8 = rng.gen();

Is that ok to "instantiate" rng each time or is there a way to do something better ?

Thank you!!

The thread_rng function already does this for you.

2 Likes

There is no "null" in Rust. Nullity is a billion+ dollar mistake that was unfortunately introduced into industry.

let my_value: Option<usize> = None;
let my_value2: Option<usize> = Some(10);

assert!(my_value.is_none());
assert!(my_value2.is_some());

let taken = my_value2.take().unwrap(); // This is okay
let panic = my_value2.take().unwrap(); // this will panic!

There is no need to instantiate rng each time. You can continue to use it and pass it from closure to closure.

1 Like

You mention "Nullity is a billion+ dollar mistake" and then followed by the last line of the code sample

let panic = my_value2.take().unwrap(); // this will panic!

Isn't this null wrapped in different clothes? As Rust grows and becomes mainstream, the teams which did not handle NULL cases will also just unwrap() Option<T> and NullPointerException will only be replaced by Option::unwrap() on a None value.

May be the compiler could force handling of None scenario before any unwraps or just remove unwraps in favour of pattern matching etc.

2 Likes

That's indeed not a great way to lazily initialize a value. I'd suggest you use once_cell::Lazy instead.

4 Likes

It is null in different clothes, but the clothes that nulls wear are important. The main thing that Option gives you is that it communicates who is actually responsible for checking if a value is null, and ensuring that it is only checked when null (None) is an intended and possible value.

9 Likes

When I first started learning this language, that's the exact same thought I had. Well, it turns out that presentation of an idea also has a psychological effect on the programmer. Fatal NPEs can be simulated in Rust by panicking if someone unwraps T when T's inner object is_none. But, the idea is that we add another layer of abstraction between true nullity and non-nullity that is more mental than programmatic. Abstraction works on the human mind too, and dare I say that our mind, since birth, has been layers of abstraction built upwards using the universal language?

1 Like

Another difference is that in Java (nearly) everything can be null, in Rust however it is clearly encoded in the typesistem which values can be "null".

1 Like

Thank you all but still don't know what to do.

Alice says function does that automatically. Nologic says there is no reason to instantiate rng each time (how could/should I instantiate it only once then?). And what about H3CO3's answer with onecell::lazy?

If you look at the docs for thread_rng, you can see that it says it already caches the value for you. You don't have to cache the result yourself, you can just call that function every time you want to access it.

1 Like

Well, what about it? Did you try it? Did you read the docs that I linked to?

Generally, the lazy initialization pattern is best left to canonical/"semi-official" crates because doing it correctly is hard, however conceptually simple it might be. There are other options, such as lazy_static, but I prefer once_cell as it doesn't require a macro.

The answer is that you can feel free to call thread_rng whenever you need it. If you view the source, you will find that it uses the thread_local! macro to return the same instance on each use (although each thread has its own version).

The comments about initialization are more relevant if you run into a similar problems with other resources you wish to share — in that case the point is that your Java example of initialization might not create the object only once if called from multiple threads, and some suggestions have been made for how to properly synchronize initialization such that it really happens only once.

4 Likes

Thank you it is crystal clear! One point for you, one for alice :smiley:

Thank you all.

I'm not used to look into the source, and I will try to pay more attention to the documentation indeed.

That being said, I think it is more the programming paradigm (oo versus procedural) that is more of a problem for a old Java developer like me.

I won't give up thanks to your support and your patience (with beginners with stupid questions :slight_smile:)

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.