www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Operator overloading through UFCS doesn't work

reply "Tommi" <tommitissari hotmail.com> writes:
Quote from TDPL: "D’s approach to operator overloading is 
simple: whenever at least one participant in an operator 
expression is of user-defined type, the compiler rewrites the 
expression into a regular method call with a specific name. Then 
the regular language rules apply."

According to the above, I think the following code should work:

struct MyStruct
{
     int _value;
}

ref MyStruct opUnary(string op : "++")(ref MyStruct ms)
{
     ++ms._value;
     return ms;
}

MyStruct opBinary(string op : "+")(MyStruct ms, int value)
{
     return MyStruct(ms._value + value);
}

void main()
{
     MyStruct ms;

     ms.opUnary!"++"();                 // #1: OK
     MyStruct ms2 = ms.opBinary!"+"(1); // #2: OK

     ++ms;                  // #3
     MyStruct ms3 = ms + 1; // #4
}

#3: Error: 'ms += 1' is not a scalar, it is a MyStruct

#4: Error: incompatible types for ((ms) + (1)):
'MyStruct' and 'int'


I'd expect the lines tagged #3 and #4 to be rewritten by the 
compiler like so:
ms.opUnary!"++"();
MyStruct ms3 = ms.opBinary!"+"(1);

So, the inability to do operator overloading though UFCS must be 
a compiler bug, right?
Oct 13 2012
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Saturday, 13 October 2012 at 08:36:19 UTC, Tommi wrote:
 Quote from TDPL: "D’s approach to operator overloading is 
 simple: whenever at least one participant in an operator 
 expression is of user-defined type, the compiler rewrites the 
 expression into a regular method call with a specific name. 
 Then the regular language rules apply."
Do note that this says *method* call. Your example doesn't use methods. Hence, the current state of operator overloading is consistent with TDPL.
Oct 13 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 13, 2012 11:06:27 Jakob Ovrum wrote:
 On Saturday, 13 October 2012 at 08:36:19 UTC, Tommi wrote:
 Quote from TDPL: "D=E2=80=99s approach to operator overloading is
 simple: whenever at least one participant in an operator
 expression is of user-defined type, the compiler rewrites the
 expression into a regular method call with a specific name.
 Then the regular language rules apply."
=20 Do note that this says *method* call. Your example doesn't use methods. Hence, the current state of operator overloading is consistent with TDPL.
Yes. It is most definitely illegal to overload any operators as free fu= nctions.=20 They're _always_ member variables of the type that they operate on. - Jonathan M Davis
Oct 13 2012
prev sibling parent reply "Tommi" <tommitissari hotmail.com> writes:
On Saturday, 13 October 2012 at 09:06:28 UTC, Jakob Ovrum wrote:
 Do note that this says *method* call. Your example doesn't use 
 methods. Hence, the current state of operator overloading is 
 consistent with TDPL.
I don't agree with the last sentence. According to TDPL: 1) "whenever at least one participant in an operator expression is of user-defined type, the compiler rewrites the expression into a regular method call with a specific name" --------------------------------------------------------------- ++var; gets rewritten to: var.opUnary!"++"(); 2) "if a.fun(b, c, d) is seen but fun is not a member of a’s type, D rewrites that as fun(a, b, c, d) and tries that as well" ---------------------------------------------------------------- So, because opUnary is not a member of var, compiler should rewrite that as: .opUnary!"++"(var);
Oct 13 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 13, 2012 11:41:07 Tommi wrote:
 On Saturday, 13 October 2012 at 09:06:28 UTC, Jakob Ovrum wrote:
 Do note that this says *method* call. Your example doesn't use
 methods. Hence, the current state of operator overloading is
 consistent with TDPL.
=20 I don't agree with the last sentence. According to TDPL: =20 1) "whenever at least one participant in an operator expression is of user-defined type, the compiler rewrites the expression into a regular method call with a specific name" --------------------------------------------------------------- ++var; gets rewritten to: var.opUnary!"++"(); =20 2) "if a.fun(b, c, d) is seen but fun is not a member of a=E2=80=99s type, D rewrites that as fun(a, b, c, d) and tries that as well" ---------------------------------------------------------------- So, because opUnary is not a member of var, compiler should rewrite that as: .opUnary!"++"(var);
Just because the overloaded operator is rewritten into a method call=20= underneath the hood doesn't mean that the UFCS rewrite also applies. Th= e=20 transformation of an operator to a method or a UFCS call to a free func= tion is=20 done _once_. You don't get both. It is most definitely _by design_ that= you=20 cannot overload operators except as member functions. If TDPL says othe= rwise,=20 it's either because you're misunderstanding what it's saying or because= it's=20 wrong. - Jonathan M Davis
Oct 13 2012
parent reply "Tommi" <tommitissari hotmail.com> writes:
On Saturday, 13 October 2012 at 09:50:05 UTC, Jonathan M Davis 
wrote:
 It is most definitely _by design_ that you cannot
 overload operators except as member functions.
I don't understand this design choice then. I don't see any problem in allowing UFCS operators. Because of the way UFCS works, it's guaranteed that there can't be any operator hijacking.
Oct 13 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 13 October 2012 at 10:00:22 UTC, Tommi wrote:
 On Saturday, 13 October 2012 at 09:50:05 UTC, Jonathan M Davis 
 wrote:
 It is most definitely _by design_ that you cannot
 overload operators except as member functions.
I don't understand this design choice then. I don't see any problem in allowing UFCS operators. Because of the way UFCS works, it's guaranteed that there can't be any operator hijacking.
I think implementing UFCS operator overloading is problematic. Firstly, you want to put this language addition too far. Secondly, compiler needs to know whether operator was overloaded or not. If it knows, it generates code to call "opSomething", if nor - it just doesn't generate anything. Now, imagine what would happen if you write in some module "free" function, supposed to hijack operator overloading method of class or struct in another module. If you compile them together, operator would be overloaded, if separately - nothing would happen. This means that operator overloading would depend on with what you compile your module - sometimes nothing would be overloaded, sometimes it would be with one function, sometimes with another. Thirdly, I see no reason in allowing it - for what purpose does you proposal service for?
Oct 13 2012
parent reply "Tommi" <tommitissari hotmail.com> writes:
On Saturday, 13 October 2012 at 11:50:40 UTC, Maxim Fomin wrote:
 I think implementing UFCS operator overloading is problematic. 
 Firstly, you want to put this language addition too far.
I don't see this as taking UFCS functionality "further". Rather, I think it's simply more logical that with UFCS you could provide extra operator methods just like you can provide extra "regular" methods. I assumed that UFCS operator overloading would work for sure, and it seems arbitrary to me that it doesn't.
 Secondly, compiler needs to know whether operator was 
 overloaded or not. If it knows, it generates code to call 
 "opSomething", if nor - it just doesn't generate anything. Now, 
 imagine what would happen if you write in some module "free" 
 function, supposed to hijack operator overloading method of 
 class or struct in another module. If you compile them 
 together, operator would be overloaded, if separately - nothing 
 would happen. This means that operator overloading would depend 
 on with what you compile your module - sometimes nothing would 
 be overloaded, sometimes it would be with one function, 
 sometimes with another.
You use the word "hijack", but free functions can't hijack anything. They can only provide new functionality. The situation you describe is exactly parallel to using UFCS (with regular functions) like this: //File: mystruct.d module mystruct; struct MyStruct { int _value; } //File: incr1.d module incr1; import mystruct; void incr(ref MyStruct ms) { ms._value += 1; } //File: incr2.d module incr2; import mystruct; void incr(ref MyStruct ms) { ms._value += 2; } //File: main.d module main; import std.stdio; import mystruct; static if (true) // change to false to print "2" import incr1; else import incr2; void main() { MyStruct ms; ms.incr(); writeln(ms._value); // prints "1" }
 Thirdly, I see no reason in allowing it - for what purpose does 
 you proposal service for?
The main reason to me is that it would make more sense. It'd seem more logical that way. I can't think of any use cases.
Oct 13 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 13 October 2012 at 15:06:14 UTC, Tommi wrote:
 On Saturday, 13 October 2012 at 11:50:40 UTC, Maxim Fomin wrote:
 I think implementing UFCS operator overloading is problematic. 
 Firstly, you want to put this language addition too far.
I don't see this as taking UFCS functionality "further". Rather, I think it's simply more logical that with UFCS you could provide extra operator methods just like you can provide extra "regular" methods. I assumed that UFCS operator overloading would work for sure, and it seems arbitrary to me that it doesn't.
I don't consider request to put the language in consistency with superficial logic (UFCS allows to use free functions as methods => allow operator overloading hijacking too) as a rational one.
 Secondly, compiler needs to know whether operator was 
 overloaded or not. If it knows, it generates code to call 
 "opSomething", if nor - it just doesn't generate anything. 
 Now, imagine what would happen if you write in some module 
 "free" function, supposed to hijack operator overloading 
 method of class or struct in another module. If you compile 
 them together, operator would be overloaded, if separately - 
 nothing would happen. This means that operator overloading 
 would depend on with what you compile your module - sometimes 
 nothing would be overloaded, sometimes it would be with one 
 function, sometimes with another.
