Should we add `a * b` for vectors?

Walter Bright newshound2 at digitalmars.com
Thu Oct 5 09:52:07 UTC 2017


On 10/5/2017 2:13 AM, Timon Gehr wrote:
> It's easy to explain why: In C++, operators are the _only_ functions that have 
> UFCS.
> 
> This is in stark contrast to D, where all functions _but_ operators have UFCS.
> 
> The proposal was allow UFCS also for overloaded operators.
> 
> Hence, this discussion is about UFCS. These are not really operator overloading 
> issues.

Ok, but I'm not sure what the proposal was.


> UFCS allows hijacking. For an example, see:
> https://github.com/tgehr/d-compiler/pull/1#discussion-diff-89697186L85

That may be a bug in the compiler. Can you produce a small test case? I know 
that some of the UFCS code was written without regard to hijacking.


> (There is a comment in the code noting that it will not compile.)

Right, but I wasn't sure what errors you expected to see. I hate to assume with 
these sorts of things, as people often post examples with errors they didn't 
intend. This is why I ask for examples, and it's nice to also point out the errors.


> The intention of the code was to demonstrate that a type can pass isInputRange 
> in the same module in which it does not support front. This is an example of 
> surprising name lookup behavior.

I submit it is surprising only if you're used to ADL :-)

ADL in C++ makes lookups bafflingly complex, and I doubt many C++ people 
actually understand it. It's like C++ overload resolution, nobody understands 
it, not even me (and I implemented it to the letter of the spec!). Some will 
argue it "just works", and no understanding is necessary, and I suppose that's 
fine until one gets an incomprehensible compiler error.

D's name lookup rules were quite simple, and deliberately set up that way. 
Unfortunately, most people thought they were unintuitive. It turns out that 
simple algorithms are not intuitive, and we now have a fairly complex lookup 
system. Martin and I implemented it, and probably neither of us completely 
understands it. I find it regrettable that things have gotten to that state.


> Of course there is also the opposite problem. You can have a type that supports 
> all range primitives via UFCS but does not pass isInputRange, because Phobos 
> does not import the module where the primitives are defined. (This particular 
> case is sometimes solved by ADL, sometimes not.)
> 
> ---
> 
> struct Iota{ private int a,b; }
> auto iota(int a,int b){ return Iota(a,b); }
> 
> @property int front(Iota i){ return i.a; }
> @property bool empty(Iota i){ return i.a>=i.b; }
> void popFront(ref Iota i){ ++i.a; }
> 
> void main(){
>      import std.stdio;
>      for(auto r=iota(0,10);!r.empty;r.popFront){ // ok
>          writeln(r.front);
>      }
>      import std.algorithm;
>      iota(0,10).each!writeln; // error
>      foreach(i;iota(0,10)) writeln(i); // error
> }
> 
> ---
> 
> If I copy-paste portions of std.range into the main module of the above program 
> instead of importing, I will be able to use my custom type with those Phobos 
> ranges.

I understand this one, as it helpfully says the expected error :-) thank you.

I suggest for this case writing a wrapper type for Iota, with 
front/empty/popFront as members of that wrapper, then it should be good to go. 
It's hardly any more work than writing the free functions. Doing this kind of 
wrapper doesn't work for operator overloading, which brings us back to ADL is 
for operator overloading.


More information about the Digitalmars-d mailing list