Thread overview
How to simplify nested ifs
Mar 13, 2018
Ozan Süel
Mar 13, 2018
rikki cattermole
Mar 13, 2018
rumbu
Mar 14, 2018
aliak
Mar 16, 2018
Satoshi
Mar 16, 2018
drug
Mar 16, 2018
drug
Mar 16, 2018
bauss
Mar 16, 2018
bauss
Mar 16, 2018
Tony
March 13, 2018
Hi

I have a construction like the following

if (source) {
  if (source.pool) {
    if (source.pool.repository) {
      if (source.pool.repository.directory) {
	if (source.pool.repository.directory.users) {
	  // do something

Any chance to simplify this nested ifs?
I know some languages has a way like.

if (source?pool?repository?directory?users) // do something


Similar ways in D?

Thanks and Regards, Ozan
March 14, 2018
On 14/03/2018 1:23 AM, Ozan Süel wrote:
> Hi
> 
> I have a construction like the following
> 
> if (source) {
>    if (source.pool) {
>      if (source.pool.repository) {
>        if (source.pool.repository.directory) {
>      if (source.pool.repository.directory.users) {
>        // do something
> 
> Any chance to simplify this nested ifs?
> I know some languages has a way like.
> 
> if (source?pool?repository?directory?users) // do something
> 
> 
> Similar ways in D?
> 
> Thanks and Regards, Ozan

if (source !is null &&
	source.pool !is null &&
	source.pool.repository !is null &&
	source.pool.repository.directory !is null &&
	source.pool.repository.directory.users !is null) {
	//...
}

That is what I'd do.
March 13, 2018
On Tuesday, 13 March 2018 at 12:23:06 UTC, Ozan Süel wrote:
> Hi
>
> I have a construction like the following
>
> if (source) {
>   if (source.pool) {
>     if (source.pool.repository) {
>       if (source.pool.repository.directory) {
> 	if (source.pool.repository.directory.users) {
> 	  // do something
>
> Any chance to simplify this nested ifs?
> I know some languages has a way like.
>
> if (source?pool?repository?directory?users) // do something
>
>
> Similar ways in D?
>
> Thanks and Regards, Ozan

You need the null conditional operator which is not available in D.

A library solution can be found there: https://forum.dlang.org/post/mailman.2562.1403196857.2907.digitalmars-d@puremagic.com

SafeDeref(source).pool.repository.directory.users
March 14, 2018
On Tuesday, 13 March 2018 at 13:13:07 UTC, rumbu wrote:
> On Tuesday, 13 March 2018 at 12:23:06 UTC, Ozan Süel wrote:
>> Hi
>>
>> I have a construction like the following
>>
>> if (source) {
>>   if (source.pool) {
>>     if (source.pool.repository) {
>>       if (source.pool.repository.directory) {
>> 	if (source.pool.repository.directory.users) {
>> 	  // do something
>>
>> Any chance to simplify this nested ifs?
>> I know some languages has a way like.
>>
>> if (source?pool?repository?directory?users) // do something
>>
>>
>> Similar ways in D?
>>
>> Thanks and Regards, Ozan
>
> You need the null conditional operator which is not available in D.
>
> A library solution can be found there: https://forum.dlang.org/post/mailman.2562.1403196857.2907.digitalmars-d@puremagic.com
>
> SafeDeref(source).pool.repository.directory.users

This library may help as well: https://code.dlang.org/packages/optional

It will handle safe dispatching of reference types and pointer types and give you back the actual return result as well wrapped up in an optional value.

class C0 {
    C1 f() { return new C1(); }
    class C1 {
        C2 f() { return new C2(); }
        class C2 {
            int f() { return 0; }
        }
    }
}

auto res1 = some!C0(null).dispatch.f.f.f; // all no ops
auto res2 = some!C0(new C0()).dispatch.f.f.f // calls all fs

assert(res1 == none);
assert(res2 == some(0));
March 16, 2018
On Tuesday, 13 March 2018 at 12:23:06 UTC, Ozan Süel wrote:
> Hi
>
> I have a construction like the following
>
> if (source) {
>   if (source.pool) {
>     if (source.pool.repository) {
>       if (source.pool.repository.directory) {
> 	if (source.pool.repository.directory.users) {
> 	  // do something
>
> Any chance to simplify this nested ifs?
> I know some languages has a way like.
>
> if (source?pool?repository?directory?users) // do something
>
>
> Similar ways in D?
>
> Thanks and Regards, Ozan

null conditional operators are not implemented in D because, as a (I think Walter) said, D is not language designed to work with classes or advanced OOP stuff. Nobody uses it, so please, if you are using it, stop and use structs and meta programming instead.
March 16, 2018
On 16.03.2018 09:34, Satoshi wrote:
> On Tuesday, 13 March 2018 at 12:23:06 UTC, Ozan Süel wrote:
>> Hi
>>
>> I have a construction like the following
>>
>> if (source) {
>>   if (source.pool) {
>>     if (source.pool.repository) {
>>       if (source.pool.repository.directory) {
>>     if (source.pool.repository.directory.users) {
>>       // do something
>>
>> Any chance to simplify this nested ifs?
>> I know some languages has a way like.
>>
>> if (source?pool?repository?directory?users) // do something
>>
>>
>> Similar ways in D?
>>
>> Thanks and Regards, Ozan
>
> null conditional operators are not implemented in D because, as a (I
> think Walter) said, D is not language designed to work with classes or
> advanced OOP stuff. Nobody uses it, so please, if you are using it, stop
> and use structs and meta programming instead.

I think that null conditional operator is intended for OOP only. It's really useful if your data field may be nullable. May be start review about this?
March 16, 2018
On 16.03.2018 09:51, drug wrote:
>
> I think that null conditional operator is intended for OOP only. It's
> really useful if your data field may be nullable. May be start review
> about this?
Oops. I mean *isn't intended for OOP only*
March 16, 2018
On Friday, 16 March 2018 at 09:34:38 UTC, Satoshi wrote:
> null conditional operators are not implemented in D because, as a (I think Walter) said, D is not language designed to work with classes or advanced OOP stuff. Nobody uses it, so please, if you are using it, stop and use structs and meta programming instead.

Tbh. the real reason is because there is no real backing and there has never been proposed a DIP on it.
March 16, 2018
On Tuesday, 13 March 2018 at 12:23:06 UTC, Ozan Süel wrote:
> Hi
>
> I have a construction like the following
>
> if (source) {
>   if (source.pool) {
>     if (source.pool.repository) {
>       if (source.pool.repository.directory) {
> 	if (source.pool.repository.directory.users) {
> 	  // do something
>
> Any chance to simplify this nested ifs?
> I know some languages has a way like.
>
> if (source?pool?repository?directory?users) // do something
>
>
> Similar ways in D?
>
> Thanks and Regards, Ozan

Kind of an ugly hack, but:

string createCondition(string[] entries)
{
    string result = "";
    string lastEntry = "";

    foreach (entry; entries)
    {
        if (lastEntry && lastEntry.length) lastEntry ~= "." ~ entry;
        else lastEntry = entry;

        result ~= lastEntry ~ " !is null &&";
    }

    result.length -= 2;

    return result;
}

bool isDefined(alias symbol,T)(T arg)
{
    import std.array : split;

    enum symbolEntries = symbol.split(".");

    enum entriesCondition = createCondition(["arg"] ~ symbolEntries[1..$]);

    mixin("return " ~ entriesCondition ~ ";");
}

...

Usage:

Let's say we have these:

class A {}

class B { A a; }

class C { B b; }

class D { C c; }

class E { D d; }

Then instead of:

auto e = new E;

if (e !is null && e.d !is null && e.d.c !is null && e.d.c.b !is null && e.d.c.b.a !is null)
{
    // ...
}

Then we can just do:

if (isDefined!((e.d.c.b.a).stringof)(e))
{
   // ...
}

...

The ugly part tbh.

is that we need to stringof when passing the symbol and we also have to pass the object itself to the function.

A preferred version would have been:

if (isDefined!(e.d.c.b.a))
{
   // ...
}

Unfortunately that's not possible.

You can see it live here: https://run.dlang.io/is/e2ACNc
March 16, 2018
On Tuesday, 13 March 2018 at 12:23:06 UTC, Ozan Süel wrote:

> if (source?pool?repository?directory?users) // do something
>

That type of chain is sometimes referred to as a "train wreck" (see Law of Demeter).

If this is a common lookup it could be:

if (source && source.GotSomeUsers() )