difference between x = Nullable.init and x.nullify

Stanislav Blinov via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Jun 4 02:29:49 PDT 2017


On Sunday, 4 June 2017 at 09:04:14 UTC, Jonathan M Davis wrote:

>> if throwing in a destructor is considered a runtime error, 
>> perhaps another valid enhancement would be to statically 
>> disallow throwing Exceptions in destructors, i.e. *require* 
>> them be nothrow?..
>
> My initial reaction would be that destructors should always be 
> nothrow, though I vaguely recall there being some reason why it 
> was supposed to be nice that destructors in D could cleanly 
> deal with exceptions. And remember that when we're talking 
> about rt_finalize, we're talking about finalizers, not 
> destructors in general. When a destructor is in a GC 
> heap-allocated object, it's treated as a finalizer and may or 
> may not be run (since the object may or may not be collected),

It doesn't matter. The only thing that matters is that it may be 
run, and therefore rt_finalize has to count on that. And it sort 
of does, at the moment, by assuming the worst possible 
combination of attributes. Problem is, with current language 
rules, it cannot be any other way, as the runtime doesn't carry 
any information about attributes of finalized object, or the 
context in which finalization takes place (i.e. is it within a 
@safe function?), which, sadly, makes unsafe code silently 
executable in a safe context, in direct contradiction to language 
guarantees.

> whereas when a destructor is on an object that's on the stack, 
> it's really a destructor. So, while they use the same syntax,

It's worse than that. There are two "destructors": __xdtor that 
calls destructors of RAII members, and, on classes, __dtor that 
actually calls ~this() for the class. But only that class, not 
it's ancestors or descendants. Such segregation is, as it turns 
out, as useful as it is unwieldy.

> and in the case of a struct, the same function could be either 
> a destructor or a finalizer depending on where the struct is 
> declared, they're not quite the same thing. And destroy muddies 
> the water a bit, because it then explicitly calls the finalizer 
> on a class, whereas it would normally be the GC that does it 
> (and while calling GC-related functions in a finalizer is 
> forbidden when called by the GC, it's fine when called via 
> destroy, since the GC is then not in the middle of a 
> collection).
>
> So, I don't know whether it would be reasonable to require that 
> destructors be nothrow. Certainly, it's _more_ likely for it to 
> be reasonable for destructors on classes to be nothrow, since 
> classes always live on the heap (and are thus finalizers) 
> unless you're playing games with something like 
> std.typecons.scoped, but I'd have to study the matter quite a 
> bit more to give a properly informed answer as to whether it 
> would be reasonable to require that all destructors be nothrow.

Scoped is not necessary. Classes may not necessarily exist in the 
GC heap, thanks to custom allocators and emplace(). But because 
the language does not enforce propagation of destructor 
attributes, destroy() is @system and not nothrow, which spills 
out into user code that would otherwise take advantage of static 
inference. Unfortunately, right now making it any other would 
impose certain restrictions on classes without real language 
support, and that is... scary.


More information about the Digitalmars-d-learn mailing list