View mode: basic / threaded / horizontal-split · Log in · Help
December 27, 2008
Re: Operator overloading
aarti_pl wrote:
> Andrei Alexandrescu pisze:
>  > We're trying to make that work. D is due for an operator overhaul.
>  >
>  > Andrei
> 
> Is there any chance that we get possibility to overload "raw operators", 
> like in C++? I think that they may coexist with currently defined 
> operator overloads with simple semantic rules, which will not allow them 
> to work together at the same time.
> ..........
> BR
> Marcin Kuszczak
> (aarti_pl)

Me also have a dream :D

<Daydream mode>
class Foo
{
	auto op(++)(); // bar++
	auto op(++)(int); // ++bar

	op(cast)(uint); // cast(uint)bar // opCast
	auto op(())(int, float); // Foo(123, 123.456) // opCall
	
	auto op(+)(Foo rhs); // bar1 + bar2
	auto op(+=)(int); // bar += 1234;
	auto op(.)(); // bar.xyz // opDot

	Foo op([][][])(int, char, float); // bar[123]['x'][123.456]

	auto op([..])(); // i = bar2[] // opSlide
	auto op([..])(int, int); // bar[1..10]

	auto op([..]=)(float); // bar[] = 12.3 //opSlideAssign
	auto op([..]=)(int, int, float); // bar[1..3] = 123.4
}
</Dream>
December 27, 2008
Re: Operator overloading
On Sat, Dec 27, 2008 at 9:42 AM, The Anh Tran <trtheanh@gmail.com> wrote:
> aarti_pl wrote:
>>
>> Andrei Alexandrescu pisze:
>>  > We're trying to make that work. D is due for an operator overhaul.
>>  >
>>  > Andrei
>>
>> Is there any chance that we get possibility to overload "raw operators",
>> like in C++? I think that they may coexist with currently defined operator
>> overloads with simple semantic rules, which will not allow them to work
>> together at the same time.
>> ..........
>> BR
>> Marcin Kuszczak
>> (aarti_pl)
>
> Me also have a dream :D
>
> <Daydream mode>
> class Foo
> {
>        auto op(++)(); // bar++
>        auto op(++)(int); // ++bar
>
>        op(cast)(uint); // cast(uint)bar // opCast
>        auto op(())(int, float); // Foo(123, 123.456) // opCall
>
>        auto op(+)(Foo rhs); // bar1 + bar2
>        auto op(+=)(int); // bar += 1234;
>        auto op(.)(); // bar.xyz // opDot
>
>        Foo op([][][])(int, char, float); // bar[123]['x'][123.456]
>
>        auto op([..])(); // i = bar2[] // opSlide
>        auto op([..])(int, int); // bar[1..10]
>
>        auto op([..]=)(float); // bar[] = 12.3 //opSlideAssign
>        auto op([..]=)(int, int, float); // bar[1..3] = 123.4
> }
> </Dream>

When I suggested this kind of thing long ago, Walter said that it
encourages operator overload abuse, because it suggests that  + is
just a generic symbolic operator rather than something that
specifically means "addition".  That's why D uses "opAdd" instead.
It's supposed to encourage only creating overloads that follow the
original meaning of the operator closely.  That way when you see a+b
you can be reasonably sure that it means addition or something quite
like it.  It also goes hand-in-hand with design decisions like
defining ++x to be x+=1, which means that in D it's impossible to make
++x mean something distinct from incrementing by 1.  With C++ you can
make ++x have whatever meaning you want.  It can do something
completely different from x+=1.  The idea is that such freedom just
makes code harder to read.

Currently I don't think it makes much difference either way.  The only
real advantage I see to the alternate syntax is that it can be perhaps
a little easier to remember.  But I also I don't think Walter's idea
about naming following usage does anything to stop someone like Downs
from using opDiv to do something completely different from division.
It probably never even occurred to Downs that Walter was trying to
prevent him from abusing opDiv by naming it opDiv instead of
operator(/).  The people who are likely to abuse operators are
precisely those who aren't likely to be daunted by mere naming.

