My two cents

Meta jared771 at gmail.com
Fri Oct 20 14:34:08 UTC 2017


On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
> On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
>> conditional dereferencing and stuff about that (same as in C#)
>> foo?.bar;
>> foo?[bar];
>> return foo ?? null;
>
> Tbh. these are some I really wish were in D, because it becomes 
> tedious having to write something like this all the time:
>
> return foo ? foo : null;
>
> where
>
> return foo ?? null; would be so much easier.
>
> It especially becomes painful when you have something with 
> multiple member accesses.
>
> Like:
>
> return foo ? foo.bar ? foo.bar.baz ? foo.bar.baz.something : 
> null;
>
> Which could just be:
>
> return foo?.bar?.baz?.something;
>
>>
>> async/await (vibe.d is nice but useless in comparison to C# or 
>> js async/await idiom)
>> I want to create function returning Promise/Task and await 
>> where I want to.
>> e.g.
>> auto result = device.start(foo, bar); // This is RPC to remote 
>> server returning Task!Bar
>> // do some important stuff
>> return await result; // wait for RPC finish, then return it's 
>> result
>
> I don't think this is much necessary, because the fiber 
> implementations already are able to let you write code close to 
> this.
>
> The only difference is you have to import the modules, but it's 
> such a small thing I don't think you really need this.
>
>>
>> implement this thing from C# (just because it's cool)
>> new Foo() {
>>   property1 = 42,
>>   property2 = "bar"
>> };
>>
>>
>>
>> Thanks for your time.
>> - Satoshi
>
> I really wish this was implemented for classes too! Currently 
> it exist for structs and it completely baffles me why it has 
> never been implemented for structs.

http://forum.dlang.org/post/mailman.2562.1403196857.2907.digitalmars-d@puremagic.com

 From that thread:

Here's a slightly improved version that collapses nested wrappers 
into a
single wrapper, so that Maybe!(Maybe!(Maybe!...Maybe!T)...) == 
Maybe!T:

	/**
	 * A safe-dereferencing wrapper resembling a Maybe monad.
	 *
	 * If the wrapped object is null, any further member 
dereferences will simply
	 * return a wrapper around the .init value of the member's type. 
Since non-null
	 * member dereferences will also return a wrapped value, any 
null value in the
	 * middle of a chain of nested dereferences will simply cause 
the final result
	 * to default to the .init value of the final member's type.
	 */
	template SafeDeref(T)
	{
	    static if (is(T U == SafeDeref!V, V))
	    {
	        // Merge SafeDeref!(SafeDeref!X) into just SafeDeref!X.
	        alias SafeDeref = U;
	    }
	    else
	    {
	        struct SafeDeref
	        {
	            T t;

	            // Make the wrapper as transparent as possible.
	            alias t this;

	            // This is the magic that makes it all work.
	            auto opDispatch(string field)()
	                if (is(typeof(__traits(getMember, t, field))))
	            {
	                alias Memb = typeof(__traits(getMember, t, 
field));

	                // If T is comparable with null, then we do a 
null check.
	                // Otherwise, we just dereference the member 
since it's
	                // guaranteed to be safe of null dereferences.
	                //
	                // N.B.: we always return a wrapped type in case 
the return
	                // type contains further nullable fields.
	                static if (is(typeof(t is null)))
	                {
	                    return safeDeref((t is null) ? Memb.init
	                                                 : 
__traits(getMember, t,
	                                                            
field));
	                } else {
	                    return safeDeref(__traits(getMember, t, 
field));
	                }
	            }
	        }
	    }
	}

	/**
	 * Wraps an object in a safe dereferencing wrapper resembling a 
Maybe monad.
	 *
	 * If the object is null, then any further member dereferences 
will just return
	 * a wrapper around the .init value of the wrapped type, instead 
of
	 * dereferencing null. This applies recursively to any element 
in a chain of
	 * dereferences.
	 *
	 * Params: t = data to wrap.
	 * Returns: A wrapper around the given type, with "safe" member 
dereference
	 * semantics.
	 */
	auto safeDeref(T)(T t)
	{
	    return SafeDeref!T(t);
	}

	unittest
	{
	    class Node
	    {
	        int val;
	        Node left, right;

	        this(int _val, Node _left=null, Node _right=null)
	        {
	            val = _val;
	            left = _left;
	            right = _right;
	        }
	    }

	    auto tree = new Node(1,
	        new Node(2),
	        new Node(3,
	            null,
	            new Node(4)
	        )
	    );

	    import std.stdio;
	    writeln(safeDeref(tree).right.right.val);
	    writeln(safeDeref(tree).left.right.left.right);
	    writeln(safeDeref(tree).left.right.left.right.val);
	}

	// Static test of monadic composition of SafeDeref.
	unittest
	{
	    {
	        struct Test {}
	        alias A = SafeDeref!Test;
	        alias B = SafeDeref!A;

	        static assert(is(B == SafeDeref!Test));
	        static assert(is(SafeDeref!B == SafeDeref!Test));
	    }

	    // Timon Gehr's original test case
	    {
	        class C
	        {
	            auto foo = safeDeref(C.init);
	        }

	        C c = new C;

	        //import std.stdio;
	        //writeln(safeDeref(c).foo); // 
SafeDeref(SafeDeref(null))

	        import std.string;
	        auto type = "%s".format(safeDeref(c).foo);
	        assert(type == "SafeDeref!(C)(null)");
	    }
	}


More information about the Digitalmars-d mailing list