You use the word "hijack", but free functions can't hijack anything.
Their inability to hijack actual methods is not an issue.
 They can only provide new functionality. The situation you 
 describe is exactly parallel to using UFCS (with regular 
 functions) like this:

 //File: mystruct.d
 module mystruct;

 struct MyStruct
 {
     int _value;
 }

 //File: incr1.d
 module incr1;

 import mystruct;

 void incr(ref MyStruct ms)
 {
     ms._value += 1;
 }

 //File: incr2.d
 module incr2;

 import mystruct;

 void incr(ref MyStruct ms)
 {
     ms._value += 2;
 }

 //File: main.d
 module main;

 import std.stdio;
 import mystruct;

 static if (true) // change to false to print "2"
     import incr1;
 else
     import incr2;

 void main()
 {
     MyStruct ms;
     ms.incr();
     writeln(ms._value); // prints "1"
 }
Yes. Do you want to have this with operator overloading too? UFCS is useful if you import some library and want to add extra functionality to particular needs of a module. So, if you do this multiple times and merge modules you may not get into trouble with high probability of conflicting names. Even if they conflict, you can slightly rename them. Can you do this if you define in several modules different operator overloading methods? Guess not.
 Thirdly, I see no reason in allowing it - for what purpose 
 does you proposal service for?
The main reason to me is that it would make more sense. It'd seem more logical that way. I can't think of any use cases.
Different groups of people have different mind and same things produce different sense on them. From my point of view operator overloading methods are special functions and not treating them as candidates for UFCS does make more sense. Even if you convince in your opinion, language addition without applied purposes makes no benefit.
Oct 13 2012
next sibling parent reply "Tommi" <tommitissari hotmail.com> writes:
On Saturday, 13 October 2012 at 16:02:25 UTC, Maxim Fomin wrote:
 From my point of view operator overloading methods are
 special functions and not treating them as candidates for
 UFCS does make more sense.
I can think of only one thing that makes custom operator methods "special" or different from regular methods. It's the fact that you don't *have* to call them through the normal method invocation syntax: var.opSomething(...), but rather, the language provides this nice layer of syntactic sugar through which you *can* call those methods, if you so choose to. What you're saying is, that calling those operator methods through this layer of syntactic sugar, e.g. var + 3, is somehow fundamentally different from directly calling the method, to which this layer of syntactic sugar would forward the expression to call anyway, i.e. var.opBinary!"+"(3)
Oct 13 2012
parent reply "Tommi" <tommitissari hotmail.com> writes:
Another way to describe my reasoning...

According to TDPL, if var is a variable of a user-defined type, 
then:
++var
gets rewritten as:
var.opUnary!"++"()

Thus, it would be very logical to assume that it doesn't matter 
whether you write:
++var
...or, write the following instead:
var.opUnary!"++"()
...because the second form is what the first form gets written to 
anyway.

But, that "very logical assumption" turns out to be wrong. 
Because in D, as it stands currently, it *does* make a difference 
whether you write it using the first form or the second:

struct S
{
     int _value;
}

ref S opUnary(string op : "++")(ref S s)
{
     ++s._value;
     return s;
}

Now, writing the following compiles and works:
S var;
var.opUnary!"++"();

...while the following doesn't compile:
S var;
++var;

This behavior of the language is not logical. And I don't think 
that logic is a matter of preference or taste.
Oct 13 2012
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 13, 2012 19:01:26 Tommi wrote:
 Another way to describe my reasoning...
 
 According to TDPL, if var is a variable of a user-defined type,
 then:
 ++var
 gets rewritten as:
 var.opUnary!"++"()
 
 Thus, it would be very logical to assume that it doesn't matter
 whether you write:
 ++var
 ...or, write the following instead:
 var.opUnary!"++"()
 ...because the second form is what the first form gets written to
 anyway.
 
 But, that "very logical assumption" turns out to be wrong.
 Because in D, as it stands currently, it *does* make a difference
 whether you write it using the first form or the second:
 
 struct S
 {
      int _value;
 }
 
 ref S opUnary(string op : "++")(ref S s)
 {
      ++s._value;
      return s;
 }
 
 Now, writing the following compiles and works:
 S var;
 var.opUnary!"++"();
 
 ...while the following doesn't compile:
 S var;
 ++var;
 
 This behavior of the language is not logical. And I don't think
 that logic is a matter of preference or taste.
All that TDPL is telling you is that the compiler uses "lowering" on overloaded operators to generate their code. It lowers them to calls the appropriate functions. But it does so in a way consistent with how the operators are supposed to work. Preincrement and Postincrement are fundamentally different. D makes the wise choice of making it so that you simply overload increment and then has the compiler use that function in a manner that generates code which is preincrementing or postincrementing depending on which operator was used. This guarantees that preincrement and postincrement are consistent. This is in contrast to C++ where you could make them do totally different things. Not only does that avoid weird bugs, but it makes it so that the compiler can generate more efficient code too. This is because postincrementing generates a temporary to save the original value for the expression where it's being used whereas preincrement does not, and if the compiler knows that preincrement and postincrement are semantically the same, then it can replace postincrement with preincrement when it doesn't matter which is called. In D, because you overload _one_ operator, the compiler knows this for user-defined types, but in C++, it doesn't, and can't make that optimization. So, in C++, code like for(vector<int>::iterator i = v.begin(), e = v.end; i != e; i++) {} is stuck creating a temporary for every call to i++, whereas in D, it can be replaced with ++i. Similarly, in D, >, >=, <=, and < are all translated to calls to opCmp, making it so that you overload one function but get 4 operators. There are cases where it would just be broken for the compiler to simply call your overloaded operator function without doing extra stuff to ensure that it acted like the built-in operators (incrementing being a prime example). So no, it's _not_ simply a matter of calling your overloaded operator functions. It's just that part of the process of compiling code using overloaded operators is to translate it to code which involves calling the overloaded operator functions. That translation may or may not be direct. TDPL makes a point about it to show that the compiler is able to translate the overloaded operators into function calls and the compile those instead of having to go to all of the extra effort required to deal with fully compiling the overloaded operators directly. It's just much simpler to turn one language construct into another, existing language construct, and then compile that rather than having to understand how to compile both. The same happens with other language constructs as well (e.g. scope statements). TDPL _never_ says that syntactic sugar is applicable to lowered code. Lowering code is effectively an implementation detail of the compiler that makes its life easier. It does _not_ make it so that one language construct will be translated into another where it will then be assumed that the new language construct is using syntactic sugar such as UFCS, because _all_ of that syntactic sugar must be lowered to code which _isn't_ syntactic sugar anymore. It would be far more expensive to have to continually make passes to lower code over and over again until no more lowering was required than it would be to just have to lower it once. You're reading way to much into what TDPL is saying. It's simply telling you about how the compiler goes about translating code which uses operators such as +, >, or = into the functions that you used to overload them. It's _not_ telling you that it'll do UFCS on overloaded operator functions. Heck, technically, TDPL never really says that D _has_ UFCS. It talks about the member call function syntax for _arrays_ (which D had for ages before it had UFCS), not for types in general. It's only very recently that full UFCS has been added to the language. Both overloaded operators and UFCS use lowering to generate different code which the compiler then compiles, but they _aren't_ mixed and they will _never_ be mixed. If it had _ever_ been intended that it be possible to overload operators as free functions, then we'd simply have made it so that you could declare a free function like auto opBinary(string op)(Foo foo, Bar bar) { ... } in the first place without requiring that it be a member function. But it _was_ required to be a member function, and it would make no sense to allow a new feature to circumvent that restriction. If it was supposed to be circumventable, then the restriction wouldn't have been put there in the first place. - Jonathan M Davis
Oct 13 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/13/2012 10:15 PM, Jonathan M Davis wrote:
 ...
 construct is using syntactic sugar such as UFCS, because _all_ of that
 syntactic sugar must be lowered to code which _isn't_ syntactic sugar anymore.
That is not what lowering means.
 It would be far more expensive to have to continually make passes to lower
 code over and over again until no more lowering was required than it would be
 to just have to lower it once.
 ...
It does not have to be implemented it in an inefficient way. It is actually simpler for a sane compiler implementation to make UFCS apply to lowered overloaded operators than to restrict it.
 You're reading way to much into what TDPL is saying. It's simply telling you
 about how the compiler goes about translating code which uses operators such
 as +, >, or = into the functions that you used to overload them. It's _not_
 telling you that it'll do UFCS on overloaded operator functions.
It is telling us that a+b is transformed to a.opBinary!"+"(b) UFCS applies to a.opBinary!"+"(b).
 Heck,
 technically, TDPL never really says that D _has_ UFCS. It talks about the
 member call function syntax for _arrays_ (which D had for ages before it had
 UFCS), not for types in general. It's only very recently that full UFCS has
 been added to the language.
Exactly, so what is the point? If TDPL does not talk about the UFCS feature, then TDPL not talking about UFCS in the context of one specific case certainly cannot be used as an argument to justify that it should not apply in that case.
 Both overloaded operators and UFCS use lowering to generate different code
 which the compiler then compiles,
By using the same strategy recursively, otherwise it is not called lowering.
 but they _aren't_ mixed and they will
 _never_ be mixed. If it had _ever_ been intended that it be possible to
 overload operators as free functions, then we'd simply have made it so that
 you could declare a free function like

 auto opBinary(string op)(Foo foo, Bar bar)
 {
     ...
 }

 in the first place  without requiring that it be a member function.
