www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Is Nullable supposed to provide Optional semantics?

reply Chris Paulson-Ellis <chris edesix.com> writes:
I've been bitten by trying to use Nullable(T) on class types. 
Minimal example...

import std.typecons : Nullable;

void main()
{
     auto o = new Object();
     o.toString();

     Nullable!Object n = o;
     o.toString();

     n.nullify();
     o.toString(); // SegV!
}

The SEGV is caused by nullify calling object.destroy() on o, 
invalidating it. This makes Nullable unsafe to use with class 
types when there may be other references to the optional values 
in the program.

Perhaps I'm not using the correct abstraction. I'm looking for 
something equivalent to java.util.Optional, or Haskell's Maybe.

If Nullable(T) *is* intended to be used like Java Optional, then 
calling .destroy when clearing the value seems to be going beyond 
its remit for class types.

For those confused as to why you'd want to wrap a Nullable around 
something that already has nullable semantics, it's mostly about 
making APIs that explicitly declare their optional return values. 
See: 
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

I also want to use it in template code that works with both value 
& reference types.

Chris.
Dec 29 2017
parent reply vit <vit vit.vit> writes:
On Friday, 29 December 2017 at 20:52:51 UTC, Chris Paulson-Ellis 
wrote:
 I've been bitten by trying to use Nullable(T) on class types. 
 Minimal example...

 [...]
use: n = Nullable!Object.init; //doesn't call destroy instead of: n.nullify();
Dec 29 2017
parent reply Chris Paulson-Ellis <chris edesix.com> writes:
On Friday, 29 December 2017 at 21:34:27 UTC, vit wrote:
 use:
    n = Nullable!Object.init;   //doesn't call destroy

 instead of:
    n.nullify();
Only nullify() can make isNull return true again. I need that semantic.
Dec 29 2017
next sibling parent Dukc <ajieskola gmail.com> writes:
On Friday, 29 December 2017 at 21:43:25 UTC, Chris Paulson-Ellis 
wrote:
 Only nullify() can make isNull return true again. I need that 
 semantic.
Quick idea without much afterthought: instead of Nullable, use pointer to o?
Dec 29 2017
prev sibling parent reply vit <vit vit.vit> writes:
On Friday, 29 December 2017 at 21:43:25 UTC, Chris Paulson-Ellis 
wrote:
 On Friday, 29 December 2017 at 21:34:27 UTC, vit wrote:
 use:
    n = Nullable!Object.init;   //doesn't call destroy

 instead of:
    n.nullify();
Only nullify() can make isNull return true again. I need that semantic.
import std.typecons : Nullable; auto o = new Object(); Nullable!Object n; assert(n.isNull == true); n = o; assert(n.isNull == false); n = Nullable!Object.init; assert(n.isNull == true); o.toString(); //OK assert(Nullable!Object.init.isNull == true); more: https://forum.dlang.org/thread/jrdedmxnycbqzcprebjl forum.dlang.org?page=1
Dec 29 2017
parent reply Chris Paulson-Ellis <chris edesix.com> writes:
On Friday, 29 December 2017 at 22:08:59 UTC, vit wrote:
     n = Nullable!Object.init;
     assert(n.isNull == true);
 [...]
 more: 
 https://forum.dlang.org/thread/jrdedmxnycbqzcprebjl forum.dlang.org?page=1
Thanks. No-one in the linked thread seemed to know why .destroy is used in nullify. Looking at the commit history it used to be .clear, but maybe that did the same thing, I don't know. I still think nullify is going beyond the Nullable remit for reference types. Unless anyone disagrees, I'll submit a bug report. C.
Dec 30 2017
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, December 30, 2017 08:59:40 Chris Paulson-Ellis via Digitalmars-
d-learn wrote:
 On Friday, 29 December 2017 at 22:08:59 UTC, vit wrote:
     n = Nullable!Object.init;
     assert(n.isNull == true);

 [...]
 more:
 https://forum.dlang.org/thread/jrdedmxnycbqzcprebjl forum.dlang.org?page
 =1
Thanks. No-one in the linked thread seemed to know why .destroy is used in nullify. Looking at the commit history it used to be .clear, but maybe that did the same thing, I don't know.
destroy used to be called clear (e.g. that's what TDPL calls it), but it was renamed, because it was too easily confused with clearing a container and tended to be misused. - Jonathan M Davis
Dec 30 2017
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/30/17 3:59 AM, Chris Paulson-Ellis wrote:
 On Friday, 29 December 2017 at 22:08:59 UTC, vit wrote:
     n = Nullable!Object.init;
     assert(n.isNull == true);
 [...]
 more: 
 https://forum.dlang.org/thread/jrdedmxnycbqzcprebjl forum.dlang.org?page=1 
Thanks. No-one in the linked thread seemed to know why .destroy is used in nullify. Looking at the commit history it used to be .clear, but maybe that did the same thing, I don't know.
clear was renamed to destroy because clear typically is used in containers to remove all elements (but not destroy the container itself). Since clear was a UFCS function, it led to confusion: somestruct.clear; // equivalent to clear(somestruct), destroys it. container.clear; // remove all elements clear(container); // destroy the container So destroy was used instead, and it's a much better name.
 I still think nullify is going beyond the Nullable remit for reference 
 types. Unless anyone disagrees, I'll submit a bug report.
I think you are correct. I believe it is calling destroy expecting it to work like calling destroy on a pointer (which does nothing I think, or just sets it to null). But it doesn't work that way. What may have been missed by the others is that the call to toString that caused the segfault was NOT on the nullable `n`, but on the original object `o`. So nullifying the nullable kills any other references to the same object. Please file a bug report. -Steve
Dec 30 2017
parent Chris Paulson-Ellis <chris edesix.com> writes:
On Saturday, 30 December 2017 at 19:11:05 UTC, Steven 
Schveighoffer wrote:
 Please file a bug report.
Sorry for the delay - stuff happened. I reopened an existing bug that I found: https://issues.dlang.org/show_bug.cgi?id=17440
Jan 13 2018