But anyway, just so you know, that's why D does things the way it
does.  So that means to see your dream come true you first have to
convince Walter that it's a dream worth having. :-)

--bb
December 27, 2008
Re: Operator overloading
The Anh Tran wrote:
> aarti_pl wrote:
>> Andrei Alexandrescu pisze:
>>  > We're trying to make that work. D is due for an operator overhaul.
>>  >
>>  > Andrei
>>
>> Is there any chance that we get possibility to overload "raw 
>> operators", like in C++? I think that they may coexist with currently 
>> defined operator overloads with simple semantic rules, which will not 
>> allow them to work together at the same time.
>> ..........
>> BR
>> Marcin Kuszczak
>> (aarti_pl)
> 
> Me also have a dream :D
> 
> <Daydream mode>
> class Foo
> {
>     auto op(++)(); // bar++
>     auto op(++)(int); // ++bar

Hey, wasn't the implementation of the postincrement operator through an 
overload a rather untasty hack?

>     op(cast)(uint); // cast(uint)bar // opCast
>     auto op(())(int, float); // Foo(123, 123.456) // opCall
>     
>     auto op(+)(Foo rhs); // bar1 + bar2
>     auto op(+=)(int); // bar += 1234;
>     auto op(.)(); // bar.xyz // opDot
> 
>     Foo op([][][])(int, char, float); // bar[123]['x'][123.456]
> 
>     auto op([..])(); // i = bar2[] // opSlide
>     auto op([..])(int, int); // bar[1..10]
> 
>     auto op([..]=)(float); // bar[] = 12.3 //opSlideAssign
>     auto op([..]=)(int, int, float); // bar[1..3] = 123.4
> }
> </Dream>

Aside for a minor change in notation, there's no improvement. We're 
looking for much more broad improvements, such as offering the ability 
to overload several operators with only one function.

Andrei
December 27, 2008
Re: Operator overloading
Bill Baxter wrote:
> On Sat, Dec 27, 2008 at 9:42 AM, The Anh Tran <trtheanh@gmail.com> wrote:
>> aarti_pl wrote:
>>> Andrei Alexandrescu pisze:
>>>  > We're trying to make that work. D is due for an operator overhaul.
>>>  >
>>>  > Andrei
>>>
>>> Is there any chance that we get possibility to overload "raw operators",
>>> like in C++? I think that they may coexist with currently defined operator
>>> overloads with simple semantic rules, which will not allow them to work
>>> together at the same time.
>>> ..........
>>> BR
>>> Marcin Kuszczak
>>> (aarti_pl)
>> Me also have a dream :D
>>
>> <Daydream mode>
>> class Foo
>> {
>>        auto op(++)(); // bar++
>>        auto op(++)(int); // ++bar
>>
>>        op(cast)(uint); // cast(uint)bar // opCast
>>        auto op(())(int, float); // Foo(123, 123.456) // opCall
>>
>>        auto op(+)(Foo rhs); // bar1 + bar2
>>        auto op(+=)(int); // bar += 1234;
>>        auto op(.)(); // bar.xyz // opDot
>>
>>        Foo op([][][])(int, char, float); // bar[123]['x'][123.456]
>>
>>        auto op([..])(); // i = bar2[] // opSlide
>>        auto op([..])(int, int); // bar[1..10]
>>
>>        auto op([..]=)(float); // bar[] = 12.3 //opSlideAssign
>>        auto op([..]=)(int, int, float); // bar[1..3] = 123.4
>> }
>> </Dream>
> 
> When I suggested this kind of thing long ago, Walter said that it
> encourages operator overload abuse, because it suggests that  + is
> just a generic symbolic operator rather than something that
> specifically means "addition".  That's why D uses "opAdd" instead.
> It's supposed to encourage only creating overloads that follow the
> original meaning of the operator closely.  That way when you see a+b
> you can be reasonably sure that it means addition or something quite
> like it.

