December 27, 2008
Jarrett Billingsley 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.
> 
> 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 ;)

Well I overstated my point, sorry. The nice thing about overloading ++ is that you can use the same algorithms with built-in types and user-defined types. You are, however, right that defining various functions such as increment and decrement for built-ins and also user-defined types would obviate the need for syntactically consistent operators.

Andrei
December 27, 2008
On Sat, Dec 27, 2008 at 11:10 AM, Bill Baxter <wbaxter@gmail.com> wrote:
>> 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.

Except that in D, you rarely use pointers, and ++ isn't defined on arrays.  So you lose a lot of the unity that the syntax affords you in C++.
December 27, 2008
Andrei Alexandrescu wrote:
>>     auto op(++)(); // bar++
>>     auto op(++)(int); // ++bar
> 
> Hey, wasn't the implementation of the postincrement operator through an overload a rather untasty hack?

> 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

How about this:

Unary op: ++f, ~f, ~f, +f, -f, *f
auto operator(++, --, ~, !, +, -, *)()
{
	// posfix is provided by compiler
	// and is only used for: foo++ foo--
	static if (posfix)
		return op(this.value);
	else ...
}

Binary op: equality comparison f1 <= f2
bool operator(<, >, <=, >=, ==, !=)(Foo foo)
{
	return op(this.value, foo.value);
}

For un-order object, he/she just list 'correct' operator(s) in op() list. Ex: bool operator(!=, ==)(Foo foo) {}


Binary op: logic f1 || f2 && f3
bool operator(&&, ||, &, |, &)(Op[] oops, Foo[] foo)
{
	auto result = foo[0].value;
	foreach (i, op ; oops)
		result = op( result, foo[i+1].value );
	return result;
}


Binary op: bitwise
auto operator(&, |, ^)(Op[], Foo[]) {}


Binary op: add, sub, mul, div, shift, cat(~) f1 + f2 * f3 ~ f4
auto operator(+, -, *, /, %, <<, >>, ~, =)(Op[] oops, Foo[] foo()
{	
	auto result = foo[0].value;
	foreach (i, op ; oops)
		result = op( result, foo[i+1].value );
	return result;
}
Op[], Foo[] should/may be re-arranged according to operator precedence???


Binary op: +=, -=, *=, <<=, ~= f1 *= f2 + f3 / f4
I 'think' the compiler can evaluate to: f1 = f1 * (f2 + f3 / f4);
December 27, 2008
The Anh Tran wrote:
> Andrei Alexandrescu wrote:
>>>     auto op(++)(); // bar++
>>>     auto op(++)(int); // ++bar
>>
>> Hey, wasn't the implementation of the postincrement operator through an overload a rather untasty hack?
> 
>> 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
> 
> How about this:
> 
> Unary op: ++f, ~f, ~f, +f, -f, *f
> auto operator(++, --, ~, !, +, -, *)()
> {
>     // posfix is provided by compiler
>     // and is only used for: foo++ foo--
>     static if (posfix)
>         return op(this.value);
>     else ...
> }
> 
> Binary op: equality comparison f1 <= f2
> bool operator(<, >, <=, >=, ==, !=)(Foo foo)
> {
>     return op(this.value, foo.value);
> }
> 
> For un-order object, he/she just list 'correct' operator(s) in op() list. Ex: bool operator(!=, ==)(Foo foo) {}

Why invent new syntax when compile-time strings are already there?

auto operator(string op)() if (op == "++" || op == "--")
{
    return mixin(op ~ "this.value");
}

etc. That, of course, is orthogonal to the semantic equivalences suggested by Don and does not solve fusion.

Andrei
December 27, 2008
Don pisze:
> 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.

Well, I think you have just discovered two levels of programmers interests in operator overloading :-)

* First level (group) is for programmers which want to use operators to create fast mathematical operations for user defined types.

* Second level (group) is for programmers which want to use operators for creating better syntax, to make their users more happy.

It seems that both groups have good reasons for their requests.

As you said these two possibilities are mutually exclusive, so I think also solution for this challenge should be splitted, so that everyone could get what he want.

One possible solution is to allow defining operator overloading on two levels also:

1. In first level, where operators are used for computation, there might be operators like today in D: opCmp, opEquals. They can be even stricter and/or better defined as needed.

2. Second level should be just raw operator access, which allows to use operator syntax in wider scope of cases.

Compiler should enforce the rule that operators from two levels can not be intermixed in one class/struct.

I think that such a solution could make these two groups have their goals achieved.

