November 20, 2009
On 2009-11-19 16:26:41 -0500, Walter Bright <newshound1@digitalmars.com> said:

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

By the way, if you could omit the parenthesis for a one-argument function call, you could write things like this:

	a .pow b

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

November 20, 2009
On Wed, Nov 18, 2009 at 8:55 PM, Robert Jacques <sandford@jhu.edu> wrote:

> For what it's worth, I used aliases of a template binary op function in order to do all the operator overloads of a small vec class. So I like your solution.

Yeh, I've done something like that before too.  So now instead of funnelling all kinds of opBlah functions into one template/mixin/whatever  the compiler will just eliminate the middle man and take us right there to the template.  I like it.

--bb
November 20, 2009
On Wed, Nov 18, 2009 at 10:55 PM, Rainer Deyke <rainerd@eldwood.com> wrote:
> Andrei Alexandrescu wrote:
>> 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.
>
> Isn't opBinary just a reduced-functionality version of opUnknownMethod (or whatever that is/was going to be called)?
>
> T opBinary(string op)(T rhs) {
>    static if (op == "+") return data + rhs.data;
>    else static if (op == "-") return data - rhs.data;
>    ...
>    else static assert(0, "Operator "~op~" not implemented");
> }
>
> T opUnknownMethod(string op)(T rhs) {
>    static if (op == "opAdd") return data + rhs.data;
>    else static if (op == "opSub") return data - rhs.data;
>    ...
>    else static assert(0, "Method "~op~" not implemented");
> }
>
> I'd much rather have opUnknownMethod than opBinary.  If if I have opUnknownMethod, then opBinary becomes redundant.

opBinary doesn't really become redundant because you still need the _r variants.
You could come up with some convention for the string that represents
the _r flavor of opUnknownMethod!("-") but why not just make'em
different methods?
I don't think there's enough in common between a typical operator and
a generic unknownMethod to make fusing them worth it.

--bb
November 20, 2009
On Thu, Nov 19, 2009 at 1:23 AM, Lars T. Kyllingstad <public@kyllingen.nospamnet> wrote:

> 7. opPow()

votes++

> 8. The magic "meta" namespace, aka. getting rid of is(typeof({...})) and
> __traits(...).

votes++

--bb
November 20, 2009
On Thu, Nov 19, 2009 at 8:46 AM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> grauzone wrote:
>>
>> What's with opSomethingAssign (or "expr1[expr2] @= expr3" in general)? opBinary doesn't seem to solve any of those.
>
> opBinary does solve opIndex* morass because it only adds one function per category, not one function per operator. For example:
>
> struct T {
>    // op can be "=", "+=", "-=" etc.
>    E opAssign(string op)(E rhs) { ... }
>    // op can be "=", "+=", "-=" etc.
>    E opIndexAssign(string op)(size_t i, E rhs) { ... }
> }

Rewrite
a.prop = x;   =>    a.opPropertyAssign!("prop", "=")(x);

to that and we're really getting somewhere!

--bb
November 20, 2009
Bill Baxter wrote:
> On Thu, Nov 19, 2009 at 8:46 AM, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>> grauzone wrote:
>>> What's with opSomethingAssign (or "expr1[expr2] @= expr3" in general)?
>>> opBinary doesn't seem to solve any of those.
>> opBinary does solve opIndex* morass because it only adds one function per
>> category, not one function per operator. For example:
>>
>> struct T {
>>    // op can be "=", "+=", "-=" etc.
>>    E opAssign(string op)(E rhs) { ... }
>>    // op can be "=", "+=", "-=" etc.
>>    E opIndexAssign(string op)(size_t i, E rhs) { ... }
>> }
> 
> Rewrite
> a.prop = x;   =>    a.opPropertyAssign!("prop", "=")(x);
> 
> to that and we're really getting somewhere!
> 
> --bb

I swear I was thinking of that.

