Re: Operator overloading through UFCS doesn't work

2016-05-31 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: Operator overloading through UFCS doesn't work

2016-05-31 Thread ixid via Digitalmars-d-learn

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


Re: Operator overloading through UFCS doesn't work

2016-05-30 Thread pineapple via Digitalmars-d-learn
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.




Re: Operator overloading through UFCS doesn't work

2016-05-30 Thread Marc Schütz via Digitalmars-d-learn

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...


Re: Operator overloading through UFCS doesn't work

2016-05-29 Thread Jonathan M Davis via Digitalmars-d-learn
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. 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.

- Jonathan M Davis




Re: Operator overloading through UFCS doesn't work

2016-05-27 Thread Marc Schütz via Digitalmars-d-learn

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.


Re: Operator overloading through UFCS doesn't work

2016-05-26 Thread Timon Gehr via Digitalmars-d-learn

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.)


Re: Operator overloading through UFCS doesn't work

2016-05-26 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: Operator overloading through UFCS doesn't work

2016-05-26 Thread Elie Morisse via Digitalmars-d-learn

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.


Re: Operator overloading through UFCS doesn't work

2016-05-26 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: Operator overloading through UFCS doesn't work

2016-05-25 Thread Elie Morisse via Digitalmars-d-learn

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)?


Re: Operator overloading through UFCS doesn't work

2016-05-25 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: Operator overloading through UFCS doesn't work

2016-05-25 Thread Elie Morisse via Digitalmars-d-learn

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?


Re: Operator overloading through UFCS doesn't work

2016-05-24 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: Operator overloading through UFCS doesn't work

2016-05-24 Thread Elie Morisse via Digitalmars-d-learn

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.


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

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.


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

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.)


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Maxim Fomin
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.




Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

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.



Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Artur Skawina
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


Re: Operator overloading through UFCS doesn't work

2012-10-16 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-16 Thread Tommi

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.


Re: Operator overloading through UFCS doesn't work

2012-10-16 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-15 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-15 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-15 Thread Artur Skawina
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


Re: Operator overloading through UFCS doesn't work

2012-10-15 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-15 Thread Artur Skawina
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


Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Maxim Fomin

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.




Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Tommi

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.


Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Artur Skawina
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


Re: Operator overloading through UFCS doesn't work

2012-10-14 Thread Tommi

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).


Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi
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?


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Jakob Ovrum

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.




Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Jonathan M Davis
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’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.

Yes. It is most definitely illegal to overload any operators as free functions. 
They're _always_ member variables of the type that they operate on.

- Jonathan M Davis


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi

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);


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Jonathan M Davis
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.
 
 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);

Just because the overloaded operator is rewritten into a method call 
underneath the hood doesn't mean that the UFCS rewrite also applies. The 
transformation of an operator to a method or a UFCS call to a free function is 
done _once_. You don't get both. It is most definitely _by design_ that you 
cannot overload operators except as member functions. If TDPL says otherwise, 
it's either because you're misunderstanding what it's saying or because it's 
wrong.

- Jonathan M Davis


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi
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.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Maxim Fomin

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?


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi

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.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Maxim Fomin

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.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi

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)


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Tommi

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.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Timon Gehr

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!)


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Jonathan M Davis
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(vectorint::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 

Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Timon Gehr

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.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread H. S. Teoh
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


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Timon Gehr

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.