You can.
 But it _was_
 required to be a member function, and it would make no sense to allow a new
 feature to circumvent that restriction. If it was supposed to be
 circumventable, then the restriction wouldn't have been put there in the first
 place.
This argument is even less convincing in the context of an informally specified language with a somewhat buggy reference compiler.
Oct 13 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sun, Oct 14, 2012 at 12:12:01AM +0200, Timon Gehr wrote:
 On 10/13/2012 10:15 PM, Jonathan M Davis wrote:
[...]
but they _aren't_ mixed and they will _never_ be mixed. If it had
_ever_ been intended that it be possible to overload operators as
free functions, then we'd simply have made it so that you could
declare a free function like

auto opBinary(string op)(Foo foo, Bar bar)
{
    ...
}

in the first place  without requiring that it be a member function.
You can.
But it _was_ required to be a member function, and it would make no
sense to allow a new feature to circumvent that restriction. If it
was supposed to be circumventable, then the restriction wouldn't have
been put there in the first place.
This argument is even less convincing in the context of an informally specified language with a somewhat buggy reference compiler.
OK, before this thread devolves into a shouting match, I'd like to understand what was the rationale behind this restriction. What were the reasons behind not allowing a non-member function to overload an operator? What are the pros and cons considered at the time, and how do they weigh now? Or was it just a matter of not being implemented because nobody thought about it at the time? T -- Why can't you just be a nonconformist like everyone else? -- YHL
Oct 13 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/14/2012 12:36 AM, H. S. Teoh wrote:
 On Sun, Oct 14, 2012 at 12:12:01AM +0200, Timon Gehr wrote:
 On 10/13/2012 10:15 PM, Jonathan M Davis wrote:
[...]
 but they _aren't_ mixed and they will _never_ be mixed. If it had
 _ever_ been intended that it be possible to overload operators as
 free functions, then we'd simply have made it so that you could
 declare a free function like

 auto opBinary(string op)(Foo foo, Bar bar)
 {
     ...
 }

 in the first place  without requiring that it be a member function.
You can.
 But it _was_ required to be a member function, and it would make no
 sense to allow a new feature to circumvent that restriction. If it
 was supposed to be circumventable, then the restriction wouldn't have
 been put there in the first place.
This argument is even less convincing in the context of an informally specified language with a somewhat buggy reference compiler.
OK, before this thread devolves into a shouting match, I'd like to understand what was the rationale behind this restriction. What were the reasons behind not allowing a non-member function to overload an operator? What are the pros and cons considered at the time, and how do they weigh now? Or was it just a matter of not being implemented because nobody thought about it at the time? T
Afaik free-function operator overloads (but not in the context of UFCS) were considered and turned down because D did not want to get amidst discussions about adding Koenig lookup. UFCS does not do Koenig lookup.
Oct 13 2012
parent reply Elie Morisse <syniurge gmail.com> writes:
On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
 Afaik free-function operator overloads (but not in the context 
 of UFCS) were considered and turned down because D did not want 
 to get amidst discussions about adding Koenig lookup. UFCS does 
 not do Koenig lookup.
I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are. Sorry for digging up this thread, just getting irritated by a restriction that seems pointless and arbitrary. Overloaded operators would suffer from the same potential abuses other methods are subjected to if UFCS was enabled, nothing more as far as I can see.
May 24 2016
next sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Tuesday, May 24, 2016 23:19:32 Elie Morisse via Digitalmars-d-learn wrote:
 On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
 Afaik free-function operator overloads (but not in the context
 of UFCS) were considered and turned down because D did not want
 to get amidst discussions about adding Koenig lookup. UFCS does
 not do Koenig lookup.
I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are. Sorry for digging up this thread, just getting irritated by a restriction that seems pointless and arbitrary. Overloaded operators would suffer from the same potential abuses other methods are subjected to if UFCS was enabled, nothing more as far as I can see.
If UFCS doesn't work, because there are two free functions with the same name which take the same arguments, then you can differentiate between them by not using UFCS and using their full import paths, or you can alias them so that they don't have the same name. Neither of those would be possible with operator overloading. If overloaded operators were allowed as free functions, then if there were ever a symbol conflict, you'd be screwed. - Jonathan M Davis
May 24 2016
parent reply Elie Morisse <syniurge gmail.com> writes:
On Tuesday, 24 May 2016 at 23:43:46 UTC, Jonathan M Davis wrote:
 On Tuesday, May 24, 2016 23:19:32 Elie Morisse via 
 Digitalmars-d-learn wrote:
 On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
 Afaik free-function operator overloads (but not in the 
 context of UFCS) were considered and turned down because D 
 did not want to get amidst discussions about adding Koenig 
 lookup. UFCS does not do Koenig lookup.
I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are. Sorry for digging up this thread, just getting irritated by a restriction that seems pointless and arbitrary. Overloaded operators would suffer from the same potential abuses other methods are subjected to if UFCS was enabled, nothing more as far as I can see.
If UFCS doesn't work, because there are two free functions with the same name which take the same arguments, then you can differentiate between them by not using UFCS and using their full import paths, or you can alias them so that they don't have the same name. Neither of those would be possible with operator overloading. If overloaded operators were allowed as free functions, then if there were ever a symbol conflict, you'd be screwed. - Jonathan M Davis
X.FreeFunc(Y); // multiple matches error ModuleA.FreeFunc(X, Y); // ok X * Y; // multiple matches error ModuleA.opBinary!'*'(X, Y); // ok Is there much of a difference between the two?
May 25 2016
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, May 25, 2016 15:46:23 Elie Morisse via Digitalmars-d-learn 
wrote:
 On Tuesday, 24 May 2016 at 23:43:46 UTC, Jonathan M Davis wrote:
 On Tuesday, May 24, 2016 23:19:32 Elie Morisse via

 Digitalmars-d-learn wrote:
 On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
 Afaik free-function operator overloads (but not in the
 context of UFCS) were considered and turned down because D
 did not want to get amidst discussions about adding Koenig
 lookup. UFCS does not do Koenig lookup.
I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are. Sorry for digging up this thread, just getting irritated by a restriction that seems pointless and arbitrary. Overloaded operators would suffer from the same potential abuses other methods are subjected to if UFCS was enabled, nothing more as far as I can see.
If UFCS doesn't work, because there are two free functions with the same name which take the same arguments, then you can differentiate between them by not using UFCS and using their full import paths, or you can alias them so that they don't have the same name. Neither of those would be possible with operator overloading. If overloaded operators were allowed as free functions, then if there were ever a symbol conflict, you'd be screwed. - Jonathan M Davis
X.FreeFunc(Y); // multiple matches error ModuleA.FreeFunc(X, Y); // ok X * Y; // multiple matches error ModuleA.opBinary!'*'(X, Y); // ok Is there much of a difference between the two?
It's not an overloaded operator anymore at that point, and that definitely fails to work for generic code, since not all operators are overloaded operators. Free functions don't have that problem. - Jonathan M Davis
May 25 2016
parent reply Elie Morisse <syniurge gmail.com> writes:
On Wednesday, 25 May 2016 at 21:50:06 UTC, Jonathan M Davis wrote:
 It's not an overloaded operator anymore at that point, and that 
 definitely fails to work for generic code, since not all 
 operators are overloaded operators. Free functions don't have 
 that problem.
Sorry to reiterate the previous post but is that really the case? void FuncTemplate(...)(...) { X.FreeFunc(Y); } import ModuleA; // contains FreeFunc import ModuleB; // contains a conflicting FreeFunc overload FuncTemplate!()(); // fails Where is the difference with writing generic code with operators (overloaded or not)?
May 25 2016
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, May 25, 2016 23:31:18 Elie Morisse via Digitalmars-d-learn 
wrote:
 On Wednesday, 25 May 2016 at 21:50:06 UTC, Jonathan M Davis wrote:
 It's not an overloaded operator anymore at that point, and that
 definitely fails to work for generic code, since not all
 operators are overloaded operators. Free functions don't have
 that problem.
Sorry to reiterate the previous post but is that really the case? void FuncTemplate(...)(...) { X.FreeFunc(Y); } import ModuleA; // contains FreeFunc import ModuleB; // contains a conflicting FreeFunc overload FuncTemplate!()(); // fails Where is the difference with writing generic code with operators (overloaded or not)?
The difference is that it's impossible to do 10.opBinary!"+"(15), so if you're forced to do foo.opBinary!"+"(bar) to get around a symbol conflict, it won't work with built-in types. UFCS does not have that problem, because you're dealing with free functions and can choose to not use UFCS and provide the full import path or to alias the function, which you can't do with operators - particularly built-in operators. D was designed to be much cleaner with operator overloading than C++ is. It restricts what the definitions of the operators are so that you don't have to define as many of them to get the basic operations (e.g. opCmp for most of the comparison operators or op!"++" for both pre-increment and post-increment) and so that they aren't easily overloaded to do stuff that does not correspond to what that operator does for built-in types. D doesn't even use + for string concatenation, because Walter thought that that was operator abuse. Allowing arbitrary code to add overloaded operators to an existing type is not at all in line with that philosophy. Regardless, there really isn't much point in arguing this. If you want things to change, you're going to need to convince Walter, which I very much doubt is going to happen. - Jonathan M Davis
May 25 2016
next sibling parent reply Elie Morisse <syniurge gmail.com> writes:
On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
 The difference is that it's impossible to do 
 10.opBinary!"+"(15), so if you're forced to do 
 foo.opBinary!"+"(bar) to get around a symbol conflict, it won't 
 work with built-in types.