Andrei
November 20, 2009
aarti_pl wrote:
> Andrei Alexandrescu pisze:
>> We're entering the finale of D2 and I want to keep a short list of things that must be done and integrated in the release. It is clearly understood by all of us that there are many things that could and probably should be done.
>>
>> 1. Currently Walter and Don are diligently fixing the problems marked on the current manuscript.
>>
>> 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.
>>
>> 3. It was mentioned in this group that if getopt() does not work in SafeD, then SafeD may as well pack and go home. I agree. We need to make it work. Three ideas discussed with Walter:
>>
>> * Allow taking addresses of locals, but in that case switch allocation from stack to heap, just like with delegates. If we only do that in SafeD, behavior will be different than with regular D. In any case, it's an inefficient proposition, particularly for getopt() which actually does not need to escape the addresses - just fills them up.
>>
>> * Allow @trusted (and maybe even @safe) functions to receive addresses of locals. Statically check that they never escape an address of a parameter. I think this is very interesting because it enlarges the common ground of D and SafeD.
>>
>> * Figure out a way to reconcile "ref" with variadics. This is the actual reason why getopt chose to traffic in addresses, and fixing it is the logical choice and my personal favorite.
>>
>> 4. Allow private members inside a template using the eponymous trick:
>>
>> template wyda(int x) {
>>    private enum geeba = x / 2;
>>    alias geeba wyda;
>> }
>>
>> The names inside an eponymous template are only accessible to the current instantiation. For example, wyda!5 cannot access wyda!(4).geeba, only its own geeba. That we we elegantly avoid the issue "where is this symbol looked up?"
>>
>> 5. Chain exceptions instead of having a recurrent exception terminate the program. I'll dedicate a separate post to this.
>>
>> 6. There must be many things I forgot to mention, or that cause grief to many of us. Please add to/comment on this list.
>>
>>
>>
>> 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)

Sweet, I've been waiting for a way to implement brainfuck using operators!

auto bf = new BrainFuck();
bf++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.;
writef(bf.toString()); // outputs "Hello World!\n"

November 20, 2009
Andrei Alexandrescu wrote:
> Justin Johansson wrote:
>> 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.
> 
> I disagree with this false choice.
> 
> http://en.wikipedia.org/wiki/False_dilemma#False_choice
> 
> 
> Andrei

You are very well read :-)
November 20, 2009
aarti_pl wrote:
> bearophile pisze:
>> aarti_pl:
>>
>>> I think that proposed names exactly reflect the meaning. So I would say it is perfectly consistent with D convention.
>>
>> Dollars are money, but opDollar is not a member function that returns the price of a struct. So I don't agree with you, or I don't understand what you mean.
>>
>> Bye,
>> bearophile
> 
> I agree. opDollar is not particularly fitting to D language operator concept. opLength/opSize would fit better.

Unfortunately $ is not necessarily the length, nor the size. It might not even be an arithmetic type.
November 20, 2009
Rainer Deyke wrote:
> Andrei Alexandrescu wrote:
>> 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.
> 
> Isn't opBinary just a reduced-functionality version of opUnknownMethod
> (or whatever that is/was going to be called)?
> 
> T opBinary(string op)(T rhs) {
>     static if (op == "+") return data + rhs.data;
>     else static if (op == "-") return data - rhs.data;
>     ...
>     else static assert(0, "Operator "~op~" not implemented");
> }
> 
> T opUnknownMethod(string op)(T rhs) {
>     static if (op == "opAdd") return data + rhs.data;
>     else static if (op == "opSub") return data - rhs.data;
>     ...
>     else static assert(0, "Method "~op~" not implemented");
> }
> 
> I'd much rather have opUnknownMethod than opBinary.  If if I have
> opUnknownMethod, then opBinary becomes redundant.
> 
> 
Shouldn't you use opUnknownMethod for, you know, unknown methods? Implementing binary operators with an unknown method method seems unclean.