November 19, 2009
On Nov 20, 09 05:26, Walter Bright wrote:
> aarti_pl wrote:
>> I know that quite a few people here doesn't like to allow users to
>> define their own operators, because it might obfuscate code. But it
>> doesn't have to be like this. Someone here already mentioned here that
>> it is not real problem for programs in C++. Good libraries don't abuse
>> this functionality.
>
> The problem with user defined operators is:
>
> 1. User defined tokens - mixes up lexing with semantic analysis
>
> 2. User defined syntax - mixes up parsing with semantic analysis
>
> and then we're in C++ land :-(
>
> Unless such have a unique grammar that can be lexed and parsed:
>
> a :string: b
>
> where string is the user defined name, so you can do things like:
>
> a :^^: b
>
> and define your own pow operator. The problem with this approach is the
> sheer ugliness of it.

a /pow/ b is already implementable...

Speaking of which, how to map opDiv_r into its opBinary!()() equivalent?
November 19, 2009
On Thu, Nov 19, 2009 at 01:26:41PM -0800, Walter Bright wrote:
> Unless such have a unique grammar that can be lexed and parsed:
> 
>     a :string: b
> 
> where string is the user defined name, so you can do things like:
> 
>     a :^^: b

What if there was some magic defined at the top of the file or something, that could be pulled out without parsing the whole thing?

pragma(DEFINE_BINARY_OPERATOR, "^^");

Then, later in that module, and any that import it, you'd treat the ^^ as a user defined operator token.

-- 
Adam D. Ruppe
http://arsdnet.net
November 19, 2009
On Thu, Nov 19, 2009 at 04:46:55PM -0500, Adam D. Ruppe wrote:
> What if there was some magic defined at the top of the file or something, that could be pulled out without parsing the whole thing?

I should add that I'm not really sold on the idea of user defined operators at all - I'm just curious about how it might be done in the compiler.


-- 
Adam D. Ruppe
http://arsdnet.net
November 19, 2009
Thu, 19 Nov 2009 13:26:41 -0800, Walter Bright wrote:

> aarti_pl wrote:
>> I know that quite a few people here doesn't like to allow users to define their own operators, because it might obfuscate code. But it doesn't have to be like this. Someone here already mentioned here that it is not real problem for programs in C++. Good libraries don't abuse this functionality.
> 
> The problem with user defined operators is:
> 
>   1. User defined tokens - mixes up lexing with semantic analysis
> 
>   2. User defined syntax - mixes up parsing with semantic analysis
> 

Some languages have syntactic rule extensions which allows defining symbols constructed either from characters [a-zA-Z][a-zA-Z0-9]* (like C) or from special characters like <>:;,.-/\ etc.

Another feature is that in those languages operators are just normal functions with extra syntax (fixity, associativity, etc.)

This way even "built-in" operations on ints etc. can be defined in the library.

> and then we're in C++ land :-(
> 
> Unless such have a unique grammar that can be lexed and parsed:
> 
>      a :string: b
> 
> where string is the user defined name, so you can do things like:
> 
>      a :^^: b
> 
> and define your own pow operator. The problem with this approach is the sheer ugliness of it.