I think that argument is rather weak and ought to be revisited. It's 
weak to start with as if writing "+" in a D program hardly evokes 
anything else but "plus". What the notation effectively achieved was put 
more burden on the programmer to memorize some names for the 
already-known symbols. I think the entire operator overloading business, 
which started from a legitimate desire to improve on C++'s, ended up 
worse off.

> It also goes hand-in-hand with design decisions like
> defining ++x to be x+=1, which means that in D it's impossible to make
> ++x mean something distinct from incrementing by 1.

This is the vomit in the fat lady's cleavage that shows just how bad the 
wine turned out to be. For iterators, increment is quite different from 
addition of an arbitrary number, so what D managed to do was effectively 
to cripple iterators. The standard library will use ranges with named 
functions so it avoids the issue, but if someone wants to define 
STL-style iterators they won't be able to.

> With C++ you can
> make ++x have whatever meaning you want.  It can do something
> completely different from x+=1.  The idea is that such freedom just
> makes code harder to read.

That sounds nice, but on the face of it I haven't heard of much code 
suffering from the problem.

> Currently I don't think it makes much difference either way.  The only
> real advantage I see to the alternate syntax is that it can be perhaps
> a little easier to remember.  But I also I don't think Walter's idea
> about naming following usage does anything to stop someone like Downs
> from using opDiv to do something completely different from division.
> It probably never even occurred to Downs that Walter was trying to
> prevent him from abusing opDiv by naming it opDiv instead of
> operator(/).  The people who are likely to abuse operators are
> precisely those who aren't likely to be daunted by mere naming.
> 
> But anyway, just so you know, that's why D does things the way it
> does.  So that means to see your dream come true you first have to
> convince Walter that it's a dream worth having. :-)

The story is quite lame, so it may be worth scrutinizing it. Let's make 
D operators not suck. Wanna?


Andrei
December 27, 2008
Re: Operator overloading
On Fri, Dec 26, 2008 at 11:20 PM, Andrei Alexandrescu
<SeeWebsiteForEmail@erdani.org> wrote:
> I think that argument is rather weak and ought to be revisited. It's weak to
> start with as if writing "+" in a D program hardly evokes anything else but
> "plus". What the notation effectively achieved was put more burden on the
> programmer to memorize some names for the already-known symbols. I think the
> entire operator overloading business, which started from a legitimate desire
> to improve on C++'s, ended up worse off.

It does, however, introduce a nice naming scheme for naming
"meta-methods", that is, methods which are called indirectly to
overload certain language structures.  opApply is an example of such a
method which doesn't truly have a corresponding operator, and I'm sure
there could be other other methods for other language constructs,
existing or theoretical.  (though I'm sure you'll agree opApply's
behavior could use a rehaul too)

> This is the vomit in the fat lady's cleavage that shows just how bad the
> wine turned out to be.

That has to be one of the most disgusting metaphors I've ever heard ;)

> For iterators, increment is quite different from
> addition of an arbitrary number, so what D managed to do was effectively to
> cripple iterators. The standard library will use ranges with named functions
> so it avoids the issue, but if someone wants to define STL-style iterators
> they won't be able to.

