Under the hood it’s doing the exact same thing, and then implementing Deref so that it looks like a normal immutable value of type T to consumers.
In addition to being shorter and not requiring application code to use unsafe, please note that in my first example, all of the expensive computation is inside an unsafe block, unless the author takes special care to hoist it. In the second example, that naturally doesn’t happen.
What do people think? This seems simple enough that I may just implement it and send a PR unless everyone hates it.
(Yes, this is essentially what lazy_static does with different syntax. You can’t always use third party crates.)
Frankly I hadn’t thought at all about that possibility. I’m not the author of lazy_static and I have no idea what they think about merging or not merging it into the stdlib. This design doesn’t involve any macros, but it might turn out to be unusably clunky in some respects if it stays that way (for instance it might be necessary to write static expensive_integer: InitOnce<i32> = InitOnce::<i32>::new(...) which is getting awfully repetitive…)
One thing that bothers me though is that ideally we want to parametrize InitOnceover the function as well, so as to avoid any possibility of indirect call But I am 100% sure that this’ll be a premature optimization, and storing, as proposed, fn() -> T function pointer will be good enough, and quite probably LLVM will be able to optimize indirect call away anyway.
But looks like to implement InitOnce we’ll need const fn? But that’s probably OK, because calling const fn on stable should be available soon.
Will it be possible to use InitOnce for non-staic lazy variables? Like in struct S { data: InitOnce<i32> }?
Should we use the name Lazy for this type? Should we provide a lazy convenience function, so that the origical example looks like
I agree this would be great. In fact we already have something like this in libstd, just a bit specialized: io::lazy::Lazy. Would be nice to be able to reuse other code there
EDIT: Actually all that really needs is a reentrant mutex with a const fn initialization function. That’s not easy to do on POSIX though…