BR
Marcin Kuszczak
(aarti_pl)
December 27, 2008
aarti_pl wrote:
> Don pisze:
>> 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.
> 
> Well, I think you have just discovered two levels of programmers interests in operator overloading :-)
> 
> * First level (group) is for programmers which want to use operators to create fast mathematical operations for user defined types.
> 
> * Second level (group) is for programmers which want to use operators for creating better syntax, to make their users more happy.
> 
> It seems that both groups have good reasons for their requests.
> 
> As you said these two possibilities are mutually exclusive, so I think also solution for this challenge should be splitted, so that everyone could get what he want.
> 
> One possible solution is to allow defining operator overloading on two levels also:
> 
> 1. In first level, where operators are used for computation, there might be operators like today in D: opCmp, opEquals. They can be even stricter and/or better defined as needed.
> 
> 2. Second level should be just raw operator access, which allows to use operator syntax in wider scope of cases.
> 
> Compiler should enforce the rule that operators from two levels can not be intermixed in one class/struct.
> 
> I think that such a solution could make these two groups have their goals achieved.
> 
> BR
> Marcin Kuszczak
> (aarti_pl)

That can be achieved by only defining the low-level operators in the language and then developing a library layer on top of them.

Andrei
December 28, 2008
Hello Andrei,

> The Anh Tran wrote:
> 
>> Andrei Alexandrescu wrote:
>> 
>>>> auto op(++)(); // bar++
>>>> auto op(++)(int); // ++bar
>>> Hey, wasn't the implementation of the postincrement operator through
>>> an overload a rather untasty hack?
>>> 
>>> 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
>>> 
>> How about this:
>> 
>> Unary op: ++f, ~f, ~f, +f, -f, *f
>> auto operator(++, --, ~, !, +, -, *)()
>> {
>> // posfix is provided by compiler
>> // and is only used for: foo++ foo--
>> static if (posfix)
>> return op(this.value);
>> else ...
>> }
>> Binary op: equality comparison f1 <= f2
>> bool operator(<, >, <=, >=, ==, !=)(Foo foo)
>> {
>> return op(this.value, foo.value);
>> }
>> For un-order object, he/she just list 'correct' operator(s) in op()
>> list. Ex: bool operator(!=, ==)(Foo foo) {}
>> 
> Why invent new syntax when compile-time strings are already there?
> 
> auto operator(string op)() if (op == "++" || op == "--")
> {
> return mixin(op ~ "this.value");
> }
> etc. That, of course, is orthogonal to the semantic equivalences
> suggested by Don and does not solve fusion.
> 
> Andrei
> 


Once again, I'm no expert in this matter, but the compiler-time strings idea looks like a great solution for this.  Was this brought up before? ...because that was kind of what I was thinking when you mentioned a new operator overloading syntax for D.

-JJR


December 28, 2008
John Reimer wrote:
> Hello Andrei,
> 
>> The Anh Tran wrote:
>>
>>> Andrei Alexandrescu wrote:
>>>
>>>>> auto op(++)(); // bar++
>>>>> auto op(++)(int); // ++bar
>>>> Hey, wasn't the implementation of the postincrement operator through
>>>> an overload a rather untasty hack?
>>>>
>>>> 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
>>>>
>>> How about this:
>>>
>>> Unary op: ++f, ~f, ~f, +f, -f, *f
>>> auto operator(++, --, ~, !, +, -, *)()
>>> {
>>> // posfix is provided by compiler
>>> // and is only used for: foo++ foo--
>>> static if (posfix)
>>> return op(this.value);
>>> else ...
>>> }
>>> Binary op: equality comparison f1 <= f2
>>> bool operator(<, >, <=, >=, ==, !=)(Foo foo)
>>> {
>>> return op(this.value, foo.value);
>>> }
>>> For un-order object, he/she just list 'correct' operator(s) in op()
>>> list. Ex: bool operator(!=, ==)(Foo foo) {}
>>>
>> Why invent new syntax when compile-time strings are already there?
>>
>> auto operator(string op)() if (op == "++" || op == "--")
>> {
>> return mixin(op ~ "this.value");
>> }
>> etc. That, of course, is orthogonal to the semantic equivalences
>> suggested by Don and does not solve fusion.
>>
>> Andrei
>>
> 
> 
> Once again, I'm no expert in this matter, but the compiler-time strings idea looks like a great solution for this.  Was this brought up before? ...because that was kind of what I was thinking when you mentioned a new operator overloading syntax for D.

Only in private conversation between Walter and me. But anyway, let's not forget we need to address fusion as well.

Andrei
1 2 3 4 5
Next ›   Last »