www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - The in operator (along with other things) is designed poorly.

reply Ruby The Roobster <michaeleverestc79 gmail.com> writes:


Don't get me wrong, I know that nothing is perfect, and that 
making a programming language is hard, and that there will be 
less-than-optimal features.  However, here are several such 
features that made me find annoying work-arounds. and they will 
be mentioned here.



Operators that can yield an expression evaluable at compile-time 
should not return a type who's value can only be known at run 
time.  The in operator returns a pointer, resulting in the 
following not working:

```d
import std.stdio;

void main()
{
     static if(0 in [0: 0]) //This expression should be true.
     {
         writeln(typeof(0 in [0: 0]).stringof);
     }
}
```

This code fails to compile, because the in operator returns a 
pointer, who's value cannot be known at compile time.  Note that 
the code will compile if you replace the expression being 
evaluated with 1 in [0: 0], because it evaluates to null.  Due to 
this poor design,  to get the code to compile you have to do the 
following:

```d
//This program prints int* to stdout.
import std.stdio;

void main()
{
     static foreach(k; [0: 0])
     {
         static if(k == 0)
         {
             writeln(typeof(0 in [0: 0]).stringof);
         }
     }
}
```


__traits(getOverloads, ... , ... ).

This is the other annoying feature that I encountered today.  
Take the following code:

```d
class C
{
     this(int m)
     {
         this.m = m;
     }
     public C opBinary(string op)(C rhs)
     {
         mixin("return new C(this.m " ~ op ~ " rhs.m);");
     }
     int m;
}

void main()
{
     import std.stdio;
     writeln(__traits(getMember, C, "opBinaryRight")); //false
     writeln(__traits(getOverloads, C, "opBinary")); //You would 
expect the output to be "(C(string op)(C rhs))".  Instead what is 
printed is ().
}
```

In other words, you can determine whether an operator is 
overloaded, but you cannot get the total list of overloads of 
that operator.  What if you need to know if there is a shared 
version?  Too bad, you're going to have to use __traits(compiles) 
to figure it out (though admittedly, it IS easier to use 
__traits(compiles) to figure this out, it still makes no sense 
that __traits(getOverloads) doesn't work on operator overloads 
while everything else does.)
May 30 2022
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 31/05/2022 12:16 PM, Ruby The Roobster wrote:

https://issues.dlang.org/show_bug.cgi?id=23150
May 30 2022
prev sibling next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 31 May 2022 at 00:16:46 UTC, Ruby The Roobster wrote:
     static if(0 in [0: 0]) //This expression should be true.
You can check the pointer it returns for null. static if((0 in [0: 0]) !is null)
 __traits(getOverloads, ... , ... ).
Notice the third argument described in the docs: https://dlang.org/spec/traits.html#getOverloads Reflection over templates is underpowered but there is a thing there to get the template overloads.
May 30 2022
prev sibling parent reply Ruby The Roobster <michaeleverestc79 gmail.com> writes:
On Tuesday, 31 May 2022 at 00:16:46 UTC, Ruby The Roobster wrote:
 ...
To add to my previous post, I present this: ```d struct A { this(int a) { this.a = a; } int a; A opBinary(string op)(A rhs) { mixin("return A(a " ~ op ~ "rhs.a);"); } A opBinaryRight(string op)(A lhs) { mixin("return A(lhs.a " ~ op ~ "rhs.a);"); } } void main(){ import std; auto c = A(1) + A(2); } ``` This doesn't compile because the argument lists for, to quote the compiler: Error: overloads ` system A(A rhs)` and `(A lhs)` both match argument list for `opBinary` This is stupid, because in the example from the spec, the argument lists were the same, and it still compiled. This seems to be a bug.
May 30 2022
parent reply Ruby The Roobster <michaeleverestc79 gmail.com> writes:
On Tuesday, 31 May 2022 at 00:48:57 UTC, Ruby The Roobster wrote:
 On Tuesday, 31 May 2022 at 00:16:46 UTC, Ruby The Roobster 
 wrote:
...
Nevermind. This isn't a bug, and it isn't really an issue.
May 30 2022
parent reply Ruby The Roobster <michaeleverestc79 gmail.com> writes:
On Tuesday, 31 May 2022 at 00:52:30 UTC, Ruby The Roobster wrote:
 On Tuesday, 31 May 2022 at 00:48:57 UTC, Ruby The Roobster 
 wrote:
 On Tuesday, 31 May 2022 at 00:16:46 UTC, Ruby The Roobster 
 wrote:
...
Nevermind. This isn't a bug, and it isn't really an issue.
And what caused me to start writing the code that caused me to make this thread is the fact that interfaces only require the classes that inherit from them to implement virtual functions. This means that if you want to require classes that inherit from and interface to implement operator overloads, you can't rely on the compiler to do it for you: you have to use __traits to make sure that those operator overloads exist.
May 30 2022
parent Nick Treleaven <nick geany.org> writes:
On Tuesday, 31 May 2022 at 00:57:43 UTC, Ruby The Roobster wrote:
 And what caused me to start writing the code that caused me to 
 make this thread is the fact that interfaces only require the 
 classes that inherit from them to implement virtual functions.  
 This means that if you want to require classes that inherit 
 from and interface to implement operator overloads, you can't 
 rely on the compiler to do it for you:  you have to use 
 __traits to make sure that those operator overloads exist.
It should be possible for the compiler to support operator overloads as virtual functions for each specific operator, as long as the runtime parameter types are fixed. That might require each operation to be listed as a separate overload though, `opBinary(string op: ”+”)`, `opBinary(string op: ”-”)` etc.
May 31 2022