digitalmars.D.learn - difference between x = Nullable.init and x.nullify
- vit (11/11) Jun 02 2017 Hello,
- Jonathan M Davis via Digitalmars-d-learn (12/23) Jun 02 2017 Assigning Nullable!Test.init is equivalent to setting the internal value...
- Stanislav Blinov (7/11) Jun 02 2017 Presently, rt_finalize cannot be made nothrow, or un-made
- Jonathan M Davis via Digitalmars-d-learn (10/22) Jun 03 2017 Well, as I said, I could be missing something, but all rt_finalize does ...
- Stanislav Blinov (8/34) Jun 03 2017 Whoops, my bad, I forgot it indeed swallows exceptions and does
- Jonathan M Davis via Digitalmars-d-learn (25/63) Jun 04 2017 My initial reaction would be that destructors should always be nothrow,
- Stanislav Blinov (24/55) Jun 04 2017 It doesn't matter. The only thing that matters is that it may be
- vit (2/3) Jun 04 2017 Why Nullable!T call destroy for reference types?
- Jonathan M Davis via Digitalmars-d-learn (10/13) Jun 04 2017 It calls destroy for everything. Why it does that instead of simply
- vit (2/3) Jun 03 2017 thanks
- Kagamin (3/5) Jun 03 2017 Eh? Does it mean Nullable is default initialized to some non-null
- Jonathan M Davis via Digitalmars-d-learn (15/20) Jun 04 2017 Well, that depends on what you mean by null. Nullable!T doesn't use
- Kagamin (2/9) Jun 05 2017 So it was a typo that Nullable.init sets _isNull to false?
- Jonathan M Davis via Digitalmars-d-learn (3/13) Jun 05 2017 Yes.
Hello, What's the difference between x = Nullable!Test.init and x.nullify? class Test{} void test()pure nothrow{ Nullable!Test x; x = Nullable!Test.init; //OK x.nullify; //Error: function 'std.typecons.Nullable!(Test).Nullable.nullify!().nullify' is not nothrow }
Jun 02 2017
On Saturday, June 03, 2017 05:52:55 vit via Digitalmars-d-learn wrote:Hello, What's the difference between x = Nullable!Test.init and x.nullify? class Test{} void test()pure nothrow{ Nullable!Test x; x = Nullable!Test.init; //OK x.nullify; //Error: function 'std.typecons.Nullable!(Test).Nullable.nullify!().nullify' is not nothrow }Assigning Nullable!Test.init is equivalent to setting the internal value to Test.init and setting _isNull to false. nullify doesn't assign Nullable!Test.init to the Nullable!Test, and it doesn't assign Test.init to _value. Rather, it calls destroy on _value and sets _isNull to true. Exactly what destroy does depends on the type. In the case of a class, it calls rt_finalize on it, which basically calls the class' finalizer (if it has one). But rt_finalize is not nothrow, so destroy isn't nothrow, so nullify isn't nothrow. However, looking at what rt_finalize does, I don't see why it couldn't be nothrow. So, unless I'm missing something, it seems like that would be a good enhancement. - Jonathan M Davis
Jun 02 2017
On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:looking at what rt_finalize does, I don't see why it couldn't be nothrow. So, unless I'm missing something, it seems like that would be a good enhancement. - Jonathan M DavisPresently, rt_finalize cannot be made nothrow, or un-made system, because "reasons": http://forum.dlang.org/thread/aalafajtuhlvfirwfvea forum.dlang.org Fixing that would require significant changes to the runtime, and probably the compiler. I don't think it qualifies as a simple "enhancement" :)
Jun 02 2017
On Saturday, June 03, 2017 06:41:44 Stanislav Blinov via Digitalmars-d-learn wrote:On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:Well, as I said, I could be missing something, but all rt_finalize does is call rt_finalize2, and rt_finalize2 _is_ nothrow (it catches any Exceptions that are thrown by the destructor/finalizer). So, I have no idea why it would be the case that rt_finalize couldn't be nothrow, and I saw nothing in that thread which contradicts that, but I could have read it too quickly. Regardless, it's a perfectly valid enhancement request whether it's easy to implement or not. - Jonathan M Davislooking at what rt_finalize does, I don't see why it couldn't be nothrow. So, unless I'm missing something, it seems like that would be a good enhancement. - Jonathan M DavisPresently, rt_finalize cannot be made nothrow, or un-made system, because "reasons": http://forum.dlang.org/thread/aalafajtuhlvfirwfvea forum.dlang.org Fixing that would require significant changes to the runtime, and probably the compiler. I don't think it qualifies as a simple "enhancement" :)
Jun 03 2017
On Saturday, 3 June 2017 at 08:01:14 UTC, Jonathan M Davis wrote:On Saturday, June 03, 2017 06:41:44 Stanislav Blinov via Digitalmars-d-learn wrote:Whoops, my bad, I forgot it indeed swallows exceptions and does the onFinalizeError instead. So... yep, then it seems that rt_finalize probably should be marked nothrow too. Hmm... 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?..On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:Well, as I said, I could be missing something, but all rt_finalize does is call rt_finalize2, and rt_finalize2 _is_ nothrow (it catches any Exceptions that are thrown by the destructor/finalizer). So, I have no idea why it would be the case that rt_finalize couldn't be nothrow, and I saw nothing in that thread which contradicts that, but I could have read it too quickly. Regardless, it's a perfectly valid enhancement request whether it's easy to implement or not. - Jonathan M Davislooking at what rt_finalize does, I don't see why it couldn't be nothrow. So, unless I'm missing something, it seems like that would be a good enhancement. - Jonathan M DavisPresently, rt_finalize cannot be made nothrow, or un-made system, because "reasons": http://forum.dlang.org/thread/aalafajtuhlvfirwfvea forum.dlang.org Fixing that would require significant changes to the runtime, and probably the compiler. I don't think it qualifies as a simple "enhancement" :)
Jun 03 2017
On Saturday, June 03, 2017 08:17:18 Stanislav Blinov via Digitalmars-d-learn wrote:On Saturday, 3 June 2017 at 08:01:14 UTC, Jonathan M Davis wrote: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), 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, 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. - Jonathan M DavisOn Saturday, June 03, 2017 06:41:44 Stanislav Blinov via Digitalmars-d-learn wrote:Whoops, my bad, I forgot it indeed swallows exceptions and does the onFinalizeError instead. So... yep, then it seems that rt_finalize probably should be marked nothrow too. Hmm... 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?..On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:Well, as I said, I could be missing something, but all rt_finalize does is call rt_finalize2, and rt_finalize2 _is_ nothrow (it catches any Exceptions that are thrown by the destructor/finalizer). So, I have no idea why it would be the case that rt_finalize couldn't be nothrow, and I saw nothing in that thread which contradicts that, but I could have read it too quickly. Regardless, it's a perfectly valid enhancement request whether it's easy to implement or not. - Jonathan M Davislooking at what rt_finalize does, I don't see why it couldn't be nothrow. So, unless I'm missing something, it seems like that would be a good enhancement. - Jonathan M DavisPresently, rt_finalize cannot be made nothrow, or un-made system, because "reasons": http://forum.dlang.org/thread/aalafajtuhlvfirwfvea forum.dlang.org Fixing that would require significant changes to the runtime, and probably the compiler. I don't think it qualifies as a simple "enhancement" :)
Jun 04 2017
On Sunday, 4 June 2017 at 09:04:14 UTC, Jonathan M Davis wrote: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.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),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.
Jun 04 2017
On Sunday, 4 June 2017 at 09:04:14 UTC, Jonathan M Davis wrote:[...]Why Nullable!T call destroy for reference types?
Jun 04 2017
On Sunday, June 04, 2017 09:31:24 vit via Digitalmars-d-learn wrote:On Sunday, 4 June 2017 at 09:04:14 UTC, Jonathan M Davis wrote:It calls destroy for everything. Why it does that instead of simply assigning T.init and setting _isNull to true, I don't know. Maybe the commit history would say, but unless it was done as part of a bugfix, it's more likely that you'd have to use the commit history to figure out who made it do that and ask them. Thinking about it though, it does seem like it's probably the wrong behavior. I'd guess that it was done with structs in mind, and it doesn't usually make sense to put a class reference in Nullable outside of generic code, since they can be null on their own. - Jonathan M Davis[...]Why Nullable!T call destroy for reference types?
Jun 04 2017
On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:[...]thanks
Jun 03 2017
On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:Assigning Nullable!Test.init is equivalent to setting the internal value to Test.init and setting _isNull to false.Eh? Does it mean Nullable is default initialized to some non-null default value?
Jun 03 2017
On Saturday, June 03, 2017 14:30:05 Kagamin via Digitalmars-d-learn wrote:On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:Well, that depends on what you mean by null. Nullable!T doesn't use pointers, so it can't be null like a pointer is null. The whole point of Nullable!T is to emulate the null behavior of pointers while keeping everything on the stack. It's a struct that contains two members: T _value; bool _isNull = true; So, _value is default-initialized to T.init, and _isNull defaults to true. Whether Nullable!T is "null" or not depends on the value of _isNull. So, Nullable!T is default-initialized to null in the sense that _isNull is true, and all of its member functions that check for "null" check whether _isNull is true, so it's treated as "null" when it's default-initialized, but it's not truly null in the sense that a pointer or class reference can be null. If that's what you want, just create a T* rather than a Nullable!T. - Jonathan M DavisAssigning Nullable!Test.init is equivalent to setting the internal value to Test.init and setting _isNull to false.Eh? Does it mean Nullable is default initialized to some non-null default value?
Jun 04 2017
On Sunday, 4 June 2017 at 08:51:44 UTC, Jonathan M Davis wrote:So it was a typo that Nullable.init sets _isNull to false?On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:T _value; bool _isNull = true;Assigning Nullable!Test.init is equivalent to setting the internal value to Test.init and setting _isNull to false.
Jun 05 2017
On Monday, June 05, 2017 10:46:39 Kagamin via Digitalmars-d-learn wrote:On Sunday, 4 June 2017 at 08:51:44 UTC, Jonathan M Davis wrote:Yes. - Jonathan M DavisSo it was a typo that Nullable.init sets _isNull to false?On Saturday, 3 June 2017 at 06:19:29 UTC, Jonathan M Davis wrote:T _value; bool _isNull = true;Assigning Nullable!Test.init is equivalent to setting the internal value to Test.init and setting _isNull to false.
Jun 05 2017