I suppose most people who _aren't_ coming from C++ (*cough* like me
*cough*) won't be terribly unhappy about this situation.
December 27, 2008
Re: Operator overloading
Jarrett Billingsley wrote:
> On Fri, Dec 26, 2008 at 11:20 PM, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>> I think that argument is rather weak and ought to be revisited. It's weak to
>> start with as if writing "+" in a D program hardly evokes anything else but
>> "plus". What the notation effectively achieved was put more burden on the
>> programmer to memorize some names for the already-known symbols. I think the
>> entire operator overloading business, which started from a legitimate desire
>> to improve on C++'s, ended up worse off.
> 
> It does, however, introduce a nice naming scheme for naming
> "meta-methods", that is, methods which are called indirectly to
> overload certain language structures.  opApply is an example of such a
> method which doesn't truly have a corresponding operator, and I'm sure
> there could be other other methods for other language constructs,
> existing or theoretical.  (though I'm sure you'll agree opApply's
> behavior could use a rehaul too)
> 
>> This is the vomit in the fat lady's cleavage that shows just how bad the
>> wine turned out to be.
> 
> That has to be one of the most disgusting metaphors I've ever heard ;)
> 
>> For iterators, increment is quite different from
>> addition of an arbitrary number, so what D managed to do was effectively to
>> cripple iterators. The standard library will use ranges with named functions
>> so it avoids the issue, but if someone wants to define STL-style iterators
>> they won't be able to.
> 
> I suppose most people who _aren't_ coming from C++ (*cough* like me
> *cough*) won't be terribly unhappy about this situation.

I'm not sure how that computes. The particular notion has little to do 
with C++ and is rather fundamental, so not grokking it should motivate 
one to look into it (as opposed to being glad for not knowing).

Andrei
December 27, 2008
Re: Operator overloading
Andrei Alexandrescu wrote:
> Bill Baxter wrote:
>> On Sat, Dec 27, 2008 at 9:42 AM, The Anh Tran <trtheanh@gmail.com> wrote:
>>> aarti_pl wrote:
>>>> Andrei Alexandrescu pisze:
>>>>  > We're trying to make that work. D is due for an operator overhaul.
>>>>  >
>>>>  > Andrei
>>>>
>>>> Is there any chance that we get possibility to overload "raw 
>>>> operators",
>>>> like in C++? I think that they may coexist with currently defined 
>>>> operator
>>>> overloads with simple semantic rules, which will not allow them to work
>>>> together at the same time.
>>>> ..........
>>>> BR
>>>> Marcin Kuszczak
>>>> (aarti_pl)
>>> Me also have a dream :D
>>>
>>> <Daydream mode>
>>> class Foo
>>> {
>>>        auto op(++)(); // bar++
>>>        auto op(++)(int); // ++bar
>>>
>>>        op(cast)(uint); // cast(uint)bar // opCast
>>>        auto op(())(int, float); // Foo(123, 123.456) // opCall
>>>
>>>        auto op(+)(Foo rhs); // bar1 + bar2
>>>        auto op(+=)(int); // bar += 1234;
>>>        auto op(.)(); // bar.xyz // opDot
>>>
>>>        Foo op([][][])(int, char, float); // bar[123]['x'][123.456]
>>>
>>>        auto op([..])(); // i = bar2[] // opSlide
>>>        auto op([..])(int, int); // bar[1..10]
>>>
>>>        auto op([..]=)(float); // bar[] = 12.3 //opSlideAssign
>>>        auto op([..]=)(int, int, float); // bar[1..3] = 123.4
>>> }
>>> </Dream>
>>
>> When I suggested this kind of thing long ago, Walter said that it
>> encourages operator overload abuse, because it suggests that  + is
>> just a generic symbolic operator rather than something that
>> specifically means "addition".  That's why D uses "opAdd" instead.
>> It's supposed to encourage only creating overloads that follow the
>> original meaning of the operator closely.  That way when you see a+b
>> you can be reasonably sure that it means addition or something quite
>> like it.
> 
> I think that argument is rather weak and ought to be revisited. It's 
> weak to start with as if writing "+" in a D program hardly evokes 
> anything else but "plus". What the notation effectively achieved was put 
> more burden on the programmer to memorize some names for the 
> already-known symbols. I think the entire operator overloading business, 
> which started from a legitimate desire to improve on C++'s, ended up 
> worse off.

