November 20, 2009
Andrei Alexandrescu wrote:
> 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
Is this doable without a performance drop?
November 20, 2009
Don <nospam@nospam.com> wrote:

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

opEnd, then?

-- 
Simen
November 20, 2009
Andrei Alexandrescu wrote:
> dsimcha wrote:
>> == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article
>>> dsimcha wrote:
>>>> == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article
>>>>> dsimcha wrote:
>>>>>> == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article
>>>>>>> 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.
>>>>>> IMHO this is a terrible solution.  SafeD should not cause major ripple
>> effects for
>>>>>> pieces of code that don't want to use it.  I'm all for safe defaults even if
>>>>>> they're less efficient or less flexible, but if D starts sacrificing performance
>>>>>> or flexibility for safety **even when the programmer explicitly asks it not
>> to**,
>>>>>> then it will officially have become a bondage and discipline language.
>>>>>>
>>>>>> Furthermore, as you point out, having the semantics of something vary in subtle
>>>>>> ways between SafeD and unsafe D is probably a recipe for confusion.
>>>>>>
>>>>>>
>>>>>>> * 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.
>>>>>> This is a great idea if it can be implemented.  Isn't escape analysis a pretty
>>>>>> hard thing to get right, though, especially when you might not have the source
>>>>>> code to the function being called?
>>>>> Escape analysis is difficult when you don't have information about the
>>>>> functions you're passing the pointer to. For example:
>>>>> void fun(int* p) {
>>>>>      if (condition) gun(p);
>>>>> }
>>>>> Now the problem is that fun's escape-or-not behavior depends on flow
>>>>> (i.e. condition) and on gun's escaping behavior.
>>>>> If we use @safe and @trusted to indicate unequivocally "no escape", then
>>>>> there is no analysis to be done - the hard part of the analysis has
>>>>> already been done manually by the user.
>>>> But then the @safe or @trusted function wouldn't be able to escape pointers to
>>>> heap or static data segment memory either, if I understand this proposal
>> correctly.
>>> Yah. The question is to what extent is that necessary.
>>> Andrei
>>
>> Too kludgey for me.  I'd rather just see ref parameters get fixed and just don't
>> allow taking the address of locals in @safe functions.  I'd say that, except in
>> low-level systems programming that would probably not be @safe for other reasons
>> anyhow, there would be very few good if any good reasons to take the address of a
>> local if reference tuples just worked.
> 
> Unfortunately it's more complicated than that. getopt takes pairs of strings and pointers. The strings don't necessarily have to be lvalues, so constraining getopt to only take references is not the right solution.
> 
> Andrei
How about allowing const references to rvalues?
November 20, 2009
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.

There's not many sensible operators anyway. opPow is the only missing one that's present in many other general-purpose languages. The only other ones I think are remotely interesting are dot and cross product.

Anything beyond that, you generally want a full DSL, probably with different precendence and associativity rules. Eg, for regexp, you'd want postfix * and + operators. There are examples of clever things done in C++  with operator overloading, but I think that's just because it's the only way to do DSLs in C++.

I don't think the applications are there.
November 20, 2009
Don:
> Unfortunately $ is not necessarily the length, nor the size. It might not even be an arithmetic type.

Is opEnd a fitter name?

Bye,
bearophile
November 20, 2009
Simen kjaeraas wrote:
> Don <nospam@nospam.com> wrote:
> 
>> 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.
> 
> opEnd, then?
> 

That was the only other viable suggestion. But I don't think it's very intuitive -- eg, it sounds like there ought to be an opBegin(); why isn't it used for ranges?; etc.
I'd go for opLength() if it really was a length, but it's not.

The big thing in favour of opDollar() is that everyone instantly knows exactly what it means.
November 20, 2009
Andrei Alexandrescu wrote:
> * 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.
> 
> Andrei

What about pure, what about const?

Will we need to

pure T opBinary(string op)(T rhs) if (op == "+" || op == "-") {
  static if (op == "+") { /* ... */ }
  else static if (op == "-") { /* ... */ }
}
T opBinary(string op)(T rhs) if (op == "+=" || ...) {
  // more static if's
}

thereby duplicating every case?
November 20, 2009
Don wrote:
> There's not many sensible operators anyway. opPow is the only missing one that's present in many other general-purpose languages. The only other ones I think are remotely interesting are dot and cross product.

Yup.

> Anything beyond that, you generally want a full DSL, probably with different precendence and associativity rules. Eg, for regexp, you'd want postfix * and + operators. There are examples of clever things done in C++  with operator overloading, but I think that's just because it's the only way to do DSLs in C++.

I was enthralled with the way C++ did it for regex for a while, but when I think more about it, it's just too clever. I think it's more operator overloading abuse now.

> I don't think the applications are there.

I agree.
November 20, 2009
Pelle Månsson wrote:
> Andrei Alexandrescu wrote:
>> * 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.
>>
>> Andrei
> 
> What about pure, what about const?
> 
> Will we need to
> 
> pure T opBinary(string op)(T rhs) if (op == "+" || op == "-") {
>   static if (op == "+") { /* ... */ }
>   else static if (op == "-") { /* ... */ }
> }
> T opBinary(string op)(T rhs) if (op == "+=" || ...) {
>   // more static if's
> }
> 
> thereby duplicating every case?

Well you're better off than before anyway - you get to group operators in pure and impure.

Andrei
November 20, 2009
Andrei Alexandrescu wrote:

> Kyle wrote:
>> Andrei Alexandrescu Wrote:
>> 
>>> 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.
>> 
>> Uniform function call syntax.
>> 
> 
> It's in the book. I'm adding this message as a reminder to add a test case. Thanks!
> 
> Andrei

I'm delighted, thanks!