Obviously operator overloading should be limited to class and struct types, so that's not really relevant.
 UFCS does not have that problem, because you're dealing with 
 free functions and can choose to not use UFCS and provide the 
 full import path or to alias the function, which you can't do 
 with operators - particularly built-in operators.
I still don't understand what you're getting at, unfortunately.
 D was designed to be much cleaner with operator overloading 
 than C++ is. It restricts what the definitions of the operators 
 are so that you don't have to define as many of them to get the 
 basic operations (e.g. opCmp for most of the comparison 
 operators or op!"++" for both pre-increment and post-increment) 
 and so that they aren't easily overloaded to do stuff that does 
 not correspond to what that operator does for built-in types. D 
 doesn't even use + for string concatenation, because Walter 
 thought that that was operator abuse. Allowing arbitrary code 
 to add overloaded operators to an existing type is not at all 
 in line with that philosophy.

 Regardless, there really isn't much point in arguing this. If 
 you want things to change, you're going to need to convince 
 Walter, which I very much doubt is going to happen.

 - Jonathan M Davis
Thanks for taking the time to explain, although I still fail to see a good justification for disabling UFCS for operators. I will look for more discussions on the topic and if still no opposing argument seems valid I might push the issue forward.
May 26 2016
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, May 26, 2016 16:24:37 Elie Morisse via Digitalmars-d-learn wrote:
 On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
 The difference is that it's impossible to do
 10.opBinary!"+"(15), so if you're forced to do
 foo.opBinary!"+"(bar) to get around a symbol conflict, it won't
 work with built-in types.
Obviously operator overloading should be limited to class and struct types, so that's not really relevant.
It's completely relevent, because generic code is frequently going to operate on a variety of types - including both built-in types and user-defined types. If code is going to use +, then + must work. opBinary!"+" is simply not going to cut it. With UFCS, if there's a potential symbol conflict, then you can work around it - even in generic code. But with an overloaded operator, the operator must work as an operator, or generic code simply won't work.
 UFCS does not have that problem, because you're dealing with
 free functions and can choose to not use UFCS and provide the
 full import path or to alias the function, which you can't do
 with operators - particularly built-in operators.
I still don't understand what you're getting at, unfortunately.
You don't _have_ to use UFCS. You can call the function as a normal free function with the full import path. You can also alias the function to a different name and use that with UFCS or import the conflicting function with an alias so that it doesn't conflict. The overloaded operator, on the other hand, needs to work as on overloaded operator, and we can't just call an overloaded operator with its full import path or alias it when importing it, because it's an overloaded operator and not just a free function. We have ways to distinguish conflicting types with free functions, and we don't with operators, because operators were designed to be part of the type and not free functions. And syntactically, it really doesn't work to provide a way to distinguish between conflicting versions of an overloaded operator, because then you're no longer just using the operator and might as well just be using a function. But all I'm really doing here is saying the same thing multiple times in slightly different ways, so if you don't get it, I don't know how to explain it.
 Thanks for taking the time to explain, although I still fail to
 see a good justification for disabling UFCS for operators. I will
 look for more discussions on the topic and if still no opposing
 argument seems valid I might push the issue forward.
You're going to need more than a good reason why it shouldn't be allowed. You're going to need a good reason why it should be, and I really don't think that you're going to have one good enough to get you anywhere with Walter. I'm fairly certain that there's a thread or two floating around somewhere in the main newsgroup where he's responded to the issue before though. - Jonathan M Davis
May 26 2016
prev sibling parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
 The difference is that it's impossible to do 
 10.opBinary!"+"(15), so if you're forced to do 
 foo.opBinary!"+"(bar) to get around a symbol conflict, it won't 
 work with built-in types.
Well, that begs the question: Why don't built-in types define `opBinary`? That's just another arbitrary irregularity, isn't it.
May 27 2016
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
next sibling parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Sunday, 29 May 2016 at 07:18:10 UTC, Jonathan M Davis wrote:
 On Friday, May 27, 2016 09:08:20 Marc Schütz via 
 Digitalmars-d-learn wrote:
 On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis 
 wrote:
 The difference is that it's impossible to do
 10.opBinary!"+"(15), so if you're forced to do
 foo.opBinary!"+"(bar) to get around a symbol conflict, it 
 won't
 work with built-in types.
Well, that begs the question: Why don't built-in types define `opBinary`? That's just another arbitrary irregularity, isn't it.
It was never intended that any op* function be called by anyone except where the compiler lowers code to use them. They're for declaring overloaded operators on user-defined types so that those types can be used with those operators. If you're calling opBinary in your own code, you're doing it wrong. And it would be downright silly to then add opBinary to the built-in types.
If I were to design my own language from scratch, that's actually how I would do it. All operators, even for built-in types, would just be syntax sugar for the method calls. The goal should be to minimize the difference between built-in and user-defined types as much as possible. Turtles all the way down...
 They don't need operator overloading. They already have the 
 operators. Operators are supposed to be used as operators, not 
 functions, and if there's any need to use them as functions, 
 then there's something seriously wrong. And the fact that 
 allowing free functions to overload operators via UFCS sends us 
 into that territory just highlights the fact that they're a 
 horrible idea.
I'd say the fact that it doesn't work, and can't currently work for the reasons you described, points to an inconsistency in the language's design. It means that we have two largely overlapping concepts (builtin types and user defined types), where most language features work the same for both, but some don't. That's not the end of the world, of course, but still...
May 30 2016
parent pineapple <meapineapple gmail.com> writes:
Here's one more vote for extending UFCS to operator overloading. 
Elie wrote that it's "a restriction that seems pointless and 
arbitrary"... which summarizes my own thoughts rather well, too.

There are certainly concerning scenarios that can arise from 
making this change, but the correct way to approach this problem 
is not to tell the programmer "I won't let you use that tool, 
because if you mishandle it then you might find yourself in a 
nasty mess." That's what Java does - it treats the programmer 
like an idiot - and that's why it's so universally despised.

It has consistently been my impression that this is very much not 
the sort of philosophy D follows.

Anyway, D already provides the programmer with a wealth of tools 
which, if mishandled, can place them in a nasty mess. So I think 
this is a poor rationale for withholding from the programmer one 
more.
May 30 2016
prev sibling parent reply ixid <adamsibson hotmail.com> writes:
On Sunday, 29 May 2016 at 07:18:10 UTC, Jonathan M Davis wrote:
 And the fact that allowing free functions to overload operators 
 via UFCS sends us into that territory just highlights the fact 
 that they're a horrible idea.

 - Jonathan M Davis
Do you have any examples of UFCS doing bad things? Most people seem to very much like it yet you argue against any change that would benefit UFCS. You seem to prefer: read(to(easier(much(i)))) over i.much.easier.to.read
May 31 2016
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Tuesday, May 31, 2016 14:11:58 ixid via Digitalmars-d-learn wrote:
 On Sunday, 29 May 2016 at 07:18:10 UTC, Jonathan M Davis wrote:
 And the fact that allowing free functions to overload operators
 via UFCS sends us into that territory just highlights the fact
 that they're a horrible idea.

 - Jonathan M Davis
Do you have any examples of UFCS doing bad things? Most people seem to very much like it yet you argue against any change that would benefit UFCS. You seem to prefer: read(to(easier(much(i)))) over i.much.easier.to.read
The primary benefit of UFCS is that you can write generic code that will work with both member functions and free functions, allowing you to have a free function that does something and a member function that does that same thing more efficiently for that specific type (a prime example of this would be a function like find where a linear search make sense in most cases but wouldn't for certain data structures - e.g. a sorted, binary tree). So, the "universal" aspect of UFCS is important for generic code, whereas it would be completely unnecessary if the code weren't generic. All of the other benefits of UFCS are highly subjective and have to do with what a particular person thinks is easier or harder to read rather than actual, technical benefits (though obviously writing code in a way that is easier to read for those working on it is obviously valuable). Personally, I've dealt with functional languages enough that I've never felt that UFCS was much of an improvement syntactically. But we have it, and anyone is free to use it or not as they see fit. Regardless, what I'm arguing against here is altering operator overloading so that it works with free functions via UFCS instead of requiring that it be part of the type. It's a terrible idea IMHO to allow random code to add an overloaded operator to a type rather having it actually be part of the type's design, and in addition to that, it doesn't play at all nicely with symbol conflicts, because you're using an operator rather than a function, meaning that not only do you have no way to specify which version of the overloaded operator code should use, but it would completely defeat the purpose of using an overloaded operator in the first place even if you could. But fortunately, Walter agrees with me (or at least did, the last time the subject came up in the newsgroup), so I don't think that I have to worry about overloaded operators be definable via free functions. - Jonathan M Davis
May 31 2016
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 25.05.2016 01:19, Elie Morisse wrote:
 On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
 Afaik free-function operator overloads (but not in the context of
 UFCS) were considered and turned down because D did not want to get
 amidst discussions about adding Koenig lookup. UFCS does not do Koenig
 lookup.
I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are. ...
Yup. It could be argued that it is essentially a compiler bug.
 Sorry for digging up this thread, just getting irritated by a
 restriction that seems pointless and arbitrary.
 ...
It is, but it has a few vocal proponents.
 Overloaded operators would suffer from the same potential abuses other
 methods are subjected to if UFCS was enabled, nothing more as far as I
 can see.
You are perfectly right of course. It's painful for no benefit. (For example, there's no way to overload e.g. '+=' for classes in a way that reassigns the reference.)
May 26 2016
prev sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 13 October 2012 at 22:34:19 UTC, H. S. Teoh wrote:
 OK, before this thread devolves into a shouting match, I'd like 
 to
 understand what was the rationale behind this restriction. What 
 were the
 reasons behind not allowing a non-member function to overload an
 operator? What are the pros and cons considered at the time, 
 and how do
 they weigh now? Or was it just a matter of not being 
 implemented because
 nobody thought about it at the time?


 T