I feel quite strongly that C++'s operator overloading was a failed 
experiment. The original intention (AFAIK) was to allow creation of 
mathematical entities which could use natural syntax. The classic 
example was complex numbers, and it works reasonably well for that, 
although it requires you to create an absurd number of repetitive functions.

But for anything much more complicated, such as matrices, tensors, big 
integer arithmetic, etc -- it's an abject failure. It's clumsy, and 
creates masses of temporary objects, which kills performance so 
completely that it's unusable. But the whole point of operator 
overloading was to allow nice notation in a performace-oriented 
language! Expression templates are basically a hack to restore 
performance in most cases, but it comes at a massive cost in simplicity.
And the performance even then is not always optimal.

I think that Walter's idea, in tightening the semantics of overloaded 
operators, is the right approach. Unfortunately, it doesn't go far 
enough, so we get the worst of both worlds: the C++ freedom is 
curtailed, but there isn't enough power to replace it.

Ultimately, I think that the problem is that ideally, '+' is not simply 
a call to a function called 'plus()'. What you'd like an operator to 
compile to, depends on the expression in which it is embedded. For 
maximum performance, an expression needs to be digested before it is 
converted into elementary functions.

In my 'operator overloading without temporaries' proposal in Bugzilla,
I showed that DEFINING a -= b as being identical to a = a - b, and then 
 creating a symmetric operation for a = b - a allows optimal code 
generation in a great many cases. It's not a complete solution, though.

In particular, irreducible temporaries need more thought. Ideally, in 
something like a += b * c + d, b*c would be created in a memory pool, 
and deleted at the end of the expression.
(By contrast, a = b*c+d, would translate to a=b*c; a+=d; so no temporary 
is required).

There are other, less serious problems which also need to be addressed.

Defining ++a as a+=1 is probably a mistake. It raises lots of nasty issues.
* If a is a complex number, a = a + 1 makes perfect sense. But it's not 
obvious that ++a is sensible.
* What type is '1'? Is it an int, a uint, a long, ... You don't have 
that issue with increment.

As I see it, there are two possible strategies:
(1) Pursuing optimal performance, which requires semantic tightening, 
and reduced flexibility, or
(2) Pursure simplicity and semantic flexibility, sacrificing performance.

I think those two possibilities are mutually exclusive.
December 27, 2008
Re: Operator overloading
On Sat, Dec 27, 2008 at 2:31 AM, Andrei Alexandrescu
<SeeWebsiteForEmail@erdani.org> wrote:
>>> For iterators, increment is quite different from
>>> addition of an arbitrary number, so what D managed to do was effectively
>>> to
>>> cripple iterators. The standard library will use ranges with named
>>> functions
>>> so it avoids the issue, but if someone wants to define STL-style
>>> iterators
>>> they won't be able to.
>>
>> I suppose most people who _aren't_ coming from C++ (*cough* like me
>> *cough*) won't be terribly unhappy about this situation.
>
> I'm not sure how that computes. The particular notion has little to do with
> C++ and is rather fundamental, so not grokking it should motivate one to
> look into it (as opposed to being glad for not knowing).

I got the impression from your argument that you thought that without
an appropriate method of overloading the increment operator, it's not
possible to duplicate the _syntax_ of STL-style iterators.  My
response is - who cares?  I don't think of iterators as "pointers that
can be incremented," and I doubt anyone who doesn't have a C++
background thinks of them that way either.  It seems that the
semantics of STL iterators can be implemented with methods just as
well.