Haskell uses a `myFun` b.
November 19, 2009
aarti_pl wrote:
> Andrei Alexandrescu pisze:
>> aarti_pl wrote:
>>> aarti_pl pisze:
>>>> Andrei Alexandrescu pisze:
>>>>> 2. User-defined operators must be revamped. Fortunately Don already put in an important piece of functionality (opDollar). What we're looking at is a two-pronged attack motivated by Don's proposal:
>>>>>
>>>>> http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP7
>>>>>
>>>>> The two prongs are:
>>>>>
>>>>> * Encode operators by compile-time strings. For example, instead of the plethora of opAdd, opMul, ..., we'd have this:
>>>>>
>>>>> T opBinary(string op)(T rhs) { ... }
>>>>>
>>>>> The string is "+", "*", etc. We need to design what happens with read-modify-write operators like "+=" (should they be dispatch to a different function? etc.) and also what happens with index-and-modify operators like "[]=", "[]+=" etc. Should we go with proxies? Absorb them in opBinary? Define another dedicated method? etc.
>>>>>
>>>>> * Loop fusion that generalizes array-wise operations. This idea of Walter is, I think, very good because it generalizes and democratizes "magic". The idea is that, if you do
>>>>>
>>>>> a = b + c;
>>>>>
>>>>> and b + c does not make sense but b and c are ranges for which a.front = b.front + c.front does make sense, to automatically add the iteration paraphernalia.
>>>>>
>>> (..)
>>>>> Andrei
>>>>
>>>> I kinda like this proposal. But I would rather call template like below:
>>>>
>>>> T opInfix(string op)(T rhs) { ... }
>>>> T opPrefix(string op)(T rhs) { ... }
>>>> T opPostfix(string op)(T rhs) { ... }
>>>>
>>>> and allow user to define her own operators (though it doesn't have to be done now).
>>>>
>>>> I know that quite a few people here doesn't like to allow users to define their own operators, because it might obfuscate code. But it doesn't have to be like this. Someone here already mentioned here that it is not real problem for programs in C++. Good libraries don't abuse this functionality.
>>>>
>>>> User defined operators would allow easy definition of Domain Specific Languages in D. I was already writing about it some time ago:
>>>>
>>>> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81026 
>>>>
>>>> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81352 
>>>>
>>>>
>>>> BR
>>>> Marcin Kuszczak
>>>> (aarti_pl)
>>>
>>> Of course for opPrefix/opPostfix signatures will be different:
>>> T opPrefix(string op)() { ... }
>>> T opPostfix(string op)() { ... }
>>>
>>> Sorry for mistake.
>>>
>>> BR
>>> Marcin Kuszczak
>>> (aarti_pl)
>>
>> I think we'll solve postfix "++" without requiring the user to define it. Do you envision user-defined postfix operators?
>>
>> Andrei
> 
> Well, maybe something like below:
> 
> auto a = 2²;  //(quadratic power of 2)
> auto a = 5!;  //factorial of 5
> auto a = 2Ƴ + 3ɛ; //solving equations
> auto weight = 5kg; //units of measurement
> 
> The point is that this covers whole scope of operators. In fact even built-in operators could be defined using it.
> 
> Postfix operator ++ can be defined using prefix operator++ just by delegation and this can be default.
> 
> Best Regards
> Marcin Kuszczak
> (aarti_pl)

Marcin demonstrates a valid point.

If there is going to be this feature creep, the feature should be complete with all the usual variants of operator arity and notation (i.e. prefix/postfix/infix).  Otherwise it really it's only two-thirds baked.

-- Justin Johansson
November 19, 2009
Justin Johansson wrote:
> aarti_pl wrote:
>> Andrei Alexandrescu pisze:
>>> aarti_pl wrote:
>>>> aarti_pl pisze:
>>>>> Andrei Alexandrescu pisze:
>>>>>> 2. User-defined operators must be revamped. Fortunately Don already put in an important piece of functionality (opDollar). What we're looking at is a two-pronged attack motivated by Don's proposal:
>>>>>>
>>>>>> http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP7
>>>>>>
>>>>>> The two prongs are:
>>>>>>
>>>>>> * Encode operators by compile-time strings. For example, instead of the plethora of opAdd, opMul, ..., we'd have this:
>>>>>>
>>>>>> T opBinary(string op)(T rhs) { ... }
>>>>>>
>>>>>> The string is "+", "*", etc. We need to design what happens with read-modify-write operators like "+=" (should they be dispatch to a different function? etc.) and also what happens with index-and-modify operators like "[]=", "[]+=" etc. Should we go with proxies? Absorb them in opBinary? Define another dedicated method? etc.
>>>>>>
>>>>>> * Loop fusion that generalizes array-wise operations. This idea of Walter is, I think, very good because it generalizes and democratizes "magic". The idea is that, if you do
>>>>>>
>>>>>> a = b + c;
>>>>>>
>>>>>> and b + c does not make sense but b and c are ranges for which a.front = b.front + c.front does make sense, to automatically add the iteration paraphernalia.
>>>>>>
>>>> (..)
>>>>>> Andrei
>>>>>
>>>>> I kinda like this proposal. But I would rather call template like below:
>>>>>
>>>>> T opInfix(string op)(T rhs) { ... }
>>>>> T opPrefix(string op)(T rhs) { ... }
>>>>> T opPostfix(string op)(T rhs) { ... }
>>>>>
>>>>> and allow user to define her own operators (though it doesn't have to be done now).
>>>>>
>>>>> I know that quite a few people here doesn't like to allow users to define their own operators, because it might obfuscate code. But it doesn't have to be like this. Someone here already mentioned here that it is not real problem for programs in C++. Good libraries don't abuse this functionality.
>>>>>
>>>>> User defined operators would allow easy definition of Domain Specific Languages in D. I was already writing about it some time ago:
>>>>>
>>>>> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81026 
>>>>>
>>>>> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81352 
>>>>>
>>>>>
>>>>> BR
>>>>> Marcin Kuszczak
>>>>> (aarti_pl)
>>>>
>>>> Of course for opPrefix/opPostfix signatures will be different:
>>>> T opPrefix(string op)() { ... }
>>>> T opPostfix(string op)() { ... }
>>>>
>>>> Sorry for mistake.
>>>>
>>>> BR
>>>> Marcin Kuszczak
>>>> (aarti_pl)
>>>
>>> I think we'll solve postfix "++" without requiring the user to define it. Do you envision user-defined postfix operators?
>>>
>>> Andrei
>>
>> Well, maybe something like below:
>>
>> auto a = 2²;  //(quadratic power of 2)
>> auto a = 5!;  //factorial of 5
>> auto a = 2Ƴ + 3ɛ; //solving equations
>> auto weight = 5kg; //units of measurement
>>
>> The point is that this covers whole scope of operators. In fact even built-in operators could be defined using it.
>>
>> Postfix operator ++ can be defined using prefix operator++ just by delegation and this can be default.
>>
>> Best Regards
>> Marcin Kuszczak
>> (aarti_pl)
> 
> Marcin demonstrates a valid point.
> 
> If there is going to be this feature creep, the feature should be complete with all the usual variants of operator arity and notation (i.e. prefix/postfix/infix).  Otherwise it really it's only two-thirds baked.
> 
> -- Justin Johansson

I meant to say "Iff there is ..." as in "if and only if".

Like others, I'm not completely sold on the idea at all.  Also it's probably not possible to squeeze something as long as this on to a short list.

All or nothing please.
November 19, 2009
On Nov 20, 09 04:31, aarti_pl wrote:
> Andrei Alexandrescu pisze:
>> aarti_pl wrote:
>>> aarti_pl pisze:
>>>> Andrei Alexandrescu pisze:
>>>>> 2. User-defined operators must be revamped. Fortunately Don already
>>>>> put in an important piece of functionality (opDollar). What we're
>>>>> looking at is a two-pronged attack motivated by Don's proposal:
>>>>>
>>>>> http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP7
>>>>>
>>>>> The two prongs are:
>>>>>
>>>>> * Encode operators by compile-time strings. For example, instead of
>>>>> the plethora of opAdd, opMul, ..., we'd have this:
>>>>>
>>>>> T opBinary(string op)(T rhs) { ... }
>>>>>
>>>>> The string is "+", "*", etc. We need to design what happens with
>>>>> read-modify-write operators like "+=" (should they be dispatch to a
>>>>> different function? etc.) and also what happens with
>>>>> index-and-modify operators like "[]=", "[]+=" etc. Should we go
>>>>> with proxies? Absorb them in opBinary? Define another dedicated
>>>>> method? etc.
>>>>>
>>>>> * Loop fusion that generalizes array-wise operations. This idea of
>>>>> Walter is, I think, very good because it generalizes and
>>>>> democratizes "magic". The idea is that, if you do
>>>>>
>>>>> a = b + c;
>>>>>
>>>>> and b + c does not make sense but b and c are ranges for which
>>>>> a.front = b.front + c.front does make sense, to automatically add
>>>>> the iteration paraphernalia.
>>>>>
>>> (..)
>>>>> Andrei
>>>>
>>>> I kinda like this proposal. But I would rather call template like
>>>> below:
>>>>
>>>> T opInfix(string op)(T rhs) { ... }
>>>> T opPrefix(string op)(T rhs) { ... }
>>>> T opPostfix(string op)(T rhs) { ... }
>>>>
>>>> and allow user to define her own operators (though it doesn't have
>>>> to be done now).
>>>>
>>>> I know that quite a few people here doesn't like to allow users to
>>>> define their own operators, because it might obfuscate code. But it
>>>> doesn't have to be like this. Someone here already mentioned here
>>>> that it is not real problem for programs in C++. Good libraries
>>>> don't abuse this functionality.
>>>>
>>>> User defined operators would allow easy definition of Domain
>>>> Specific Languages in D. I was already writing about it some time ago:
>>>>
>>>> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81026
>>>>
>>>> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81352
>>>>
>>>>
>>>> BR
>>>> Marcin Kuszczak
>>>> (aarti_pl)
>>>
>>> Of course for opPrefix/opPostfix signatures will be different:
>>> T opPrefix(string op)() { ... }
>>> T opPostfix(string op)() { ... }
>>>
>>> Sorry for mistake.
>>>
>>> BR
>>> Marcin Kuszczak
>>> (aarti_pl)
>>
>> I think we'll solve postfix "++" without requiring the user to define
>> it. Do you envision user-defined postfix operators?
>>
>> Andrei
>
> Well, maybe something like below:
>
> auto a = 2²; //(quadratic power of 2)
> auto a = 5!; //factorial of 5
> auto a = 2Ƴ + 3ɛ; //solving equations
> auto weight = 5kg; //units of measurement
>
> The point is that this covers whole scope of operators. In fact even
> built-in operators could be defined using it.
>
> Postfix operator ++ can be defined using prefix operator++ just by
> delegation and this can be default.
>
> Best Regards
> Marcin Kuszczak
> (aarti_pl)

It will make weird stuff like

class G {
  G opPostfix(string op)() if (op == "%") { ... }
  G opCall(int x) { ... }
}

auto g = new G;
g% (4+2); // what should it do?


November 19, 2009
On Thu, Nov 19, 2009 at 12:47 PM, Leandro Lucarella <llucax@gmail.com> wrote:
> Andrei Alexandrescu, el 18 de noviembre a las 20:33 me escribiste:
>> Leandro Lucarella wrote:
>> >grauzone, el 19 de noviembre a las 03:47 me escribiste:
>> >>Does the current proposal make things simpler at all? All you're doing is to enable the programmer to "fix" the clumsy semantics by throwing lots of CTFE onto the problem. Why not generate the operator functions with CTFE in the first place...
>> >
>> >I was about to say that, the solution is a hack. I could understand a hack if there were no other way to do it, but you can generate the code for the opXxx using CTFE/string mixins already: we already have a hackish solution. I don't think adding a new hack would be nice (specially when it will be a big change).
>> >
>> >Maybe a not-so-hackish solution can be found when AST macros get implemented.
>>
>> I am thinking that representing operators by their exact token representation is a principled approach because it allows for unambiguous mapping, testing with if and static if, and also allows saving source code by using only one string mixin. It would take more than just a statement that it's hackish to convince me it's hackish. I currently don't see the hackishness of the approach, and I consider it a vast improvement over the current state of affairs.
>>
>> I'd be grateful if you argued your point further and hopefully suggested an approach that is better. I want us to move fast with this. So it's just the right time to contribute.
>
> What I found hackish about it is that the code is a string manipulation mess. You can already do a string manipulation mess to programatically implement all the operator overloading.

This is true, but if you leave it entirely up to the programmer and
string mixins, the mess is much more messy.
You're going to end up with code like this:

mixin(genBinaryOp("+", q{MyType}, q{MyType rhs}, q{
    return this.impl + rhs.impl;
}));


instead of this:
MyType opBinary(string op : "+")(MyType rhs)  {
    return this.impl + rhs.impl;
}

I would have a hard time defending the former as the recommended D style. But the latter is not so bad.  It looks like a regular template declaration, and code is code, not a string.


> About the ideal solution, I don't have it. I just have the impression that AST macros can help here, but it's been ages since they were postponed to D3 and I don't have any idea of what they would look like, so I can't propose a solution now.

Yeh, I think macros are the best solution.  If we have macros then the declarations could look like

genBinaryOp(+, MyType, MyType rhs,
        return this.impl + rhs.impl;
)

And with definable syntax, it could maybe become
MyType opBinary "+" (MyType rhs) {
   return this.impl + rhs.impl;
}

If we had such a macro then the macro could handle mapping symbols
("+") to names ("opAdd").

Some sort of Nemerle-ish definition of such a macro:

macro opBinary(op, ret, args, code)
syntax {
     $ret opBinary $op ($args) { $code }
}
{
    auto opFuncName = operatorNameForSymbol(op);
    <| $ret $opFuncName ($args) { $code } |>
}

I think definable syntax is probably a long way off for DMD.
But the rest of it has a direct translation in terms of a CTFE string
processing function.
All the args are actually 'string' just not declared as such.
<| ... |>  is basically just a call to a big string manipulation
function that replaces $var with whatever value the string var has.
And there's an implicit 'return' of that string.

--bb
November 19, 2009
On Thu, Nov 19, 2009 at 1:26 PM, Walter Bright <newshound1@digitalmars.com> wrote:
> aarti_pl wrote:
>>
>> I know that quite a few people here doesn't like to allow users to define their own operators, because it might obfuscate code. But it doesn't have to be like this. Someone here already mentioned here that it is not real problem for programs in C++. Good libraries don't abuse this functionality.
>
> The problem with user defined operators is:
>
>  1. User defined tokens - mixes up lexing with semantic analysis
>
>  2. User defined syntax - mixes up parsing with semantic analysis
>
> and then we're in C++ land :-(
>
> Unless such have a unique grammar that can be lexed and parsed:
>
>    a :string: b
>
> where string is the user defined name, so you can do things like:
>
>    a :^^: b
>
> and define your own pow operator. The problem with this approach is the sheer ugliness of it.

You also have to wedge precedence in there somehow.
Maybe instead of :string: you use +string+ or *string* and the
first/last character tells the precedence.

Oh wait, downs already has code that does this.  The question, I
think, is how to make it reasonably fast and less cumbersome to
declare.
Though I'm not sure it's really worth the effort.

--bb
November 19, 2009
Walter Bright pisze:
> aarti_pl wrote:
>> I know that quite a few people here doesn't like to allow users to define their own operators, because it might obfuscate code. But it doesn't have to be like this. Someone here already mentioned here that it is not real problem for programs in C++. Good libraries don't abuse this functionality.
> 
> The problem with user defined operators is:
> 
>  1. User defined tokens - mixes up lexing with semantic analysis
> 
>  2. User defined syntax - mixes up parsing with semantic analysis
> 
> and then we're in C++ land :-(
> 

"retard" probably already answered it.

I was thinking about something like below:


symbols = '!@#$%^&*'	//quick & dirty definition
identifier = '[a-zA-Z][a-zA-Z0-9]*' //quick & dirty definition

Prefix operator:
1. [symbols][whitespace][identifier]
2. [identifier]whitespace[identifier]

Postfix operator:
1. [identifier][whitespace][symbols]
2. [identifier]whitespace[identifier]

Infix operator:
1. [identifier][whitespace][symbols][whitespace][identifier]
2. [identifier]whitespace[identifier]whitespace[identifier]

With precedence defined as above: first prefix, then postfix, then infix.

Should work...

> Unless such have a unique grammar that can be lexed and parsed:
> 
>     a :string: b
> 
> where string is the user defined name, so you can do things like:
> 
>     a :^^: b
> 
> and define your own pow operator. The problem with this approach is the sheer ugliness of it.

This might be also acceptable. Especially with `` syntax. (I know it's currently for strings).

----

I believe that user defined operators will have positive impact on D language. Please notice that always when you have more power, then you can make more bad things. But you can also do more good things! And doing good things or doing bad things is not something what should programming language care of. Programming language is IMHO just for giving good tools. User should decide how to use them.

I think there aren't enough good reasons to introduce new syntax if it will not allow user defined operators. It will be rather source of confusion if we only allow to pass few symbols as strings: strings are about 'freedom' of content. So using it for passing just a few symbols is for me "corner case".

BR
Marcin Kuszczak
(aarti_pl)