www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - possible improvement to if statements?

reply Steven Schveighoffer <schveiguy gmail.com> writes:
We have this pattern in D, which is pretty nice:

if(auto p = x in y)
{
    // use p which is a pointer
}

But pointers can be difficult to use -- you sometimes have to 
dereference them to use them, and you can't create a reference variable 
in-line.

What about something like:

if(ref p = ptrExpression)
{
}

The expression would be a pointer expression. p would be bound to the 
pointer target, but the if statement is on the pointer itself. That is, 
you get inside only if p is referring to something not null.

I realize this is not going to fly, because there are too many holes. 
But I've wished for something like this a few times.

You can ALMOST get there with a kooky foreach helper (foreach is one of 
the few places where a ref local can be added into a function scope):

struct RefOf(T)
{
     T* ptr;
     ref T front() { return *ptr; }
     bool empty() { return ptr is null; }
     void popFront() { ptr = null; }
}

RefOf!T refof(T)(T * ptr) { return RefOf!T(ptr); }

foreach(ref r; (x in y).refof)
{
}

but you can't do `else` with it. You can wrap it in an if like this:

if(auto p = x in y) foreach(ref r; p.refof) {
    // ugh...
}
else
{
}

Does anyone have a workable way this kind of thing could be added to D?

-Steve
Apr 26
next sibling parent reply Sebastiaan Koppe <mail skoppe.eu> writes:
On Sunday, 26 April 2020 at 20:41:47 UTC, Steven Schveighoffer 
wrote:
 Does anyone have a workable way this kind of thing could be 
 added to D?

 -Steve
Did you consider this? ``` import std.stdio; struct Wrap(P) { P* p; this(P* p) { this.p = p; } bool opCast(T)() if (is(T == bool)) { return p !is null; } ref P get() { return *p; } alias get this; } auto wrap(P)(P* p) { return Wrap!P(p); } void main() { struct Foo { int bar; } Foo[string] x = ["a": Foo(5)]; if (auto r = wrap("a" in x)) { r.bar = 7; } writeln(x); // prints ["a":Foo(7)] } ```
Apr 26
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 4/26/20 5:06 PM, Sebastiaan Koppe wrote:
 On Sunday, 26 April 2020 at 20:41:47 UTC, Steven Schveighoffer wrote:
 Does anyone have a workable way this kind of thing could be added to D?
Did you consider this?
No I haven't, that's at least as good as the foreach version (though having a simple ref is nicer than having a wrapper type). Is this located anywhere on code.dlang.org or in phobos? But there is one issue -- what if P defines opCast(bool)? Still it's almost good enough, and probably better than what I wrote. I would still like an improvement to this pattern that fits what I want to do -- essentially, if this exists, give me a reference to it, and let me use it. -Steve
Apr 26
next sibling parent Sebastiaan Koppe <mail skoppe.eu> writes:
On Sunday, 26 April 2020 at 21:26:31 UTC, Steven Schveighoffer 
wrote:
 Is this located anywhere on code.dlang.org or in phobos?
No, hence the awful name.
 But there is one issue -- what if P defines opCast(bool)?
I think you can introspect that in the opCast function, and if so, forward the call if p !is null. That still leaves you with the downside of wrapping the (x in y) expression. You could also argue that the (x in y) expression needs to return an optional. If ever there was a need for optional this would be it. If fact the Wrap thing I wrote is dangerously close to the nullable, including it's flaws, namely that it automatically dereferences p. A more function approach might be better. Gets rid of the control flow as well. y.get(x) .then(x => writeln(x)); // prints only when x is in y y.get(x) .withDefault(55) .then(x => writeln(x)); // prints x or 55 y.get(x) .then(x => writeln(x)) .orElse({ throw new Exception("not found")}); // prints x or throws
Apr 27
prev sibling parent Sebastiaan Koppe <mail skoppe.eu> writes:
On Sunday, 26 April 2020 at 21:26:31 UTC, Steven Schveighoffer 
wrote:
 Is this located anywhere on code.dlang.org or in phobos?
No, hence the awful name.
 But there is one issue -- what if P defines opCast(bool)?
I think you can introspect that in the opCast function, and if so, forward the call if p !is null. That still leaves you with the downside of wrapping the (x in y) expression. You could also argue that the (x in y) expression needs to return an optional. If ever there was a need for optional this would be it. If fact the Wrap thing I wrote is dangerously close to the nullable, including it's flaws, namely that it automatically dereferences p. A more function approach might be better. Gets rid of the control flow as well. y.get(x) .then(x => writeln(x)); // prints only when x is in y y.get(x) .withDefault(55) .then(x => writeln(x)); // prints x or 55 y.get(x) .then(x => writeln(x)) .orElse({ throw new Exception("not found")}); // prints x or throws
Apr 27
prev sibling parent Meta <jared771 gmail.com> writes:
On Sunday, 26 April 2020 at 20:41:47 UTC, Steven Schveighoffer 
wrote:
 We have this pattern in D, which is pretty nice:

 if(auto p = x in y)
 {
    // use p which is a pointer
 }

 But pointers can be difficult to use -- you sometimes have to 
 dereference them to use them, and you can't create a reference 
 variable in-line.

 What about something like:

 if(ref p = ptrExpression)
 {
 }

 The expression would be a pointer expression. p would be bound 
 to the pointer target, but the if statement is on the pointer 
 itself. That is, you get inside only if p is referring to 
 something not null.

 I realize this is not going to fly, because there are too many 
 holes. But I've wished for something like this a few times.

 You can ALMOST get there with a kooky foreach helper (foreach 
 is one of the few places where a ref local can be added into a 
 function scope):

 struct RefOf(T)
 {
     T* ptr;
     ref T front() { return *ptr; }
     bool empty() { return ptr is null; }
     void popFront() { ptr = null; }
 }

 RefOf!T refof(T)(T * ptr) { return RefOf!T(ptr); }

 foreach(ref r; (x in y).refof)
 {
 }

 but you can't do `else` with it. You can wrap it in an if like 
 this:

 if(auto p = x in y) foreach(ref r; p.refof) {
    // ugh...
 }
 else
 {
 }

 Does anyone have a workable way this kind of thing could be 
 added to D?

 -Steve
The real answer is flow-based typing (which is a nuke for this particular cockroach of a problem, but has many more benefits besides).
Apr 26