If that's not what you were arguing - that is, if you're arguing that
C++'s operator overloading is somehow more expressive and allows you
to implement something that can't be implemented with method calls -
then I will put my foot in my mouth ;)
December 27, 2008
Re: Operator overloading
On Sat, Dec 27, 2008 at 11:19 PM, Jarrett Billingsley
<jarrett.billingsley@gmail.com> wrote:
> On Sat, Dec 27, 2008 at 2:31 AM, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>>>> For iterators, increment is quite different from
>>>> addition of an arbitrary number, so what D managed to do was effectively
>>>> to
>>>> cripple iterators. The standard library will use ranges with named
>>>> functions
>>>> so it avoids the issue, but if someone wants to define STL-style
>>>> iterators
>>>> they won't be able to.
>>>
>>> I suppose most people who _aren't_ coming from C++ (*cough* like me
>>> *cough*) won't be terribly unhappy about this situation.
>>
>> I'm not sure how that computes. The particular notion has little to do with
>> C++ and is rather fundamental, so not grokking it should motivate one to
>> look into it (as opposed to being glad for not knowing).
>
> I got the impression from your argument that you thought that without
> an appropriate method of overloading the increment operator, it's not
> possible to duplicate the _syntax_ of STL-style iterators.  My
> response is - who cares?  I don't think of iterators as "pointers that
> can be incremented," and I doubt anyone who doesn't have a C++
> background thinks of them that way either.  It seems that the
> semantics of STL iterators can be implemented with methods just as
> well.

There is a little something nice about being able to use a pointer and
iterator interchangeably for templated container algorithms.  You lose
that if ++iter can't be used to iterate your iterator.  But working
around it is not really that hard.  One little incr(T)(ref thing)
template and you're pretty much done.  But ++foo is a concise syntax
that conveys the meaning of what's happening pretty well, so it's a
shame not to be able to use it on iterators.
(Actually I don't really recall why it can't be used for iterators in
D other than it forces you to use more runtime errors for bad args to
+=.  Was there anything more to it than that?)

--bb
December 27, 2008
Re: Operator overloading
Don wrote:
> Andrei Alexandrescu wrote:
>> Bill Baxter wrote:
>>> On Sat, Dec 27, 2008 at 9:42 AM, The Anh Tran <trtheanh@gmail.com> 
>>> wrote:
>>>> aarti_pl wrote:
>>>>> Andrei Alexandrescu pisze:
>>>>>  > We're trying to make that work. D is due for an operator overhaul.
>>>>>  >
>>>>>  > Andrei
>>>>>
>>>>> Is there any chance that we get possibility to overload "raw 
>>>>> operators",
>>>>> like in C++? I think that they may coexist with currently defined 
>>>>> operator
>>>>> overloads with simple semantic rules, which will not allow them to 
>>>>> work
>>>>> together at the same time.
>>>>> ..........
>>>>> BR
>>>>> Marcin Kuszczak
>>>>> (aarti_pl)
>>>> Me also have a dream :D
>>>>
>>>> <Daydream mode>
>>>> class Foo
>>>> {
>>>>        auto op(++)(); // bar++
>>>>        auto op(++)(int); // ++bar
>>>>
>>>>        op(cast)(uint); // cast(uint)bar // opCast
>>>>        auto op(())(int, float); // Foo(123, 123.456) // opCall
>>>>
>>>>        auto op(+)(Foo rhs); // bar1 + bar2
>>>>        auto op(+=)(int); // bar += 1234;
>>>>        auto op(.)(); // bar.xyz // opDot
>>>>
>>>>        Foo op([][][])(int, char, float); // bar[123]['x'][123.456]
>>>>
>>>>        auto op([..])(); // i = bar2[] // opSlide
>>>>        auto op([..])(int, int); // bar[1..10]
>>>>
>>>>        auto op([..]=)(float); // bar[] = 12.3 //opSlideAssign
>>>>        auto op([..]=)(int, int, float); // bar[1..3] = 123.4
>>>> }
>>>> </Dream>
>>>
>>> When I suggested this kind of thing long ago, Walter said that it
>>> encourages operator overload abuse, because it suggests that  + is
>>> just a generic symbolic operator rather than something that
>>> specifically means "addition".  That's why D uses "opAdd" instead.
>>> It's supposed to encourage only creating overloads that follow the
>>> original meaning of the operator closely.  That way when you see a+b
>>> you can be reasonably sure that it means addition or something quite
>>> like it.
>>
>> I think that argument is rather weak and ought to be revisited. It's 
>> weak to start with as if writing "+" in a D program hardly evokes 
>> anything else but "plus". What the notation effectively achieved was 
>> put more burden on the programmer to memorize some names for the 
>> already-known symbols. I think the entire operator overloading 
>> business, which started from a legitimate desire to improve on C++'s, 
>> ended up worse off.
> 
> I feel quite strongly that C++'s operator overloading was a failed 
> experiment. The original intention (AFAIK) was to allow creation of 
> mathematical entities which could use natural syntax. The classic 
> example was complex numbers, and it works reasonably well for that, 
> although it requires you to create an absurd number of repetitive 
> functions.
> 
> But for anything much more complicated, such as matrices, tensors, big 
> integer arithmetic, etc -- it's an abject failure. It's clumsy, and 
> creates masses of temporary objects, which kills performance so 
> completely that it's unusable. But the whole point of operator 
> overloading was to allow nice notation in a performace-oriented 
> language! Expression templates are basically a hack to restore 
> performance in most cases, but it comes at a massive cost in simplicity.
> And the performance even then is not always optimal.
> 
> I think that Walter's idea, in tightening the semantics of overloaded 
> operators, is the right approach. Unfortunately, it doesn't go far 
> enough, so we get the worst of both worlds: the C++ freedom is 
> curtailed, but there isn't enough power to replace it.