It likely was not implemented rather than disallowed. The only mentioned reason is to allow writing operator overloading methods outside type scope - just because somebody (currently two people) consider it logical to broaden UFCS usage. This doesn't solve ay practical issue.
Oct 13 2012
parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 10/14/12 08:13, Maxim Fomin wrote:
 The only mentioned reason is to allow writing operator overloading methods
outside type scope - just because somebody (currently two people) consider it
logical to broaden UFCS usage.
It's more than two people... Also, it's not about "broadening UFCS usage", it's about making UFCS work properly.
 This doesn't solve ay practical issue.
Obviously, it does. Otherwise this issue wouldn't come up repeatedly. artur
Oct 14 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Sunday, 14 October 2012 at 19:50:54 UTC, Artur Skawina wrote:
 On 10/14/12 08:13, Maxim Fomin wrote:
 The only mentioned reason is to allow writing operator 
 overloading methods outside type scope - just because somebody 
 (currently two people) consider it logical to broaden UFCS 
 usage.
It's more than two people... Also, it's not about "broadening UFCS usage", it's about making UFCS work properly.
When UFCS was added to the language its purpose was to call free functions pretending you are invoking methods. It does it job pretty well and actually works properly. But some questions arise: how this addition interacts with other parts of the language: - with calling through pointer (8603) - with template alias parameters (8692) - with function imports (6185) - with typeof operator (8661) - with operator overloading - ... - probably other issues which are not encountered yet. Each time there should be a decision to choose which language feature has higher priority. That is why this is broadening UFCS usage on areas of the language where it has never been before rather than making work properly in existing areas of usage.
 This doesn't solve ay practical issue.
Obviously, it does. Otherwise this issue wouldn't come up repeatedly. artur
Actually not - the only purpose mentioned in the thread was to place operator overloading methods outside scope of declaration.
Oct 15 2012
parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 10/15/12 10:17, Maxim Fomin wrote:
 On Sunday, 14 October 2012 at 19:50:54 UTC, Artur Skawina wrote:
 On 10/14/12 08:13, Maxim Fomin wrote:
 The only mentioned reason is to allow writing operator overloading methods
outside type scope - just because somebody (currently two people) consider it
logical to broaden UFCS usage.
It's more than two people... Also, it's not about "broadening UFCS usage", it's about making UFCS work properly.
When UFCS was added to the language its purpose was to call free functions pretending you are invoking methods. It does it job pretty well and actually works properly. But some questions arise: how this addition interacts with other parts of the language: - with calling through pointer (8603) - with template alias parameters (8692) - with function imports (6185) - with typeof operator (8661) - with operator overloading - ... - probably other issues which are not encountered yet.
UFCS has pros and cons. I could agree that it has problems and should be removed from the language completely. But if the feature is there, it should work, w/o any unnecessary special cases. An overloaded operator is just another normal method; you get the same type of problems when dealing with "normal" methods - eg in types having an "alias this" - an UFCS "method" must take precedence over one reachable via the alias - just like in the overloaded op case. The only sane alternative would be disallowing UFCS for types with an "alias this" (which would be a severe limitation).
 Each time there should be a decision to choose which language feature has
higher priority. That is why this is broadening UFCS usage on areas of the
language where it has never been before rather than making work properly in
existing areas of usage.
 
 This doesn't solve ay practical issue.
Obviously, it does. Otherwise this issue wouldn't come up repeatedly.
Actually not - the only purpose mentioned in the thread was to place operator overloading methods outside scope of declaration.
And the purpose of UFCS is?... "operator overloading methods" are /not/ special. There have been several threads in the past where this missing functionality was mentioned. It's how it should work, if UFCS is here to stay. If you think that would causes problems and UFCS should instead be removed from the language then I can understand that - UFCS /does/ have issues. But it's also useful and I'm not yet convinced that the problems it introduces justifies killing the feature. Nothing justifies special casing just certain combinations like op-overloading and UFCS however, especially when it's not necessary. artur
Oct 15 2012
next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 15 October 2012 at 11:01:13 UTC, Artur Skawina wrote:
 UFCS has pros and cons. I could agree that it has problems and 
 should be removed
 from the language completely. But if the feature is there, it 
 should work, w/o any
 unnecessary special cases.
Special cases would be created by any decision, the only question is which feature is discriminated - alias this, UFCS or something else (currently UFCS is).
 An overloaded operator is just another normal method; you get 
 the same type of
 problems when dealing with "normal" methods - eg in types 
 having an "alias this" -
  an UFCS "method" must take precedence over one reachable via 
 the alias - just like
 in the overloaded op case. The only sane alternative would be 
 disallowing UFCS
 for types with an "alias this" (which would be a severe 
 limitation).
You seem to be in the second camp (UFCS free function takes precedence over alias this, if declared). I am not against, just to note.
 And the purpose of UFCS is?... "operator overloading methods" 
 are /not/ special.
 artur
The point is that when you want to define UFCS free functions like opUnary, you want not only to call them like a.opUnary!"++"() but to code like ++a. That is the key issue here and that makes the whole case special. In other words: with UFCS you have an option: to call your function as it was a method of some type. And anyone has this option. The only problem is namespace conflict which can be easily avoided. But you still has the option. With UFCS operator overloaded functions you have *two* options: to call free functions as methods as usual *and* to use struct/class with many operators in a manner you want. But if anyone of that type users define his set of operator overloaded functions *you lose the second option* which makes the proposal to allow simultaneous access to single resource pointless. Consider this: ---somelib.d--- struct A { void foo() {} } ---otherlib.d--- void bar(A a) {} ---mycode.d--- // blah, foo and bar are taken // solution - choose other name void baz(A a) {} --------------- Now assume, UFCS operator overload is possible. ---somelib.d--- struct A { int i; int j; } ---mycode.d--- int opUnary(string T : "++")() { return ++i; } ... ++a; ... ------------- At some point of time the owner of somelib.d changes code (or anyone whom code you import define such functions): ---somelib.d--- struct A { int i; int j; int opUnary(string T : "++")() { return ++j; } } ---mycode.d--- int opUnary(string T : "++")() { return ++i; } ---------------- So, you lost your option to use A in expressions and call your function which is the point here. You cannot invent +my_unary+ operator. Neither you can rebind ++ to some function other than opUnary. Yes, it also may happen with regular function, when you lose ability to give a function some specific name you want (like "create", "foo" etc.). But in case of UFCS operators you lose not only some function name ("opUnary") but corresponding expression as well (++). This means that it makes sense to allow only one set of opUnary/opBinary/.. etc. of functions (anyway, only one can define them and use with operators) and the most suitable place is declaration of their type.
Oct 15 2012
parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 10/15/12 17:49, Maxim Fomin wrote:
 On Monday, 15 October 2012 at 11:01:13 UTC, Artur Skawina wrote:
 UFCS has pros and cons. I could agree that it has problems and should be
removed
 from the language completely. But if the feature is there, it should work, w/o
any
 unnecessary special cases.
Special cases would be created by any decision, the only question is which feature is discriminated - alias this, UFCS or something else (currently UFCS is).
 An overloaded operator is just another normal method; you get the same type of
 problems when dealing with "normal" methods - eg in types having an "alias
this" -
  an UFCS "method" must take precedence over one reachable via the alias - just
like
 in the overloaded op case. The only sane alternative would be disallowing UFCS
 for types with an "alias this" (which would be a severe limitation).
