October 16, 2012
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.
October 17, 2012
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
October 17, 2012
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?
October 17, 2012
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.
October 17, 2012
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.)
October 17, 2012
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.

October 17, 2012
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.

October 17, 2012
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.
October 17, 2012
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.
October 17, 2012
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?