Very well put.

> Ultimately, I think that the problem is that ideally, '+' is not simply 
> a call to a function called 'plus()'. What you'd like an operator to 
> compile to, depends on the expression in which it is embedded. For 
> maximum performance, an expression needs to be digested before it is 
> converted into elementary functions.
> 
> In my 'operator overloading without temporaries' proposal in Bugzilla,
> I showed that DEFINING a -= b as being identical to a = a - b, and then 
>  creating a symmetric operation for a = b - a allows optimal code 
> generation in a great many cases. It's not a complete solution, though.
> 
> In particular, irreducible temporaries need more thought. Ideally, in 
> something like a += b * c + d, b*c would be created in a memory pool, 
> and deleted at the end of the expression.
> (By contrast, a = b*c+d, would translate to a=b*c; a+=d; so no temporary 
> is required).

That's an awesome proposal. I'd like to expand it to comprehend fusion 
as well. Consider:

A = B + C - D;

where the operands are matrices. The best hand-written implementation 
would loop once through the three matrices and assign to the destination 
element-wise A[i, j] = B[i, j] + C[i, j] - D[i, j]. However, with an 
approach that has only one operator application as its horizon, it is 
impossible to achieve that optimization. So I wonder what abstraction 
could be devised that makes it easy and natural to support such fusion. 
Expression templates achieve that by saving the right-hand expression 
tree as a type and then using it during the assignment. This requires a 
considerable effort and has some drawbacks.

> There are other, less serious problems which also need to be addressed.
> 
> Defining ++a as a+=1 is probably a mistake. It raises lots of nasty issues.
> * If a is a complex number, a = a + 1 makes perfect sense. But it's not 
> obvious that ++a is sensible.
> * What type is '1'? Is it an int, a uint, a long, ... You don't have 
> that issue with increment.

Great points!

> As I see it, there are two possible strategies:
> (1) Pursuing optimal performance, which requires semantic tightening, 
> and reduced flexibility, or
> (2) Pursure simplicity and semantic flexibility, sacrificing performance.
> 
> I think those two possibilities are mutually exclusive.

I tend to be more optimistic, but if asked to choose, I'd go for (1). 
One important lesson learned from C++'s operator overloading is that 
freedom was almost always badly used. Tellingly, whenever operator 
overloading is taught or talked about, the first caveat mentioned is 
that defining inconsistent batteries of operators is exceedingly easy.

Andrei
1 2 3 4 5
Top | Discussion index | About this forum | D home