You seem to be in the second camp (UFCS free function takes precedence over alias this, if declared). I am not against, just to note.
Actually, I'm not really in any camp. UFCS has several obvious problems plus likely quite a few more subtle ones. Ignoring the issues does not make them go away and the some-compiler-happens-to-implement-it-like-that-today-therefore-thats-how-it- -must-work arguments, that often appear here, do not really help. Note that my above "UFCS method must take precedence" statement only describes the required functionality; handling it like that /by default/ wouldn't probably be a good idea, as that would make accidental method hijacking possible. The lookup should be more like - T.method - ufcs_method(T) marked with 'override' - while (T = alias this) { - T.method - ufcs_method(T) marked with 'override' } - ufcs_method(T) w/o 'override' - while (T = alias this) - ufcs_method(T) w/o 'override' with the compiler enforcing the obvious 'override' rules for ufcs_method declarations (requiring that T isn't opaque when declaring (or calling) UFCS functions is reasonable, i don't think having 'foo(a)' and 'a.foo()' mean completely different things would work well together with UFCS). And yes, it wouldn't completely eliminate the possibility of hijacking - but you'd need three components interacting for it to happen, which would make it much less likely to occur. [Note i came up w/ this design while writing this email - it's not necessarily perfect.]
 And the purpose of UFCS is?... "operator overloading methods" are /not/
special.
The point is that when you want to define UFCS free functions like opUnary, you want not only to call them like a.opUnary!"++"() but to code like ++a. That is the key issue here and that makes the whole case special. In other words: with UFCS you have an option: to call your function as it was a method of some type. And anyone has this option. The only problem is namespace conflict which can be easily avoided. But you still has the option. With UFCS operator overloaded functions you have *two* options: to call free functions as methods as usual *and* to use struct/class with many operators in a manner you want. But if anyone of that type users define his set of operator overloaded functions *you lose the second option* which makes the proposal to allow simultaneous access to single resource pointless.
This is how UFCS works - for "normal" methods. There's no reason to handle op overloads or other special methods differently. You are arguing for introducing arbitrary restrictions, which would bring no gain (that i can see right now), but disallow useful functionality. Yes, there are some issues, but those are not op-overload specific, but UFCS-related.
 Yes, it also may happen with regular function, when you lose ability to give a
function some specific name you want (like "create", "foo" etc.). But in case
of UFCS operators you lose not only some function name ("opUnary") but
corresponding expression as well (++).
 This means that it makes sense to allow only one set of opUnary/opBinary/..
etc. of functions (anyway, only one can define them and use with operators) and
the most suitable place is declaration of their type.
Well, i don't think anybody wants to /override/ existing operators - it's only about allowing /extending/ the functionality of non-local types, by adding support for additional ops and/or types. While being able to override existing methods with UFCS would have some uses, allowing that would also introduce additional problems. Anyway, if you need to modify how a type's existing ops work you can always sub-type - this is also true in the (non-virtual) method case; UFCS is basically just syntax sugar (which allows you to transparently locally inject methods w/o creating a new type, downcasting and handling the (implicit) upcasts (which could be problematic when eg working with (pointers-to-)structs)). artur
Oct 15 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Tuesday, 16 October 2012 at 00:50:54 UTC, Artur Skawina wrote:
 Actually, I'm not really in any camp. UFCS has several obvious 
 problems plus likely
 quite a few more subtle ones. Ignoring the issues does not make 
 them go away and
 the 
 some-compiler-happens-to-implement-it-like-that-today-therefore-thats-how-it-
 -must-work arguments, that often appear here, do not really 
 help.
I am against proposal not because dmd doesn't do it but because I believe it is unwisely pushed in a manner that defects the purpose of proposal. BTW, some operators are not overloadable because, if I remember right, "they were considered to create more confusion than flexibility if ever overloaded". Leaving UFCS with operator overloading as they are now does make sense, because of similar reason.
 Well, i don't think anybody wants to /override/ existing 
 operators - it's only about
 allowing /extending/ the functionality of non-local types, by 
 adding support for additional
 ops and/or types. While being able to override existing methods 
 with UFCS would have some
 uses, allowing that would also introduce additional problems.
 Anyway, if you need to modify how a type's existing ops work 
 you can always sub-type -
 this is also true in the (non-virtual) method case; UFCS is 
 basically just syntax sugar
 (which allows you to transparently locally inject methods w/o 
 creating a new type,
 downcasting and handling the (implicit) upcasts (which could be 
 problematic when eg
 working with (pointers-to-)structs)).

 artur
This doesn't scale well. Certanly, nobody would intentionally create problems. But if you import code of other people, whom you cannot control, override problems occurs. At NG discussion it may look nice to define some type and then add operator overloading methods but as soon as you import some other modules, authors of which also consider UFCS operators a good idea, everything breaks including namespace conflict as well as loosing ability to manipulate that type within built-in expression as well.
Oct 16 2012
next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 10/16/12 17:57, Maxim Fomin wrote:
 This doesn't scale well. Certanly, nobody would intentionally create problems.
But if you import code of other people, whom you cannot control, override
problems occurs.
 
 At NG discussion it may look nice to define some type and then add operator
overloading methods but as soon as you import some other modules, authors of
which also consider UFCS operators a good idea, everything breaks including
namespace conflict as well as loosing ability to manipulate that type within
built-in expression as well.
Operator overloading can be abused - that's an obvious and well known fact. But that same feature can also be very useful, if used right. Worrying about UFCS problems in the context of op-overloading needlessly complicates the issue - the UFCS problems are there also w/o op-overloads. UFCS is, like a lot of D features, just a quick hack, that somebody thought was "cute" enough to add to the language, w/o really considering the consequences. It might be possible to make UFCS solid enough, but introducing a lot of special-casing isn't the right way. For example, UFCS will allow you to write a templated generic function (or new type) that works with any type providing a certain interface (function signatures in this case) and "fills in" missing optional methods, w/o cluttering the code or wrapping the methods, right? Wrong, as UFCS is (wrongly) restricted to module-scope functions, hence can't be used for this. UFCS is nothing but syntax sugar (you can do 'f(o)' everywhere where UFCS would let you do 'o.f()'). Similarly as in the op-overload case - if the argument is that lifting the restriction would allow for confusing code (methods being available in one scope, but not another; or 'o.f()' doing different things in different scopes) then that's an argument for *removing UFCS* - as the same problems happen elsewhere too (think two modules each containing a different 'f(o)' function definition and several scopes that locally import just one of the modules). Things would be a bit different if D had a "global" scope, but that would also add new issues, and UFCS alone does not justify introducing one. (It wouldn't even help UFCS much, other than reducing the chances of clashing method names) artur
Oct 17 2012
parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Wednesday, 17 October 2012 at 10:24:57 UTC, Artur Skawina 
wrote:
 Operator overloading can be abused - that's an obvious and well 
 known fact. But that
 same feature can also be very useful, if used right. Worrying 
 about UFCS problems in
 the context of op-overloading needlessly complicates the issue 
 - the UFCS problems are
 there also w/o op-overloads.
 ...
 <skipped>
 artur
I don't see how this addresses the issue I try to put attention to. The discussion it turning into repetition of views.
Oct 17 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/16/2012 05:57 PM, Maxim Fomin wrote:
 ...

 At NG discussion it may look nice to define some type and then add
 operator overloading methods
Operator overloading is not magic, so your statement can be shortened to ... and then add methods Which is still not correct, because that is not what UFCS does.
 but as soon as you import some other
 modules, authors of which also consider UFCS operators a good idea,
Who has stated that? It just does not make sense to explicitly ban them, as they are not special.
 everything breaks including namespace conflict
The usual disambiguation procedures apply. (Which are broken in DMD at the moment, because module-scope private symbols can cause conflicts.) Infix operators are not special. It is just notation.
 as well as loosing
 ability to manipulate that type within built-in expression as well.
I did not get that.
Oct 17 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Wednesday, 17 October 2012 at 11:00:05 UTC, Timon Gehr wrote:
 On 10/16/2012 05:57 PM, Maxim Fomin wrote:
 ...

 At NG discussion it may look nice to define some type and then 
 add
 operator overloading methods
Operator overloading is not magic, so your statement can be shortened to ... and then add methods Which is still not correct, because that is not what UFCS does.
It is not correct as long as you cavil at lexis, however the statement has room for correction.
 but as soon as you import some other
 modules, authors of which also consider UFCS operators a good 
 idea,
Who has stated that? It just does not make sense to explicitly ban them, as they are not special.
Who stated that they should be "explicitly banned"? I explained potential problem in previous posts.
 everything breaks including namespace conflict
The usual disambiguation procedures apply. (Which are broken in DMD at the moment, because module-scope private symbols can cause conflicts.) Infix operators are not special. It is just notation.
 as well as loosing
 ability to manipulate that type within built-in expression as 
 well.
I did not get that.
Again, the problem is in conflict between different declared operator overloading functions across different modules.
Oct 17 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/17/2012 01:32 PM, Maxim Fomin wrote:
 On Wednesday, 17 October 2012 at 11:00:05 UTC, Timon Gehr wrote:
 On 10/16/2012 05:57 PM, Maxim Fomin wrote:
 ...

 At NG discussion it may look nice to define some type and then add
 operator overloading methods
Operator overloading is not magic, so your statement can be shortened to ... and then add methods Which is still not correct, because that is not what UFCS does.
It is not correct as long as you cavil at lexis, however the statement has room for correction.
In a discussion it is crucial that both parties agree on a common set of terms and definitions. Otherwise agreement cannot be detected.
 but as soon as you import some other
 modules, authors of which also consider UFCS operators a good idea,
Who has stated that? It just does not make sense to explicitly ban them, as they are not special.
Who stated that they should be "explicitly banned"?
Well, you did, if I got that right: On 10/13/2012 06:02 PM, Maxim Fomin wrote:
 From my point of view operator overloading methods are special functions
 and not treating them as candidates for UFCS does make more sense.
(Explicitly banning UFCS operators is the same thing as not treating rewritten operators as candidates for UFCS.)
 I explained potential problem in previous posts.
Yes, several times, but to me the argument still looks similar to the following (note that only the 'counter argument' part is related to this discussion): Issue: the 'body' keyword is not used enough to warrant keyword status, parsing could succeed without making it a full keyword. Proposed solution: make 'body' a valid identifier that is only recognised as special where it is expected to occur. Main counter argument: Two people might define a symbol using the newly available 'body' identifier, which can cause symbol conflicts. Do you agree with this reasoning, and if not, what is the fundamental difference between this and the point you are trying to convey?
 everything breaks including namespace conflict
The usual disambiguation procedures apply. (Which are broken in DMD at the moment, because module-scope private symbols can cause conflicts.) Infix operators are not special. It is just notation.
 as well as loosing
 ability to manipulate that type within built-in expression as well.
I did not get that.
Again, the problem is in conflict between different declared operator overloading functions across different modules.
Can you explain the usage of the term 'built-in' in this context?
Oct 17 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/15/2012 01:00 PM, Artur Skawina wrote:
 ...

 An overloaded operator is just another normal method; you get the same type of
 problems when dealing with "normal" methods - eg in types having an "alias
this" -
   an UFCS "method" must take precedence over one reachable via the alias -
just like
 in the overloaded op case. The only sane alternative would be disallowing UFCS
 for types with an "alias this" (which would be a severe limitation).
 ...
Just no. Why make symbol lookup even more complicated just in order to add an strange exception to the language that either enables new forms of hijacking or would be a severe limitation?
Oct 17 2012
parent Artur Skawina <art.08.09 gmail.com> writes:
On 10/17/12 12:46, Timon Gehr wrote:
 On 10/15/2012 01:00 PM, Artur Skawina wrote:
 ...

 An overloaded operator is just another normal method; you get the same type of
 problems when dealing with "normal" methods - eg in types having an "alias
this" -
   an UFCS "method" must take precedence over one reachable via the alias -
just like
 in the overloaded op case. The only sane alternative would be disallowing UFCS
 for types with an "alias this" (which would be a severe limitation).
 ...
Just no. Why make symbol lookup even more complicated just in order to add an strange exception to the language that either enables new forms of hijacking or would be a severe limitation?
Like i said in a later message - I think the /functionality/ should be available, how it's handled is a different issue. The reason why I'd want UFCS take priority over alias-this is that in the presence of multiple aliases and external components method hijacking is actually likely to become a problem. Eg a newer /library/ version can silently hijack an apps UFCS extension "method". Plus, the aliases can severely limit the available ufcs namespace; and the compiler won't even flag many conflicts as errors. UFCS is a much cheaper alternative to sub-typing, having it work for as many cases as possible is important. Think: app that uses an own GUI module on top of a themeing library on top of a GUI widget toolkit on top of a basic windowing system. Being able to extend functionality (by adding just a method or two, in the app) without having to create an extra type hierarchy and dealing with all the conversion issues could be very useful. UFCS is just optional syntax sugar, so I can buy the 'no changes for this' argument - only then I fear that it's usefulness decreases to the point where the cost is no longer justified. For the cases where creating a new type is overkill, one can always use a free function. [Yeah, I'm ignoring the 'functional-style' aspect, I know. UFCS might help there, but a DSL would be better long-term solution IMHO, and would also avoid the property related issues (extra parens). But that's off-topic, at least in this thread.] artur
Oct 17 2012
prev sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 13 October 2012 at 17:01:27 UTC, Tommi wrote:
 Another way to describe my reasoning...

 According to TDPL, if var is a variable of a user-defined type, 
 then:
 ++var
 gets rewritten as:
 var.opUnary!"++"()
Not always. If user-defined type has an alias this to integer member, than something different would happen. It would be also interesting to see, how operation ++T would differ because somebody imported module with opUnary method. Because opUnary suits better than alias this, dmd will issue call to that function, it it see its declaration.
Oct 13 2012
parent reply "Tommi" <tommitissari hotmail.com> writes:
On Sunday, 14 October 2012 at 06:22:03 UTC, Maxim Fomin wrote:
 On Saturday, 13 October 2012 at 17:01:27 UTC, Tommi wrote:
 Another way to describe my reasoning...

 According to TDPL, if var is a variable of a user-defined 
 type, then:
 ++var
 gets rewritten as:
 var.opUnary!"++"()
Not always. If user-defined type has an alias this to integer member, than something different would happen.
Yeah, I wasn't specific enough with that example.
 It would be also interesting to see, how operation ++T would 
 differ because somebody imported module with opUnary method. 
 Because opUnary suits better than alias this, dmd will issue 
 call to that function, it it see its declaration.
Actually, it seems that alias this has precedence over UFCS. So, a free function opUnary wouldn't ever suit better than an actual method opUnary of the thing referred to by that alias this.
Oct 14 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Sunday, 14 October 2012 at 07:01:30 UTC, Tommi wrote:
 Actually, it seems that alias this has precedence over UFCS. 
 So, a free function opUnary wouldn't ever suit better than an 
 actual method opUnary of the thing referred to by that alias 
 this.
http://dpaste.dzfl.pl/d0a4431d Free function doesn't suit better than actual method. The issue is absence of the actual method. opUnary method has priority over alias this, which does make sense because alias this is chosen only when it is impossible to apply operation over A type. If this request is approved and compiler has opUnary definition outside type (which suits better then alias this) such function would hijack alias this. If not, there is a new case when something is going special than at usual cases and only for the purpose of writing operator overloading methods outside the body of the type.
Oct 14 2012
next sibling parent reply "Tommi" <tommitissari hotmail.com> writes:
On Sunday, 14 October 2012 at 07:14:25 UTC, Maxim Fomin wrote:
 If this request is approved and compiler has opUnary definition 
 outside type (which suits better then alias
 this) such function would hijack alias this.
Free functions cannot and must not ever hijack, i.e. modify existing functionality of a type. Free functions should only be able to add new functionality to a type. This is what currently happens with alias this vs free function which is accessed through UFCS: struct B { void fun() { writeln("B.fun()"); } } struct A { B b; alias b this; } void fun(A a) { writeln(".fun(A)"); } void main() { A a; a.fun(); // prints B.fun() as it should } It shouldn't be any different if fun was some operator function, like opUnary; the free function mustn't hijack type A's existing functionality (which is currently being provided to A by that alias this thingy).
Oct 14 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Sunday, 14 October 2012 at 20:15:15 UTC, Tommi wrote:
 On Sunday, 14 October 2012 at 07:14:25 UTC, Maxim Fomin wrote:
 If this request is approved and compiler has opUnary 
 definition outside type (which suits better then alias
 this) such function would hijack alias this.
Free functions cannot and must not ever hijack, i.e. modify existing functionality of a type. Free functions should only be able to add new functionality to a type. This is what currently happens with alias this vs free function which is accessed through UFCS:
<snip> This shows current behavior. The issue is future behavior of code like this: ---foo.d--- struct A { int i; alias i this; } ---bar.d--- int opUnary(string T)(A a) { ... } ... { ++a; } ----------- I. i is incremented, opUnary is not called. However opUnary matches better to the actual type and if it were a method, it would be called - another special issue in the language which breaks usual logic. And if you declared opUnary in bar.d when alias this was absent in foo.d and later added - hijacking also occurs but now it happens from another side. Bad. II. opUnary is called, i is not incremented. On the one hand you get what you wanted - you supplied opUnary and it is called. At least this is consistent with matching behavior. On the other hand, it is hijacking from position of foo. Bad. III. Compiler issues error if you try to define some free functions which are similar to existing methods (code above is particular case) or if you declare operator overloading methods in the presence of alias this. This prevents from making confusion but if you link to some library, update code and its author defines new method, which is similar to your UFCS function, you get errors and have to rewrite code. IV. Do nothing and leave things as they are. Presence of opUnary function doesn't affect operator overloading. While current UFCS behavior falls in the first category (newly created foo.d methods hijack bar's free functions) there are no such problems with operator overloading methods. And operator overloading requires methods, not just free functions. Although methods and free functions may be called similar in source code, they still are different - in runtime calling, in mangling, in requiring contract invocation, argument passing, etc.
Oct 15 2012
parent reply "Tommi" <tommitissari hotmail.com> writes:
On Monday, 15 October 2012 at 09:33:23 UTC, Maxim Fomin wrote:
 ---foo.d---
 struct A
 {
    int i;
    alias i this;
 }
 ---bar.d---
 int opUnary(string T)(A a) { ... }
 ...
 {
   ++a;
 }
 -----------
 I. i is incremented, opUnary is not called. However opUnary 
 matches better to the actual type and if it were a method, it 
 would be called - another special issue in the language which 
 breaks usual logic. And if you declared opUnary in bar.d when 
 alias this was absent in foo.d and later added - hijacking also 
 occurs but now it happens from another side. Bad.
Let's talk about the semantics of the word "hijacking" as it relates to this discussion. Here's my take on it: Let type T have some inherent functionality F. That is, functionality F cannot be removed from T without making changes to the module file where type T is defined. Then, if some other functionality F' overrides (replaces and modifies) F, it is said that F' "hijacks" F. If I apply this definition to your example, we see that the free function opUnary in bar.d is *not* part of struct A's inherent functionality. Therefore, by adding later that alias this in A's definition, we are *not* hijacking anything. Furthermore, if that free function opUnary was defined in foo.d instead, it would be an inherent part of A's functionality. Then, by adding later that alias this in A's definition, we would be *changing* A's functionality. But that's not hijacking, because we're making the change in the module file where A is defined. That's not hijacking, that's just changing the inherent functionality of your own user-defined type.
Oct 16 2012
parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Tuesday, 16 October 2012 at 16:10:31 UTC, Tommi wrote:
 On Monday, 15 October 2012 at 09:33:23 UTC, Maxim Fomin wrote:
 ---foo.d---
 struct A
 {
   int i;
   alias i this;
 }
 ---bar.d---
 int opUnary(string T)(A a) { ... }
 ...
 {
  ++a;
 }
 -----------
 I. i is incremented, opUnary is not called. However opUnary 
 matches better to the actual type and if it were a method, it 
 would be called - another special issue in the language which 
 breaks usual logic. And if you declared opUnary in bar.d when 
 alias this was absent in foo.d and later added - hijacking 
 also occurs but now it happens from another side. Bad.
Let's talk about the semantics of the word "hijacking" as it relates to this discussion. Here's my take on it: Let type T have some inherent functionality F. That is, functionality F cannot be removed from T without making changes to the module file where type T is defined. Then, if some other functionality F' overrides (replaces and modifies) F, it is said that F' "hijacks" F. If I apply this definition to your example, we see that the free function opUnary in bar.d is *not* part of struct A's inherent functionality. Therefore, by adding later that alias this in A's definition, we are *not* hijacking anything. Furthermore, if that free function opUnary was defined in foo.d instead, it would be an inherent part of A's functionality. Then, by adding later that alias this in A's definition, we would be *changing* A's functionality. But that's not hijacking, because we're making the change in the module file where A is defined. That's not hijacking, that's just changing the inherent functionality of your own user-defined type.
Or simpler: hijack is when some code is written and under new circumstances the same code does different things. Hijack happens if there are two conflict entities and one of them has higher priority than another. In case of UFCS depending on design two types of hijacks may happen: - either newly created free UFCS function hijacks existing method - or newly created method hijacks existing free function. Currently D is designed in favor for blocking first type which doesn't mean that it stops author of some type from declaring new methods and breaking (hijacking) free functions.
Oct 16 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/14/2012 09:14 AM, Maxim Fomin wrote:
 On Sunday, 14 October 2012 at 07:01:30 UTC, Tommi wrote:
 Actually, it seems that alias this has precedence over UFCS. So, a
 free function opUnary wouldn't ever suit better than an actual method
 opUnary of the thing referred to by that alias this.
http://dpaste.dzfl.pl/d0a4431d Free function doesn't suit better than actual method. The issue is absence of the actual method. opUnary method has priority over alias this, which does make sense because alias this is chosen only when it is impossible to apply operation over A type. If this request is approved and compiler has opUnary definition outside type (which suits better then alias this) such function would hijack alias this. If not, there is a new case when something is going special than at usual cases and only for the purpose of writing operator overloading methods outside the body of the type.
The goal must be to get rid of all special behaviour that can result in strange interactions. Add the suitable operator function templates to built-in types. Always rewrite operators to operator function calls. Problem solved. (And people are already asking for custom constant folding procedures, even without having this in place to use as a supporting argument.)
Oct 17 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Wednesday, 17 October 2012 at 11:11:26 UTC, Timon Gehr wrote:
 On 10/14/2012 09:14 AM, Maxim Fomin wrote:
 On Sunday, 14 October 2012 at 07:01:30 UTC, Tommi wrote:
 Actually, it seems that alias this has precedence over UFCS. 
 So, a
 free function opUnary wouldn't ever suit better than an 
 actual method
 opUnary of the thing referred to by that alias this.
http://dpaste.dzfl.pl/d0a4431d Free function doesn't suit better than actual method. The issue is absence of the actual method. opUnary method has priority over alias this, which does make sense because alias this is chosen only when it is impossible to apply operation over A type. If this request is approved and compiler has opUnary definition outside type (which suits better then alias this) such function would hijack alias this. If not, there is a new case when something is going special than at usual cases and only for the purpose of writing operator overloading methods outside the body of the type.
The goal must be to get rid of all special behaviour that can result in strange interactions. Add the suitable operator function templates to built-in types. Always rewrite operators to operator function calls. Problem solved. ...
You have a struct with alias this to int without overloaded operators. It (say, struct.d) contains code with structure increments. Some other module (say bob.d), which import the structure, defines function supposed to overload opUnary. If operators are always rewritten to function calls, now function should be called in module bob.d, as well as in struct.d if they are compiled together. It certainly not what author of struct.d expected. The case can be even more interesting, if alias this in struct.d were absent at a time when bob.d was written and at some point of future Bob is updating his sources.
Oct 17 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/17/2012 01:51 PM, Maxim Fomin wrote:
 On Wednesday, 17 October 2012 at 11:11:26 UTC, Timon Gehr wrote:
 On 10/14/2012 09:14 AM, Maxim Fomin wrote:
 On Sunday, 14 October 2012 at 07:01:30 UTC, Tommi wrote:
 Actually, it seems that alias this has precedence over UFCS. So, a
 free function opUnary wouldn't ever suit better than an actual method
 opUnary of the thing referred to by that alias this.
http://dpaste.dzfl.pl/d0a4431d Free function doesn't suit better than actual method. The issue is absence of the actual method. opUnary method has priority over alias this, which does make sense because alias this is chosen only when it is impossible to apply operation over A type. If this request is approved and compiler has opUnary definition outside type (which suits better then alias this) such function would hijack alias this. If not, there is a new case when something is going special than at usual cases and only for the purpose of writing operator overloading methods outside the body of the type.
The goal must be to get rid of all special behaviour that can result in strange interactions. Add the suitable operator function templates to built-in types. Always rewrite operators to operator function calls. Problem solved. ...
You have a struct with alias this to int without overloaded operators. It (say, struct.d) contains code with structure increments. Some other module (say bob.d), which import the structure, defines function supposed to overload opUnary. If operators are always rewritten to function calls, now function should be called in module bob.d, as well as in struct.d if they are compiled together. It certainly not what author of struct.d expected. The case can be even more interesting, if alias this in struct.d were absent at a time when bob.d was written and at some point of future Bob is updating his sources.
Members do not cause conflicts with free functions. Alias this takes precedence as it is a member of the type. What is the issue?
Oct 17 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/13/2012 06:02 PM, Maxim Fomin wrote:
 ...
 Different groups of people have different mind and same things produce
 different sense on them. From my point of view operator overloading
 methods are special functions and not treating them as candidates for
 UFCS does make more sense.
I do not understand how an operation that happens to be called '+' is fundamentally different from an operation that is called 'add'.
 Even if you convince in your opinion,
 language addition without applied purposes makes no benefit.
I guess the functionality could be achieved in DMD mostly by removing code. (Code for good error messages excluded!)
Oct 13 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 13 October 2012 at 19:50:02 UTC, Timon Gehr wrote:
 On 10/13/2012 06:02 PM, Maxim Fomin wrote:
 ...
 Different groups of people have different mind and same things 
 produce
 different sense on them. From my point of view operator 
 overloading
 methods are special functions and not treating them as 
 candidates for
 UFCS does make more sense.
I do not understand how an operation that happens to be called '+' is fundamentally different from an operation that is called 'add'.
The first one is an operator, which sometimes, may be rewritten to function call, the second one is a function call.
 Even if you convince in your opinion,
 language addition without applied purposes makes no benefit.
I guess the functionality could be achieved in DMD mostly by removing code. (Code for good error messages excluded!)
I don't understand what you are trying to say. Anyway, you can write a pull request and propose it at github. It would be interesting to see reaction of others.
Oct 14 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/14/2012 09:01 AM, Maxim Fomin wrote:
 On Saturday, 13 October 2012 at 19:50:02 UTC, Timon Gehr wrote:
 On 10/13/2012 06:02 PM, Maxim Fomin wrote:
 ...
 Different groups of people have different mind and same things produce
 different sense on them. From my point of view operator overloading
 methods are special functions and not treating them as candidates for
 UFCS does make more sense.
I do not understand how an operation that happens to be called '+' is fundamentally different from an operation that is called 'add'.
The first one is an operator, which sometimes, may be rewritten to function call, the second one is a function call.
What is the difference between an operator and a function call? Is it important? int add(int a, int b){ return a+b; } // or conversely (not valid syntax): int (int a)+(int b){ return add(a,b); }
 Even if you convince in your opinion,
 language addition without applied purposes makes no benefit.
I guess the functionality could be achieved in DMD mostly by removing code. (Code for good error messages excluded!)
I don't understand what you are trying to say. Anyway, you can write a pull request and propose it at github. It would be interesting to see reaction of others.
Built-in types shouldn't be special except maybe that the parser recognises related keywords. It should go like this: a + b => a.opBinary!"+"(b); // opBinary_r woes left out, // but would require treatment a + b => __add(a,b); // if a and b of built-in type a.opBinary!"+"(b) => __add(a,b); // if a and b of built-in type Where __add(a,b) is the representation of an AST node of a built-in add operation involving operands a and b. All the code in DMD that supposedly tries to make up for this kind of inconsistencies (and sometimes fails, because it does not catch all the ways the language features interact) can be gotten rid of.
Oct 17 2012