www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Overloading relational operators separately; thoughts?

reply Minty Fresh <mint fresh.com> writes:
Currently, D offers fine grained overloading for most of the 
unary and arithmetic binary operators, but at some point a 
decision was made to lump together all of the relational 
operators (and if necessary, the equality operators) into a 
single function `opCmp`.
And while it does add a lot of convenience and consistency to how 
operators behave, it does also put a lot of limitations on what 
they can do.

For example, it's not currently possible to implement comparison 
operators that would behave lazily and only compute a certain 
value once a function call forces the computation.

Similarly, it's not possible to construct a DSL that would 
produce code or a query in another language, by returning values 
behave like AST nodes rather than actually performing a 
comparison.

ie.
   table.users
        .where!((users) => users.joined_on >= 3.days.ago)
        .joins(table.posts)
        .on!((posts, users) => posts.user_id == users.id)
        .limit(10)
        .toSql;

It's a little odd to me that D puts so little focus on DSLs, 
since language features like template constraints, `opDispatch`, 
and even the fact that binary operators are overloadable via a 
single templated function are all very useful tools for 
implementing them.

So, I'm just interested in other people's thoughts are on the 
subject, and whether there are any plans to allow overloading 
these operators separately.
Sep 27 2016
next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Wednesday, September 28, 2016 01:18:58 Minty Fresh via Digitalmars-d wrote:
 So, I'm just interested in other people's thoughts are on the
 subject, and whether there are any plans to allow overloading
 these operators separately.
Basically, having them be overloaded separately is error-prone, and it leads to folks overloading them in ways that have nothing to do with what they mean for the built-in types, which makes code harder to read and maintain. D has a concatenation operator specifically because Walter thought that it was horrible to use + for concatenation. If you want to write DSLs, then use strings and mixins. D gives you a _lot_ of power in that area, and it avoids the problems associated with making overloaded operators do things other than what those operators are normally intended to do. With strings, you can make your DSL look however you want - even doing stuff like using various Unicode symbols as operators if you want to. Even with how C++ overloads operators, overloading operators gives you fairly limited options with what you can do with a DSL, whereas you have full freedom with strings - and without the problems that come with trying to make your DSL look like normal D code. - Jonathan M Davis
Sep 27 2016
parent reply Minty Fresh <mint fresh.com> writes:
On Wednesday, 28 September 2016 at 03:12:05 UTC, Jonathan M Davis 
wrote:
 On Wednesday, September 28, 2016 01:18:58 Minty Fresh via 
 Digitalmars-d wrote:
 Basically, having them be overloaded separately is error-prone, 
 and it leads to folks overloading them in ways that have 
 nothing to do with what they mean for the built-in types, which 
 makes code harder to read and maintain. D has a concatenation 
 operator specifically because Walter thought that it was 
 horrible to use + for concatenation.

 If you want to write DSLs, then use strings and mixins. D gives 
 you a _lot_ of power in that area, and it avoids the problems 
 associated with making overloaded operators do things other 
 than what those operators are normally intended to do. With 
 strings, you can make your DSL look however you want - even 
 doing stuff like using various Unicode symbols as operators if 
 you want to. Even with how C++ overloads operators, overloading 
 operators gives you fairly limited options with what you can do 
 with a DSL, whereas you have full freedom with strings - and 
 without the problems that come with trying to make your DSL 
 look like normal D code.

 - Jonathan M Davis
Using strings and mixins does have quite a number of downsides. The additional work required to past the DSL aside, you also usually lose the scope in which things are declared (especially if you wish to reference or declare variables/functions/other constructs within your DSL), error reporting becomes much less precise, and the transition between the outer code and the inner DSL becomes jarring (especially in terms of syntax highlighting). That said, I love the fact D has a separate operator for concatenation. It's extremely useful to not have that ambiguity. Another thought is, operators not behaving as expected doesn't strike me as a failure of the language, given the language supports operator overloading. It's a failure in documentation to explain what the operators are intended to do, or a failure in implementation to behave as they should. Lastly, if operators are intended to behave so strictly, why does this not extend then to binary arithmetic operators (+, -, *, /, %, etc.) They don't follow the same rules as the binary relational operators, after all.
Sep 27 2016
next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Wednesday, September 28, 2016 03:28:50 Minty Fresh via Digitalmars-d wrote:
 Lastly, if operators are intended to behave so strictly, why does
 this not extend then to binary arithmetic operators (+, -, *, /,
 %, etc.)
 They don't follow the same rules as the binary relational
 operators, after all.
It's not possible in the general case to define the arithmetic operators as functions of each other. They actually need to be defined separately in order to work. The comparison operators don't have that problem. And in the cases where the arithmetic operations are essentially being passed on to a member variable such that it's just the operator itself that's changing, and the code is otherwise the same, the fact that opBinary takes a string for the operator makes it trivial to use string mixins so that you only need one function body for all of the operators, whereas in the cases where you can't do that (e.g. the operation involves multiple member variables), you can declare separate functions. The increment and decrement operators are in a similar boat to the comparison operators in that post and pre can be derived from a single function. So, it's not just the comparison operators that got combined. In the cases where it made sense to combine operators, they were combined, and in the cases where it didn't make sense, they weren't. It would be nice if more could be combined, but most of them actually need to be separate to work. Fortunately though, some of them can be combined, and those were combined, which makes operator overloading in D easier and less error-prone. - Jonathan M Davis
Sep 27 2016
parent reply Chris Wright <dhasenan gmail.com> writes:
On Tue, 27 Sep 2016 23:05:54 -0700, Jonathan M Davis via Digitalmars-d
wrote:

 On Wednesday, September 28, 2016 03:28:50 Minty Fresh via Digitalmars-d
 wrote:
 Lastly, if operators are intended to behave so strictly, why does this
 not extend then to binary arithmetic operators (+, -, *, /, %, etc.)
 They don't follow the same rules as the binary relational operators,
 after all.
It's not possible in the general case to define the arithmetic operators as functions of each other. They actually need to be defined separately in order to work.
Specifically for making efficient programs. Increment, decrement, and test for equality is sufficient mathematically, but we want programs that terminate in our lifetimes. </pedantry>
Sep 28 2016
parent Guillaume Boucher <guillaume.boucher.d gmail.com> writes:
On Wednesday, 28 September 2016 at 14:27:58 UTC, Chris Wright 
wrote:
 Increment, decrement, and
 test for equality is sufficient mathematically, but we want 
 programs that
 terminate in our lifetimes.
 </pedantry>
Only for BigInts you need those three. For ints decrement is not needed. And for most other data types increment/decrement is not sufficient, e.g. for reals or any kind of vectors/matrices.
Sep 28 2016
prev sibling parent reply pineapple <meapineapple gmail.com> writes:
On Wednesday, 28 September 2016 at 03:28:50 UTC, Minty Fresh 
wrote:
 Using strings and mixins does have quite a number of downsides. 
 The additional work required to past the DSL aside, you also 
 usually lose the scope in which things are declared (especially 
 if you wish to reference or declare variables/functions/other 
 constructs within your DSL), error reporting becomes much less 
 precise, and the transition between the outer code and the 
 inner DSL becomes jarring (especially in terms of syntax 
 highlighting).

 That said, I love the fact D has a separate operator for 
 concatenation. It's extremely useful to not have that ambiguity.

 Another thought is, operators not behaving as expected doesn't 
 strike me as a failure of the language, given the language 
 supports operator overloading. It's a failure in documentation 
 to explain what the operators are intended to do, or a failure 
 in implementation to behave as they should.
I agree that opCmp has the benefit of unambiguity, but I still think Minty makes very good points. I think the cleanest possible solution would be to allow comparison operators to be overridden with opBinary and opBinaryRight, as well, but use opCmp and opEquals instead if they exist. I can't think of any way this would break existing code. On Wednesday, 28 September 2016 at 09:48:48 UTC, Matthias Bentrup wrote:
 In Mathematics the comparison operators are also commonly used 
 for semi orders, which cannot be implemented by opCmp, because 
 opCmp has no way to indicate that two values are incomparable.

 Interestingly the floating point types are semi ordered (due to 
 NaNs), and for those D has some (non-overridable and 
 deprecated) operators like !<, which would be easily extendable 
 to any semi order, whereas the suggested replacement (i.e. test 
 for NaNs manually) works only on floats.
It's probably a terrible idea, but I'd love if those FP comparison operators would be de-deprecated and made possible to overload using opBinary. On Wednesday, 28 September 2016 at 06:05:54 UTC, Jonathan M Davis wrote:
 The increment and decrement operators are in a similar boat to 
 the comparison operators in that post and pre can be derived 
 from a single function. So, it's not just the comparison 
 operators that got combined.
Incidentally, I'm a little surprised and disappointed that D doesn't allow pre- and postfix operators to be separately overloaded. Postfix operators should default to their current behavior, where `x<op>` is the same as `auto t = x; x = <op>x; return t;` where prefix unary <op> is defined, but I also think it'd be fantastic if we introduced an opUnaryPostfix override. (And should that be done, for the sake of clarity, it might be a good idea deprecate usage of opUnary in favor of calling the method opUnaryPrefix.)
Sep 28 2016
next sibling parent pineapple <meapineapple gmail.com> writes:
I'd also like to point out a generally sound design principle:

Give the programmer as much power and flexibility as possible - 
but don't forget to provide tools for simplifying common use 
cases, and don't forget to define sensible defaults.

It makes a lot of sense that opCmp and opEquals exist, they fit 
the by-far-most-common use case perfectly, but they aren't always 
flexible enough for what the programmer wants to do. What if 
comparison operators should return something other than booleans? 
What if `!=` should be implemented differently from `==`? These 
overrides great tools to have, but it would be better if they 
weren't the only options we had.

Similarly, it makes a lot of sense that postfix operators are 
rewritten in terms of prefix operators, but that's not always 
flexible enough for what the programmer wants to do. It's a great 
default to have, but it would be better if we also had the option 
to define our own distinct behaviors for postfix operators.
Sep 28 2016
prev sibling parent Chris Wright <dhasenan gmail.com> writes:
On Wed, 28 Sep 2016 10:06:43 +0000, pineapple wrote:
 I think the cleanest possible solution would be to allow comparison
 operators to be overridden with opBinary and opBinaryRight, as well, but
 use opCmp and opEquals instead if they exist. I can't think of any way
 this would break existing code.
What happens with this? struct MyInt { int value; MyInt opBinary(string op)(MyInt other) { return MyInt(mixin("value " ~ op ~ " other.value")); } } Obvious pattern for wrapping a value. Comparisons used to be unsupported, producing an appropriate error message: Error: need member function opCmp() for struct MyInt to compare Now they produce a different, opaque error message, which will have to be created, but the current equivalent is: Error: recursive opCmp expansion That's not a breakage, but it is an unfortunate direction for the quality of error messages.
Sep 28 2016
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/27/2016 6:18 PM, Minty Fresh wrote:
 So, I'm just interested in other people's thoughts are on the subject, and
 whether there are any plans to allow overloading these operators separately.
The limitations are deliberate based on the idea that comparison operators need to be consistent and predictable, and should have a close relationship to the mathematical meaning of the operators. Overloading <= to mean something other than "less than or equal" is considered poor style in D, and the same goes for the other arithmetic operators. The use of them to create DSLs (a technique called "expression templates" in C++) is discouraged in D, for several reasons. The recommended way to create DSLs in D is to parse strings using CTFE. An excellent example of that is the std.regex package. There are no plans to change this.
Sep 27 2016
next sibling parent reply Matthias Bentrup <matthias.bentrup googlemail.com> writes:
On Wednesday, 28 September 2016 at 04:02:59 UTC, Walter Bright 
wrote:
 The limitations are deliberate based on the idea that 
 comparison operators need to be consistent and predictable, and 
 should have a close relationship to the mathematical meaning of 
 the operators.
In Mathematics the comparison operators are also commonly used for semi orders, which cannot be implemented by opCmp, because opCmp has no way to indicate that two values are incomparable. Interestingly the floating point types are semi ordered (due to NaNs), and for those D has some (non-overridable and deprecated) operators like !<, which would be easily extendable to any semi order, whereas the suggested replacement (i.e. test for NaNs manually) works only on floats.
Sep 28 2016
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 28.09.2016 11:48, Matthias Bentrup wrote:
 On Wednesday, 28 September 2016 at 04:02:59 UTC, Walter Bright wrote:
 The limitations are deliberate based on the idea that comparison
 operators need to be consistent and predictable, and should have a
 close relationship to the mathematical meaning of the operators.
In Mathematics the comparison operators are also commonly used for semi orders, which cannot be implemented by opCmp, because opCmp has no way to indicate that two values are incomparable. ...
Yes it does. float opCmp(S rhs){ return float.nan; // incomparable }
Sep 28 2016
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/28/2016 2:48 AM, Matthias Bentrup wrote:
 In Mathematics the comparison operators are also commonly used for semi orders,
 which cannot be implemented by opCmp, because opCmp has no way to indicate that
 two values are incomparable.

 Interestingly the floating point types are semi ordered (due to NaNs), and for
 those D has some (non-overridable and deprecated) operators like !<, which
would
 be easily extendable to any semi order, whereas the suggested replacement (i.e.
 test for NaNs manually) works only on floats.
I'm aware of the limitation, and a fair amount of thought was given on it, but the solution used generally for unordered is to test for it separately, and people seem happy with it. The !<, etc., operators have been an utter failure (not a failure technically, but people found them hopelessly confusing and would not use them).
Sep 28 2016
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 28.09.2016 06:02, Walter Bright wrote:
 On 9/27/2016 6:18 PM, Minty Fresh wrote:
 So, I'm just interested in other people's thoughts are on the subject,
 and
 whether there are any plans to allow overloading these operators
 separately.
The limitations are deliberate based on the idea that comparison operators need to be consistent and predictable, and should have a close relationship to the mathematical meaning of the operators. Overloading <= to mean something other than "less than or equal" is considered poor style in D, and the same goes for the other arithmetic operators. ...
The restrictions enforce that <= computes a boolean result. "less than or equal" is not necessarily the same as "decide /now/ whether this is less than or equal and give me a boolean". The restriction is annoying if you are implementing e.g. symbolic algebra. opCmp is a good thing to have for the common case, but why disable opBinary?
 The use of them to create DSLs (a technique called "expression
 templates" in C++) is discouraged in D, for several reasons. The
 recommended way to create DSLs in D is to parse strings using CTFE.
One anecdote: In the big-O library discussion, my initial proposal relied on string parsing. Andrei promptly criticized this and used operator overloading instead.
 An excellent example of that is the std.regex package.
 ...
It's actually a bad example, because it is irrelevant: it is obviously a bad idea to implement regex using operator overloading, because the regex operators have no D equivalent. Assume I have two symbolic expressions a and b: Expression a=variable("a"), b=variable("b"); Why should I be allowed to do auto c = a + b; // symbolic value a + b but not auto d = a <= b; // symbolic value a <= b The string parsing approach is not useful here: how do I use existing expressions that are accessible in the scope to build new expressions?
Sep 28 2016
next sibling parent John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 28 September 2016 at 13:58:35 UTC, Timon Gehr wrote:
 Assume I have two symbolic expressions a and b:

 Expression a=variable("a"), b=variable("b");

 Why should I be allowed to do

 auto c = a + b; // symbolic value a + b

 but not

 auto d = a <= b; // symbolic value a <= b

 The string parsing approach is not useful here: how do I use 
 existing expressions that are accessible in the scope to build 
 new expressions?
Thanks for expressing this so clearly. This is exactly the sort of thing I want to be able to do.
Sep 28 2016
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/28/2016 6:58 AM, Timon Gehr wrote:
 An excellent example of that is the std.regex package.
It's actually a bad example, because it is irrelevant: it is obviously a bad idea to implement regex using operator overloading, because the regex operators have no D equivalent.
Yet this "obviously bad" idea regularly resurfaces as a cool use of expression templates and respected people in the industry like it and advocate it.
 Assume I have two symbolic expressions a and b:

 Expression a=variable("a"), b=variable("b");

 Why should I be allowed to do

 auto c = a + b; // symbolic value a + b

 but not

 auto d = a <= b; // symbolic value a <= b
Because there is no way to stop the former but still have operator overloading.
 The string parsing approach is not useful here: how do I use existing
 expressions that are accessible in the scope to build new expressions?
You seem to be asking for expression templates. They do actually work in D, but I recommend against them. To reiterate, operator overloading exists in D to support the inclusion of arithmetic library types. Any other purpose is discouraged, and that includes expression templates and things like << for iostreams. AST macros are an alternative to expression templates. Having AST macros has been proposed before multiple times, and has been debated at length. I haven't seen any new information that would justify reopening the issue.
Sep 28 2016
next sibling parent reply pineapple <meapineapple gmail.com> writes:
On Wednesday, 28 September 2016 at 20:16:08 UTC, Walter Bright 
wrote:
 Because there is no way to stop the former but still have 
 operator overloading.

 To reiterate, operator overloading exists in D to support the 
 inclusion of arithmetic library types. Any other purpose is 
 discouraged, and that includes expression templates and things 
 like << for iostreams.
This is an obsolete way of thinking about operators. Operator overloading exists to make the programmer's life easier, and limiting the ways in which a valuable tool can be used drives people to languages which allow them to be more expressive. For my job I write Python. We use a database layer called sqlalchemy that allows us to express queries by writing, for example, `session.query(some_table).filter(row1 == row2)` and I cannot begin to express how useful this is when writing code, when maintaining code, and when attempting to understand code that someone else wrote. The objective should never be to stop the programmer from doing something because you personally dislike the practice.
Sep 28 2016
parent reply Russel Winder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Wed, 2016-09-28 at 20:30 +0000, pineapple via Digitalmars-d wrote:
 On Wednesday, 28 September 2016 at 20:16:08 UTC, Walter Bright=C2=A0
 wrote:
=20
 Because there is no way to stop the former but still have=C2=A0
 operator overloading.
=20
 To reiterate, operator overloading exists in D to support the=C2=A0
 inclusion of arithmetic library types. Any other purpose is=C2=A0
 discouraged, and that includes expression templates and things=C2=A0
 like << for iostreams.
=20 This is an obsolete way of thinking about operators. Operator=C2=A0 overloading exists to make the programmer's life easier, and=C2=A0 limiting the ways in which a valuable tool can be used drives=C2=A0 people to languages which allow them to be more expressive.
Definitely, yes.=C2=A0 However, this has come up many times, and every time Walter says "no, it's wrong". Whilst the C++ iostreams << may have problems, using this as a single point argument as to why overloading fails in all other cases except numeric arithmetic is bad philosophy. In my view this is holding D back.
 For my job I write Python. We use a database layer called=C2=A0
 sqlalchemy that allows us to express queries by writing, for=C2=A0
 example, `session.query(some_table).filter(row1 =3D=3D row2)` and I=C2=A0
 cannot begin to express how useful this is when writing code,=C2=A0
 when maintaining code, and when attempting to understand code=C2=A0
 that someone else wrote.
Definitely. I spend a lot of my time trying to inculcate people into DSL-based thinking as an extension of abstraction and leading towards understanding and modelling the solution to problems in the domain. Python has it's problems, C++ more, but this is a far superior way of going than the Java approach of "operator overloading is too hard for programmers to deal with so let's ban it". Hence Groovy, Scala, Kotlin, Ceylon, etc. all of which bring back this feature Java eschewed from C++ =E2=80=93 possibly because the Oak developers had their problems.=C2=A0
 The objective should never be to stop the programmer from doing=C2=A0
 something because you personally dislike the practice.
I guess it depends on whether the language is wanting to gain traction in the market or remain a pet project. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 29 2016
parent reply Minty Fresh <mint fresh.com> writes:
On Thursday, 29 September 2016 at 11:29:55 UTC, Russel Winder 
wrote:
 However, this has come up many times, and every time Walter 
 says "no, it's wrong". Whilst the C++ iostreams << may have 
 problems, using this as a single point argument as to why 
 overloading fails in all other cases except numeric arithmetic 
 is bad philosophy. In my view this is holding D back.
To add some thoughts to this, The use of << being bad is purely a matter of opinion. If you believe that << is to only be used for bit-shifting operations, you might hold the view that it is bad. On the other hand, if you come from a background like Haskell or Ruby, you might have a very different opinion. ie. In Ruby, << is named the shovel operator. It's uses are things like appending an element into an Array. Hence, a less opinionated point is necessary here.
Sep 29 2016
parent reply Russel Winder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thu, 2016-09-29 at 11:50 +0000, Minty Fresh via Digitalmars-d wrote:
 On Thursday, 29 September 2016 at 11:29:55 UTC, Russel Winder=C2=A0
 wrote:
=20
 However, this has come up many times, and every time Walter=C2=A0
 says "no, it's wrong". Whilst the C++ iostreams << may have=C2=A0
 problems, using this as a single point argument as to why=C2=A0
 overloading fails in all other cases except numeric arithmetic=C2=A0
 is bad philosophy. In my view this is holding D back.
=20 To add some thoughts to this, =20 The use of << being bad is purely a matter of opinion. If you believe that << is to only be used for bit-shifting=C2=A0 operations, you might hold the view that it is bad.
But, but, but, << means very much less than, everyone knows this. What is this bitshifting of which you speak. !
 On the other hand, if you come from a background like Haskell or=C2=A0
 Ruby, you might have a very different opinion.
Is there anyone from an Haskell background here. :-) Anyway everyone who wants to make Haskell code mainstream is using Frege.
 ie.
 In Ruby, << is named the shovel operator. It's uses are things=C2=A0
 like appending an element into an Array.
Groovy, and indeed Python, likewise. We ignore the mess Algol68 and Scala have got themselves into with this.
=20
 Hence, a less opinionated point is necessary here.
Opinionated is not always bad. Look at Go, the developers know that there is no sane way of doing generics so they ban it. Also they know that exceptions are totally incomprehensible to all programmers so they ban them. Rust developers know that all memory handling must be explicit all the world falls apart. Opinionated languages clearly get traction =E2=80=93 not usually because of the opinions, it has to be said, = more usually because of the amount of money thrown at marketing. Except Python, obviously. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 29 2016
parent pineapple <meapineapple gmail.com> writes:
On Thursday, 29 September 2016 at 12:20:42 UTC, Russel Winder 
wrote:
 Opinionated is not always bad. Look at Go, the developers know 
 that
 there is no sane way of doing generics so they ban it. Also 
 they know
 that exceptions are totally incomprehensible to all programmers 
 so they
 ban them. Rust developers know that all memory handling must be
 explicit all the world falls apart. Opinionated languages 
 clearly get
 traction – not usually because of the opinions, it has to be 
 said, more
 usually because of the amount of money thrown at marketing. 
 Except
 Python, obviously.
Reminds me of this - https://twitter.com/paniq/status/757951588057096192
Sep 29 2016
prev sibling next sibling parent Minty Fresh <mint fresh.com> writes:
On Wednesday, 28 September 2016 at 20:16:08 UTC, Walter Bright 
wrote:
 To reiterate, operator overloading exists in D to support the 
 inclusion of arithmetic library types. Any other purpose is 
 discouraged, and that includes expression templates and things 
 like << for iostreams.
It seeds rather harsh to discourage every possible use case of a feature sans one, simply because one does not agree with the others.
Sep 28 2016
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 28.09.2016 22:16, Walter Bright wrote:
 On 9/28/2016 6:58 AM, Timon Gehr wrote:
 An excellent example of that is the std.regex package.
It's actually a bad example, because it is irrelevant: it is obviously a bad idea to implement regex using operator overloading, because the regex operators have no D equivalent.
Yet this "obviously bad" idea regularly resurfaces as a cool use of expression templates and respected people in the industry like it and advocate it. ...
This is not surprising. C++ has no good options.
 Assume I have two symbolic expressions a and b:

 Expression a=variable("a"), b=variable("b");

 Why should I be allowed to do

 auto c = a + b; // symbolic value a + b

 but not

 auto d = a <= b; // symbolic value a <= b
Because there is no way to stop the former but still have operator overloading. ...
What's wrong with that usage? (This is NOT expression templates.)
 The string parsing approach is not useful here: how do I use existing
 expressions that are accessible in the scope to build new expressions?
You seem to be asking for expression templates.
No. It's symbolic computation at run time. Think Wolfram Mathematica.
Sep 28 2016
next sibling parent Minty Fresh <mint fresh.com> writes:
On Wednesday, 28 September 2016 at 20:40:49 UTC, Timon Gehr wrote:
 This is not surprising. C++ has no good options.
This is further made worse by some C++'s more inane design decisions (ie. allowing overloading of the comma operator).
Sep 28 2016
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/28/2016 1:40 PM, Timon Gehr wrote:
 What's wrong with that usage?
Because then something other than comparison is happening with <=, <, >, >= and there'll be nothing in the code to give the user a hint.
 (This is NOT expression templates.)
Right, but it's an enabler of expression templates. Discussion of more powerful operator overloading cannot be divorced from expression templates, and once ETs are in we'll be stuck with them forever. D has many very powerful modeling abilities, but so far we've tried to stay away from things that make context-free user understanding of code unduly difficult. It should not be necessary to use an IDE to understand code. In that category are things like text macros, AST macros, user-defined syntax, non-arithmetic operator overloading, and expression templates.
Sep 28 2016
next sibling parent reply Minty Fresh <mint fresh.com> writes:
On Thursday, 29 September 2016 at 04:15:32 UTC, Walter Bright 
wrote:
 On 9/28/2016 1:40 PM, Timon Gehr wrote:
 What's wrong with that usage?
Because then something other than comparison is happening with <=, <, >, >= and there'll be nothing in the code to give the user a hint.
There's also nothing to give the user a hint that binary arithmetic operators may also not do what they expect them to do. Going further, there may be nothing to give the user a hint that a named function doesn't to what its name suggests. All of the above are shortcomings in documentation, or short comings in implementation. Even with the current system of using `opCmp`, it's still possible to implement these operators such that they behave in a way that would confound the user (ie. have their results be nondeterministic, external side effects, etc.)
 D has many very powerful modeling abilities, but so far we've 
 tried to stay away from things that make context-free user 
 understanding of code unduly difficult. It should not be 
 necessary to use an IDE to understand code.
No, you're right. It's not the responsibility of the IDE to perform such tasks. It's the responsibility of the documentation. D is already is such a state the language is difficult for a context-free user without access to documentation. Even the standard library. Especially the standard library. Things like `.each` in std.algorithm returning void, whereas the bizarrely named `.tee` in std.range actually retuning the input range. Things like the `SList` and `DList` types defined in std.container requiring explicit initialization to work. Things like the behavior and semantics of type tuples (or alias lists). Things like the differences between `.byLine` vs `.byLineCopy` in std.stdio. All of these rely on the developer having documentation. There's no way around it. D as a language is already way too complex to do anything without it. This applies to operator overloads just like everything else. They're just syntactic sugar for functions. Documenting their behavior is just as necessary.
Sep 28 2016
parent Mike Parker <aldacron gmail.com> writes:
On Thursday, 29 September 2016 at 04:39:37 UTC, Minty Fresh wrote:

 This applies to operator overloads just like everything else. 
 They're just syntactic sugar for functions. Documenting their 
 behavior is just as necessary.
I disagree with this. Operators are different in that the symbols themselves already have meaning and are a core part of the language. When I see a function in code that was written by someone else, I have no idea what it really does, no matter how it was named, until I pull up the documentation or the source and actually read it. I expect that I'm going to have to do that. Using operators in ways they were not intended to be used is breaking my expectations. When I'm scanning D code and see a '+', I'm going to think addition (and not concatenation or appending or anything else). It isn't going to occur to me that the types involved are doing something completely different and I ought to look in the documentation to see what that is. And I shouldn't have to worry about it. That sort of cognitive disruption is really annoying. In D1, operators were overloaded *by name* and not by symbol. I loved that, because it made it quite clear that opAdd is an addition and doing something different with it would be akin to having a function named printFoo launching an audio player. And if printFoo *did* launch an audio player, I'm quite confident most programmers would consider the function horribly misnamed. The same applies to operators, as I see it.
Sep 28 2016
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Wednesday, September 28, 2016 21:15:32 Walter Bright via Digitalmars-d 
wrote:
 Because then something other than comparison is happening with <=, <, >, >=
 and there'll be nothing in the code to give the user a hint.
[snip]
 D has many very powerful modeling abilities, but so far we've tried to stay
 away from things that make context-free user understanding of code unduly
 difficult. It should not be necessary to use an IDE to understand code.
A related issue is generic code. Having the same operator or function name mean essentially the same thing for every type that has it is required for generic code to work. To some extent, that's also checked by having the semantics of the code checked (e.g. that front returns something as opposed to being void or that popFront takes no arguments), but there's only so much that can be done there. And no, even then, you can't guarantee that the function in question operates the way that the generic code expects. But if common function names mean the same thing and act the same way for types in general, then they play well with generic code, whereas as soon as someone takes a common function and makes it do something different from what's normal, it does not play well with generic code at all. Overloaded operators are the prime example of this, because there is a clear expectation for what their basic behaviors are, and they're functions that are built into the language. Next in line would be extremely common idioms such as the range-based functions. Once you start getting to less common stuff, then the issue of whether a function with a particular name acts the same way in one library as another is significantly diminished, but for the common stuff, it's critical for generic code that folks don't go and make common functions operate in a way that is inconsistent with how they would function on most every other type out there and how everyone is going to expect them to behave when they see them. Having a type implement something like expression templates is an utter disaster for generic code, just like it's a disaster if front does something like call popFront every time that it's called. Consistent semantics for common functions is very important for generic code as well as for code legibility and maintainability. - Jonathan M Davis
Sep 28 2016
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 29.09.2016 06:15, Walter Bright wrote:
 On 9/28/2016 1:40 PM, Timon Gehr wrote:
 What's wrong with that usage?
Because then something other than comparison is happening with <=,
You also complained about '+'.
 <, >,
= and there'll be nothing in the code to give the user a hint.
...
Actually, comparison is precisely what is happening. The hint about what is happening precisely is that the entire codebase does symbolic computations all over the place, and it is very clear what the involved types are.
 (This is NOT expression templates.)
Right, but it's an enabler of expression templates. Discussion of more powerful operator overloading cannot be divorced from expression templates, and once ETs are in we'll be stuck with them forever. ...
They work today, just not with comparison operators.
 D has many very powerful modeling abilities, but so far we've tried to
 stay away from things that make context-free user understanding of code
 unduly difficult. It should not be necessary to use an IDE to understand
 code.
 ...
That is and has always been the responsibility of the programmer. (IDEs don't even help that much.)
 In that category are things like text macros, AST macros, user-defined
 syntax, non-arithmetic operator overloading, and expression templates.
What's the definition of "arithmetic" here?
Sep 29 2016
parent reply Chris Wright <dhasenan gmail.com> writes:
On Thu, 29 Sep 2016 10:41:38 +0200, Timon Gehr wrote:

 On 29.09.2016 06:15, Walter Bright wrote:
 On 9/28/2016 1:40 PM, Timon Gehr wrote:
 (This is NOT expression templates.)
Right, but it's an enabler of expression templates. Discussion of more powerful operator overloading cannot be divorced from expression templates, and once ETs are in we'll be stuck with them forever. ...
They work today, just not with comparison operators.
To take it the other way, D could enforce that the return type of arithmetic operators is compatible with at least one of the operands -- by implicit cast or constructor or being the same type. Wouldn't that be fun?
Sep 29 2016
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 30.09.2016 03:15, Chris Wright wrote:
 On Thu, 29 Sep 2016 10:41:38 +0200, Timon Gehr wrote:

 On 29.09.2016 06:15, Walter Bright wrote:
 On 9/28/2016 1:40 PM, Timon Gehr wrote:
 (This is NOT expression templates.)
Right, but it's an enabler of expression templates. Discussion of more powerful operator overloading cannot be divorced from expression templates, and once ETs are in we'll be stuck with them forever. ...
They work today, just not with comparison operators.
To take it the other way, D could enforce that the return type of arithmetic operators is compatible with at least one of the operands -- by implicit cast or constructor or being the same type.
It wouldn't infer with any of my use cases, but I don't see the point.
 Wouldn't that be fun?
Certainly.
Sep 30 2016
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 30.09.2016 21:02, Timon Gehr wrote:
 On 30.09.2016 03:15, Chris Wright wrote:
 ...
 Wouldn't that be fun?
Certainly.
On a related note: alias Seq(T...)=T; struct S{ int x; S opBinary(string op:"+",T...)(T args){ S r=this; foreach(a;args) r.x+=a; return r; } } void main(){ import std.stdio; assert(S(1) + Seq!(2,3,4) == S(10)); }
Sep 30 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/30/2016 03:18 PM, Timon Gehr wrote:
 On 30.09.2016 21:02, Timon Gehr wrote:
 On 30.09.2016 03:15, Chris Wright wrote:
 ...
 Wouldn't that be fun?
Certainly.
On a related note: alias Seq(T...)=T; struct S{ int x; S opBinary(string op:"+",T...)(T args){ S r=this; foreach(a;args) r.x+=a; return r; } } void main(){ import std.stdio; assert(S(1) + Seq!(2,3,4) == S(10)); }
That looks awfully cool! -- Andrei
Sep 30 2016
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 30.09.2016 22:14, Andrei Alexandrescu wrote:
 On 09/30/2016 03:18 PM, Timon Gehr wrote:
 On 30.09.2016 21:02, Timon Gehr wrote:
 On 30.09.2016 03:15, Chris Wright wrote:
 ...
 Wouldn't that be fun?
Certainly.
On a related note: alias Seq(T...)=T; struct S{ int x; S opBinary(string op:"+",T...)(T args){ S r=this; foreach(a;args) r.x+=a; return r; } } void main(){ import std.stdio; assert(S(1) + Seq!(2,3,4) == S(10)); }
That looks awfully cool! -- Andrei
[my code here]
Sep 30 2016
prev sibling parent Russel Winder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Wed, 2016-09-28 at 21:15 -0700, Walter Bright via Digitalmars-d
wrote:
 On 9/28/2016 1:40 PM, Timon Gehr wrote:
=20
 What's wrong with that usage?
=20 Because then something other than comparison is happening with <=3D, <,
, >=3D and=C2=A0
there'll be nothing in the code to give the user a hint.
This is a very "tunnel vision" view of programming language and the way programs are constructed and perceived. But sadly I know we have been round this many times, and you will not be changing you viewpoint. But even though I know nothing will change, I feel required to take on the challenge again. Until you cite psychology of programming experimental data to back up any position, it is all just opinion and personal experience. I am happy with << as very much less than, or output depending on context, you are not. But it is bad philosophy for me to say << is comprehensible to me and so it is comprehensible to everyone, and equally bad philosophy for you to say the same with s/comprehensible/incomprehensible/. This sort of thing happened in Python with the reduce function, leaving Python 3 in a truly inconsistent position regarding higher order functions. So when it comes to writing DSLs I'll stick with Python and Groovy, until D gets it right. [=E2=80=A6] --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 29 2016
prev sibling parent reply Martin Nowak <code dawg.eu> writes:
On Wednesday, 28 September 2016 at 20:16:08 UTC, Walter Bright 
wrote:
 On 9/28/2016 6:58 AM, Timon Gehr wrote:
 An excellent example of that is the std.regex package.
It's actually a bad example, because it is irrelevant: it is obviously a bad idea to implement regex using operator overloading, because the regex operators have no D equivalent.
Yet this "obviously bad" idea regularly resurfaces as a cool use of expression templates and respected people in the industry like it and advocate it.
 Assume I have two symbolic expressions a and b:

 Expression a=variable("a"), b=variable("b");

 Why should I be allowed to do

 auto c = a + b; // symbolic value a + b

 but not

 auto d = a <= b; // symbolic value a <= b
Because there is no way to stop the former but still have operator overloading.
The fact that it's not possible to overload < but have to use the ternary opCmp is even a performance problem. All std algorithms only use less as a predicate, leading to lots of unnecessary cycles when e.g. sorting UDTs. While I agree with your point on expression templates, overloading comparison operators has valid use cases.
Oct 01 2016
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/1/16 3:13 AM, Martin Nowak wrote:
 The fact that it's not possible to overload < but have to use the
 ternary opCmp is even a performance problem. All std algorithms only use
 less as a predicate, leading to lots of unnecessary cycles when e.g.
 sorting UDTs.
I've also been often annoyed by having to write return a < b ? -1 : a > b; in e.g. checkedint. Does inlining take care of this? -- Andrei
Oct 01 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/1/16 7:33 AM, Andrei Alexandrescu wrote:
 On 10/1/16 3:13 AM, Martin Nowak wrote:
 The fact that it's not possible to overload < but have to use the
 ternary opCmp is even a performance problem. All std algorithms only use
 less as a predicate, leading to lots of unnecessary cycles when e.g.
 sorting UDTs.
I've also been often annoyed by having to write return a < b ? -1 : a > b; in e.g. checkedint. Does inlining take care of this? -- Andrei
Apparently in dmd the generated code is less efficient: https://goo.gl/OWxbA0. In gdc it's the same: https://godbolt.org/g/NmUyXM. I couldn't test with ldc, http://ldc.acomirei.ru seems down. -- Andrei
Oct 01 2016
prev sibling parent pineapple <meapineapple gmail.com> writes:
On Saturday, 1 October 2016 at 07:13:39 UTC, Martin Nowak wrote:
 The fact that it's not possible to overload < but have to use 
 the ternary opCmp is even a performance problem. All std 
 algorithms only use less as a predicate, leading to lots of 
 unnecessary cycles when e.g. sorting UDTs.
On Saturday, 1 October 2016 at 11:53:07 UTC, Andrei Alexandrescu wrote:
 Apparently in dmd the generated code is less efficient: 
 https://goo.gl/OWxbA0. In gdc it's the same: 
 https://godbolt.org/g/NmUyXM. I couldn't test with ldc, 
 http://ldc.acomirei.ru seems down. -- Andrei
On Saturday, 1 October 2016 at 06:46:31 UTC, Russel Winder wrote:
 This debate is about whether D constrains people as Java does 
 or whether it enables people as C++ and Python do.

 Or use C++ or Python which allow for this. Fine, end of D 
 having a future amongst a large section of the programming 
 population. This is fine. Unless D wants to be a player in this 
 game.

 This has already been done, read the thread. SQLAlchemy. The 
 expression language is a a lovely builder DSL for constructing 
 SQL entirely in Python with no parser overhead. No operator 
 overloading, no DSL for builder languages. See same on the JVM: 
 in Java you can't do it, Kotlin, Ceylon, Scala, Groovy, do it 
 beautifully, and a lot of people do.
This isn't a PR yet because it's not nearly ready for general consumption, but these are all good points and I'd greatly appreciate if you would all please take a few minutes to express them in the DIP and get the changes merged so that we can have something that lays out clearly the pros and cons of this change. https://github.com/pineapplemachine/DIPs/blob/operator_overload_expansion/DIPs/DIP1003.md
Oct 01 2016
prev sibling next sibling parent Minty Fresh <mint fresh.com> writes:
On Wednesday, 28 September 2016 at 04:02:59 UTC, Walter Bright 
wrote:
 The use of them to create DSLs (a technique called "expression 
 templates" in C++) is discouraged in D, for several reasons. 
 The recommended way to create DSLs in D is to parse strings 
 using CTFE.
I don't really come from a C++ background. Actually, I have a strong distaste for the language. Professionally, I word with Ruby. Again, string DSLs face a number of issues. A few that come to mind are: 1. A parser + code generator must be implemented, which is a lot of additional work. 2. The quality and precision of error messages degrades. 3. You loose the ability to perform actions like making declarations within the context of the DSL (ie. assigning a commonly re-used expression to a variable), unless your DSL is turing complete.
 An excellent example of that is the std.regex package.
You know, if someone had managed to implement a regex DSL using operator overloading, something must have gone _terribly_ wrong. Regex is traditionally done in strings, lest the language supports regex literals.
Sep 28 2016
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2016-09-28 06:02, Walter Bright wrote:

 The limitations are deliberate based on the idea that comparison
 operators need to be consistent and predictable, and should have a close
 relationship to the mathematical meaning of the operators. Overloading
 <= to mean something other than "less than or equal" is considered poor
 style in D, and the same goes for the other arithmetic operators.
If that is not allowed, why is this allowed: struct MyInt { int value; MyInt opBinary(string op)(MyInt rhs) if (op == "+") { return MyInt(value - rhs.value); } } assert(MyInt(3) + MyInt(3) == MyInt(0)); The language you just provide a set of tools, then it's up the to the programmer to do what he/she wants to do.
 The use of them to create DSLs (a technique called "expression
 templates" in C++) is discouraged in D, for several reasons. The
 recommended way to create DSLs in D is to parse strings using CTFE.
That's one of the ugliest things about D. Because suddenly you will not have any help of any tools, like editors, IDEs, linters, syntax analysis and so on. One also needs to implement a complete parser, how many complete parsers do we have for D? -- /Jacob Carlborg
Sep 28 2016
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/28/2016 11:48 PM, Jacob Carlborg wrote:
 If that is not allowed, why is this allowed:
I.e. you can overload '+' to do bad things. Yes, you can, and as I replied upthread that can be done because there's no way to prevent that while having operator overloading at all. But that is not justification for allowing such disasters for the comparison operators. I.e. one weakness is not justification for opening the door to all weakness. Interestingly, by shutting the door on misuse of the comparison operators, it seems D has been successful in discouraging nutburger designs like overloading '+' to mean 'OR'.
 The language you just provide a set of tools, then it's up the to the
programmer
 to do what he/she wants to do.
That can be used to justify any feature at all.
 The use of them to create DSLs (a technique called "expression
 templates" in C++) is discouraged in D, for several reasons. The
 recommended way to create DSLs in D is to parse strings using CTFE.
That's one of the ugliest things about D. Because suddenly you will not have any help of any tools, like editors, IDEs, linters, syntax analysis and so on. One also needs to implement a complete parser, how many complete parsers do we have for D?
I know you really want AST macros for D. We've discussed that at length before. BTW, there's a CTFE parser generator for D around somewhere.
Sep 29 2016
next sibling parent reply pineapple <meapineapple gmail.com> writes:
On Thursday, 29 September 2016 at 07:58:26 UTC, Walter Bright 
wrote:
 On 9/28/2016 11:48 PM, Jacob Carlborg wrote:
 If that is not allowed, why is this allowed:
I.e. you can overload '+' to do bad things. Yes, you can, and as I replied upthread that can be done because there's no way to prevent that while having operator overloading at all. But that is not justification for allowing such disasters for the comparison operators. I.e. one weakness is not justification for opening the door to all weakness. Interestingly, by shutting the door on misuse of the comparison operators, it seems D has been successful in discouraging nutburger designs like overloading '+' to mean 'OR'.
 The language you just provide a set of tools, then it's up the 
 to the programmer
 to do what he/she wants to do.
That can be used to justify any feature at all.
This is not an argument to justify adding just any feature, it's an argument that it is idiocy to give a programmer a powerful tool, and then impose arbitrary limitations upon how they are allowed to use it. One of the most popular topics of discussion in this forum is "Why is D not more widely adopted?" and "What can we do to get broader adoption for D?" Perhaps one of the more obvious answers is: Do not prevent programmers from doing something solely on the basis that _you_ would not want to do it. I think camelCase is hideous, but does that mean I should forbid another programmer defining symbols in that style? Of course not. That they are able to write their code that way doesn't mean I have to, and doesn't mean I have to use or interface with their code. I agree that '+' should always mean addition and '~' should always mean concatenation, but does that mean I should forbid another programmer from defining them differently? Of course not. Just because they are able to do it that way doesn't mean I have to, or that I have to use their code. If I thought '>' and '<' should always mean arithmetic comparison, does that mean I should forbid another programmer from defining them differently? You need to understand that _you are not the only one writing code in this language_. Your use cases do not summarize all possible use cases. That you do not need to use a tool in a specific way is not a valid argument against allowing others to use the tool that way. Give us a rational argument. We are unconcerned with your personal dogma. What you refer to as a weakness I view as a strength. Programmers require more flexibility and expressiveness, not less.
Sep 29 2016
parent Jacob Carlborg <doob me.com> writes:
On 2016-09-29 11:31, pineapple wrote:

 This is not an argument to justify adding just any feature, it's an
 argument that it is idiocy to give a programmer a powerful tool, and
 then impose arbitrary limitations upon how they are allowed to use it.

 One of the most popular topics of discussion in this forum is "Why is D
 not more widely adopted?" and "What can we do to get broader adoption
 for D?"

 Perhaps one of the more obvious answers is: Do not prevent programmers
 from doing something solely on the basis that _you_ would not want to do
 it.

 I think camelCase is hideous, but does that mean I should forbid another
 programmer defining symbols in that style? Of course not. That they are
 able to write their code that way doesn't mean I have to, and doesn't
 mean I have to use or interface with their code. I agree that '+' should
 always mean addition and '~' should always mean concatenation, but does
 that mean I should forbid another programmer from defining them
 differently? Of course not. Just because they are able to do it that way
 doesn't mean I have to, or that I have to use their code.

 If I thought '>' and '<' should always mean arithmetic comparison, does
 that mean I should forbid another programmer from defining them
 differently?

 You need to understand that _you are not the only one writing code in
 this language_. Your use cases do not summarize all possible use cases.
 That you do not need to use a tool in a specific way is not a valid
 argument against allowing others to use the tool that way.

 Give us a rational argument. We are unconcerned with your personal
 dogma. What you refer to as a weakness I view as a strength. Programmers
 require more flexibility and expressiveness, not less.
Well said. -- /Jacob Carlborg
Sep 29 2016
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2016-09-29 09:58, Walter Bright wrote:

 I.e. you can overload '+' to do bad things. Yes, you can, and as I
 replied upthread that can be done because there's no way to prevent that
 while having operator overloading at all.

 But that is not justification for allowing such disasters for the
 comparison operators. I.e. one weakness is not justification for opening
 the door to all weakness.
You're using the same justification when rejecting most feature requests you don't like: you had one bad experience with C++ and therefore it must be banned for all eternity. It's not a valid argument.
 Interestingly, by shutting the door on misuse of the comparison
 operators, it seems D has been successful in discouraging nutburger
 designs like overloading '+' to mean 'OR'.
It's also shutting the door on doing a lot of useful things. My goal is no to use the comparison operators to mean something different than comparison. The goal is, for example, to build a corresponding SQL query out of an expression. But the == operator would still be used for equality. One major issue with using string literals is, if we use the SQL query as an example again, as follows: First try: auto bar = `"bar"`; auto query = "SELECT * FROM foo WHERE bar = " ~ bar; Is have the issue of SQL injection. Second try: auto bar = "bar"; auto foo = "foo"; auto q = query("SELECT * FROM foo WHERE bar = $1 AND foo = $2", bar, foo); This has the issue that the value and the place of where a value is used far away from each other in the code making it more difficult to read. This was "solved" in Rails by using an associative array mapping the column names to the values: foo = "foo" bar = "bar" Foo.where(bar: bar, foo: foo) That has the issue of only working with equality and "AND". Now way to do less than or "OR". Third try: auto foo = "foo"; auto bar = "bar"; Foo.where(q => q.foo == foo && q.bar == "bar"); The above expression would be translated to the query in the second example, with the values properly escaped. Now this is how I want the code to look like.
 The language you just provide a set of tools, then it's up the to the
 programmer
 to do what he/she wants to do.
That can be used to justify any feature at all.
 I know you really want AST macros for D. We've discussed that at length
 before.

 BTW, there's a CTFE parser generator for D around somewhere.
And that will handle all that the DMD parser does? I don't think so. -- /Jacob Carlborg
Sep 29 2016
parent Minty Fresh <mint fresh.com> writes:
On Thursday, 29 September 2016 at 12:54:54 UTC, Jacob Carlborg 
wrote:
 BTW, there's a CTFE parser generator for D around somewhere.
And that will handle all that the DMD parser does? I don't think so.
I agree with this entirely. Lest you have an entire D compiler implemented in CTFE (reductio ad absurdum), you're working with a limited subset of the language, and pose additional challenges for a developer trying to debug. Not to mention that string mixins render IDE features like code completion and error highlighting essentially unusable.
Sep 29 2016
prev sibling parent reply Sai <test test.com> writes:
 I.e. you can overload '+' to do bad things. Yes, you can, and 
 as I replied upthread that can be done because there's no way 
 to prevent that while having operator overloading at all.

 But that is not justification for allowing such disasters for 
 the comparison operators. I.e. one weakness is not 
 justification for opening the door to all weakness.
If I understand the issue correctly, one will not be able to overload <=, >, etc for symbolic math, like CAS (mimicking mathematica for example), how can I do it now? Wouldn't the current rules discourage someone from implementing CAS like library in D?
Sep 29 2016
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/29/2016 9:41 AM, Sai wrote:
 If I understand the issue correctly, one will not be able to overload <=, >,
etc
 for symbolic math, like CAS (mimicking mathematica for example), how can I do
it
 now?
a.isLessThan(b)
Sep 29 2016
next sibling parent reply Russel Winder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thu, 2016-09-29 at 10:52 -0700, Walter Bright via Digitalmars-d
wrote:
 On 9/29/2016 9:41 AM, Sai wrote:
=20
 If I understand the issue correctly, one will not be able to
 overload <=3D, >, etc
 for symbolic math, like CAS (mimicking mathematica for example),
 how can I do it
 now?
=20 =20 =C2=A0=C2=A0=C2=A0=C2=A0a.isLessThan(b)
How wonderfully Java. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 29 2016
parent reply Minty Fresh <mint fresh.com> writes:
On Thursday, 29 September 2016 at 18:07:37 UTC, Russel Winder 
wrote:
 On Thu, 2016-09-29 at 10:52 -0700, Walter Bright via 
 Digitalmars-d wrote:
 On 9/29/2016 9:41 AM, Sai wrote:
 
 If I understand the issue correctly, one will not be able to
 overload <=, >, etc
 for symbolic math, like CAS (mimicking mathematica for 
 example),
 how can I do it
 now?
    a.isLessThan(b)
How wonderfully Java.
Personally, I'm amused because this implies the prospect of: a.isGreaterThanOrEqualTo(b) I mean, there is an acceptable level of verbosity. This is not it.
Sep 29 2016
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, September 29, 2016 18:14:22 Minty Fresh via Digitalmars-d wrote:
 On Thursday, 29 September 2016 at 18:07:37 UTC, Russel Winder

 wrote:
 On Thu, 2016-09-29 at 10:52 -0700, Walter Bright via

 Digitalmars-d wrote:
 On 9/29/2016 9:41 AM, Sai wrote:
 If I understand the issue correctly, one will not be able to
 overload <=, >, etc
 for symbolic math, like CAS (mimicking mathematica for
 example),
 how can I do it
 now?
a.isLessThan(b)
How wonderfully Java.
Personally, I'm amused because this implies the prospect of: a.isGreaterThanOrEqualTo(b) I mean, there is an acceptable level of verbosity. This is not it.
Then you could always do something like a.myOp!"<"(b) and a.myOp!">="(b) if you still want to have the operator in there somewhere. You can name the functions whatever you want. You just can't use overloaded operators for it, since it would not be in line with what the operators are supposed to mean and be used for. - Jonathan M Davis
Sep 29 2016
next sibling parent Matthias Bentrup <matthias.bentrup googlemail.com> writes:
On Thursday, 29 September 2016 at 18:38:42 UTC, Jonathan M Davis 
wrote:
 Then you could always do something like a.myOp!"<"(b) and 
 a.myOp!">="(b) if you still want to have the operator in there 
 somewhere. You can name the functions whatever you want. You 
 just can't use overloaded operators for it, since it would not 
 be in line with what the operators are supposed to mean and be 
 used for.

 - Jonathan M Davis
Also with mixins and a CTFE D parser you could replace the operators by any desired function calls.
Sep 29 2016
prev sibling parent reply pineapple <meapineapple gmail.com> writes:
On Thursday, 29 September 2016 at 18:38:42 UTC, Jonathan M Davis 
wrote:
 You just can't use overloaded operators for it, since it would
 not be in line with what the operators are supposed to mean and
 be used for.
This is not a valid argument because what an operator is "supposed to mean" is up to the programmer who wishes to implement that operator for their data type. Not up to me. Not up to you. Your thinking like this limits D's viability for real-world code. Programmers do not care how you think they are supposed to use the language. They care only that they can get their job done in a way that makes sense to them. What makes sense to them will not be the same as what makes sense to you. Relinquish the notion that you or anyone can have the slightest idea what any language feature is "supposed to mean and be used for".
Sep 29 2016
next sibling parent Minty Fresh <mint fresh.com> writes:
On Thursday, 29 September 2016 at 19:11:55 UTC, pineapple wrote:
 Relinquish the notion that you or anyone can have the slightest 
 idea what any language feature is "supposed to mean and be used 
 for".
Basically what led to D's CTFE implementation in the first place, IIRC.
Sep 29 2016
prev sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, September 29, 2016 19:11:55 pineapple via Digitalmars-d wrote:
 On Thursday, 29 September 2016 at 18:38:42 UTC, Jonathan M Davis

 wrote:
 You just can't use overloaded operators for it, since it would
 not be in line with what the operators are supposed to mean and
 be used for.
This is not a valid argument because what an operator is "supposed to mean" is up to the programmer who wishes to implement that operator for their data type. Not up to me. Not up to you. Your thinking like this limits D's viability for real-world code. Programmers do not care how you think they are supposed to use the language. They care only that they can get their job done in a way that makes sense to them. What makes sense to them will not be the same as what makes sense to you. Relinquish the notion that you or anyone can have the slightest idea what any language feature is "supposed to mean and be used for".
Every language feature is designed with a purpose. Sometimes that purpose is broader than other times. And once the feature is there, you can do whatever is legal to do with the feature whether that was really what it was intended for or not, but if what you're trying to do goes against what the feature was designed for, don't expect to get support for making it do more stuff that goes against why it's in the language in the first place - especially when plenty of folks think that what you're trying to do is bad practice. The reality of the matter is that D's operator overloading was designed specifically so that you could overload the built-in operators to be used with your own types so that they could act like the built-in types. It was not intended or designed to allow for the symbols use for those operators to then be used for other arbitrary stuff that's unrelated to what they mean for the built-in types. The decisions made in how the operators are overloaded were geared entirely towards better supporting having your types act like built-in types, and none of it was designed with the idea that you would do arbitrary stuff via overloading the operators (which is why the language does stuff like derive some operators from others; it supports the goal of making them work like the built-in types, and supporting arbitrary usage of those operators was never a goal, so losing out on the ability is not considered to be a problem). The language can't stop you from doing at least some arbitrary stuff with them (like making + do subtraction), but the whole goal was for user-defined types to be able to act like the built-in types, and as such, it would make no sense to alter them towards being treated like symbols that you can do whatever you want with. And there are plenty of folks who think that overloading operators to do stuff fundamentally different from how they work for the built-in types is bad practice and consider it to be an abuse of operator overloading. So, the fact that D limits that is going to be viewed as positive by many folks. You're obviously free to do whatever you want with overloaded operators in D within the bounds of how they work, but we're not going to change them with the goal of making them less restrictive about mimicking the operators for the built-in types when the entire reason that they're in the language is to mimic the operators for the built-in types. And if you do try and make them work differently than for the built-in types, then your code is likely to be considered by many to be following bad programming practices. - Jonathan M Davis
Sep 29 2016
next sibling parent Minty Fresh <mint fresh.com> writes:
On Thursday, 29 September 2016 at 19:39:35 UTC, Jonathan M Davis 
wrote:
 The language can't stop you from doing at least some arbitrary 
 stuff with them (like making + do subtraction), but the whole 
 goal was for user-defined types to be able to act like the 
 built-in types, and as such, it would make no sense to alter 
 them towards being treated like symbols that you can do 
 whatever you want with.
Having `+` do subtraction isn't something you'd normally see. It's not a use case that would normally exist. Having `+` do addition, but do so in a database layer is a use case that actually may exist. The operator still behaves like a built-in type. It may perform addition as part of a SQL query, for example. Whether the expression `a + b` is translated into machine language, or translated into SQL, both still perform addition. A value represented by `a` is added to a value represented by `b`. Whether `a` and `b` are variables in D, or columns in a database table is irrelevant. And as it stands, D can already do this. It's the inability to perform an equivalent action for the expression `a > b`.
Sep 29 2016
prev sibling parent reply pineapple <meapineapple gmail.com> writes:
On Thursday, 29 September 2016 at 19:39:35 UTC, Jonathan M Davis 
wrote:
 The reality of the matter is that D's operator overloading was 
 designed specifically so that you could overload the built-in 
 operators to be used with your own types so that they could act 
 like the built-in types. It was not intended or designed to 
 allow for the symbols use for those operators to then be used 
 for other arbitrary stuff that's unrelated to what they mean 
 for the built-in types.
I repeat: Your thinking like this limits D's viability for real-world code. Yes, I understand, the reason operator overloading works the way it does now is because members of the community wanted to arbitrarily limit programmers working in the language. Because they believed theirs was the singular appropriate way to use the language, to the exclusion of all others. I'm opinionated too, but I also have the presence of mind to recognize that my opinions are not universal, and they are certainly no basis for imposing arbitrary limits upon another person's behavior. On Thursday, 29 September 2016 at 19:39:35 UTC, Jonathan M Davis wrote:
 And there are plenty of folks who think that overloading 
 operators to do stuff fundamentally different from how they 
 work for the built-in types is bad practice and consider it to 
 be an abuse of operator overloading. So, the fact that D limits 
 that is going to be viewed as positive by many folks.
Let me see if I understand your thinking: What you're saying is that because some people may not want to use a feature in a specific way, D should disallow anyone from using the feature in that way? That, somehow, contrary to logic, you believe this contributes positively to D's usability and appeal?
Sep 29 2016
next sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, September 29, 2016 20:16:00 pineapple via Digitalmars-d wrote:
 On Thursday, 29 September 2016 at 19:39:35 UTC, Jonathan M Davis

 wrote:
 The reality of the matter is that D's operator overloading was
 designed specifically so that you could overload the built-in
 operators to be used with your own types so that they could act
 like the built-in types. It was not intended or designed to
 allow for the symbols use for those operators to then be used
 for other arbitrary stuff that's unrelated to what they mean
 for the built-in types.
I repeat: Your thinking like this limits D's viability for real-world code. Yes, I understand, the reason operator overloading works the way it does now is because members of the community wanted to arbitrarily limit programmers working in the language. Because they believed theirs was the singular appropriate way to use the language, to the exclusion of all others. I'm opinionated too, but I also have the presence of mind to recognize that my opinions are not universal, and they are certainly no basis for imposing arbitrary limits upon another person's behavior.
Except that the limits aren't arbitrary. Walter designed D's overloaded operators for a specific purpose - to mimic the built-in operators. If you want to make them do something else, and you're able to do so with how they're designed, then that's your choice, but that's not what they're designed for, and there is no attempt to support it. You could just as easily ask why D's overloaded operators don't support arbitrary operators, allowing you do stuff like opBinary!"#" to support # in your code and complain that the current limitation on that is arbitary. The feature _could_ have been made to do something like that, but that wasn't its intended purpose, and there are reasons why it's a bad idea, so that's not how D's operator overloading was designed. The comparison operators have a specific purpose, and the functions for overloading them were designed with that in mind. It just so happens that that conflicts with what you want to do, but that doesn't mean that the limitation is arbitrary. Rather, code correctness and conciseness of code was valued, so they were overloaded using functions that could be used to derive those operators rather than explicitly overloading each operator individually. And because the ability to overload operators to do aribtrary stuff was never one of the goals of the design, the fact that having functions like opEquals and opCmp conflicted with the ability to overload each comparison operator to do arbitrary stuff was not considered to be a problem. It's a design tradeoff that just doesn't happen to be in line with what you want to do. Just because C++ overloaded operators in a way that happens to support doing arbitrary stuff with all of them doesn't mean that D needs to or that the restriction is arbitrary.
 On Thursday, 29 September 2016 at 19:39:35 UTC, Jonathan M Davis

 wrote:
 And there are plenty of folks who think that overloading
 operators to do stuff fundamentally different from how they
 work for the built-in types is bad practice and consider it to
 be an abuse of operator overloading. So, the fact that D limits
 that is going to be viewed as positive by many folks.
Let me see if I understand your thinking: What you're saying is that because some people may not want to use a feature in a specific way, D should disallow anyone from using the feature in that way? That, somehow, contrary to logic, you believe this contributes positively to D's usability and appeal?
There are plenty of folks who think that overloading operators to mean anything other than what they mean for the built-in types is bad practice. Walter seems to be in agreement with that. So, when he designed D's operator overloading, he did not attempt to support that. He didn't do a lot to prevent it either, but in cases where it made sense to derive multiple operators from a single function, he did so, even if it meant that you then couldn't overload those operators to mean something other than what they meant for the built-in types, because he considered what you got out of combining them was worth far more than trying to support what many think is bad practice. t's not like Walter sat down and tried to prevent every misuse of operator overloading. He simply didn't choose a design that fully supports such misuse. Rather, he chose a design that better supports the intended use. The tradeoff just so happens to leave you without being able to do something that he considers to be bad practice, so he doesn't see it as a loss. And neither do I. But that wasn't even the primary goal of why the operators work they do. It's just a side effect of there being design goals that were better served by a design that happened to inhibit operator overloading abuse. You'd have a much better argument if the language specifically did stuff to hobble the abuse of overloaded operators. It doesn't. It just doesn't implement operator overloading in a way that fully supports it. And Walter is clearly not in favor of implementing such a language "enhancement," because he thinks that it would just enable bad code, so I think that it's clear that it's not going to happen. - Jonathan M Davis
Sep 29 2016
prev sibling parent reply bachmeier <no spam.net> writes:
On Thursday, 29 September 2016 at 20:16:00 UTC, pineapple wrote:
 I repeat: Your thinking like this limits D's viability for 
 real-world code.
You're looking for https://www.perl.org/ That's a highly viable language, where you can do things like bury $[ = 1 somewhere in your code to change from 0-indexing to 1-indexing of arrays. They take pride in unpredictable, unreadable code.
Sep 29 2016
parent reply Minty Fresh <mint fresh.com> writes:
On Thursday, 29 September 2016 at 22:27:50 UTC, bachmeier wrote:
 You're looking for https://www.perl.org/ That's a highly viable 
 language, where you can do things like bury $[ = 1 somewhere in 
 your code to change from 0-indexing to 1-indexing of arrays. 
 They take pride in unpredictable, unreadable code.
This is not at all relevant to the current argument.
Sep 29 2016
next sibling parent bachmeier <no spam.net> writes:
On Thursday, 29 September 2016 at 22:37:51 UTC, Minty Fresh wrote:
 On Thursday, 29 September 2016 at 22:27:50 UTC, bachmeier wrote:
 You're looking for https://www.perl.org/ That's a highly 
 viable language, where you can do things like bury $[ = 1 
 somewhere in your code to change from 0-indexing to 1-indexing 
 of arrays. They take pride in unpredictable, unreadable code.
This is not at all relevant to the current argument.
I see
Sep 29 2016
prev sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, September 29, 2016 22:37:51 Minty Fresh via Digitalmars-d wrote:
 On Thursday, 29 September 2016 at 22:27:50 UTC, bachmeier wrote:
 You're looking for https://www.perl.org/ That's a highly viable
 language, where you can do things like bury $[ = 1 somewhere in
 your code to change from 0-indexing to 1-indexing of arrays.
 They take pride in unpredictable, unreadable code.
This is not at all relevant to the current argument.
Except that it kind of is. It's an example of a language allowing you to mess with too much and make it so that it doesn't function as expected, which is what happens when you overload operators to act in a way inconsistent with how they work with the built-in types. The perl example is more extreme, but the point still stands that having normal, common constructs operate in a way that's inconsistent with how they normally work tends to make code harder to read and maintain. Certainly, it can result in very unexpected behavior when mixing it with generic code that uses those operations. - Jonathan M Davis
Sep 29 2016
next sibling parent reply Chris Wright <dhasenan gmail.com> writes:
On Thu, 29 Sep 2016 17:50:54 -0700, Jonathan M Davis via Digitalmars-d 
wrote:
 Except that it kind of is. It's an example of a language allowing you to
 mess with too much and make it so that it doesn't function as expected,
 which is what happens when you overload operators to act in a way
 inconsistent with how they work with the built-in types.
The perl example is a line of code buried somewhere that changes the meaning of the rest of the code. Operator overloading is restricted to a specific user-defined type. With such a dramatic difference in the scope of the change, the analogy is useless.
Sep 29 2016
parent reply bachmeier <no spam.net> writes:
On Friday, 30 September 2016 at 01:07:49 UTC, Chris Wright wrote:
 The perl example is a line of code buried somewhere that 
 changes the meaning of the rest of the code. Operator 
 overloading is restricted to a specific user-defined type. With 
 such a dramatic difference in the scope of the change, the 
 analogy is useless.
I was responding to someone that wrote: "I also have the presence of mind to recognize that my opinions are not universal, and they are certainly no basis for imposing arbitrary limits upon another person's behavior". I gave an example of what happens when you don't want "arbitrary limits". Claiming that operator overloading only applies to a specific user-defined type makes it worse. Having it work one way for three types, a different way for four other types, and a third way for yet another type doesn't sound like a minor thing. But have fun debating design decisions that were made long ago and aren't going to change.
Sep 30 2016
parent reply Minty Fresh <mint fresh.com> writes:
On Friday, 30 September 2016 at 19:46:35 UTC, bachmeier wrote:
 Claiming that operator overloading only applies to a specific 
 user-defined type makes it worse. Having it work one way for 
 three types, a different way for four other types, and a third 
 way for yet another type doesn't sound like a minor thing.
But operators already behave in different way for different types. Built-in types inclusive. The most trivial and nit-picky difference would be between integer types and floating point types. ie. Division between two integers yields an integer, division between two floats yields a float, but then division between an integer and a float also yields a float. Alternatively, the bit-shift operators `<<` and `>>` don't function at all for floats. But then we have also wonderful floating point values like `NaN` and `Infinity` for which arithmetic and relational operators behave differently altogether. Another would static arrays, versus dynamic arrays, versus associative arrays. The first two support concatenation via `~`, only the second supports in-place concatenation `~=`, and the last has no notion of concatenation at all. A counter argument that might be raised is that those are different types altogether. They are intended to behave in different ways entirely. Completely different data structures. Their similarities are only superficial. And such a counter argument would be absolutely correct. Markedly so. They are completely different types. The same is true of user-defined types. Their behavior should not be equated to (nor expected to be like) the behaviors of types they only resemble superficially.
 But have fun debating design decisions that were made long ago 
 and aren't going to change.
That's exactly the kind of decision making you see in C++ and PHP. Metathesiophobia would be one way of describing it. Stubborn blindness to real world usage is more contextually appropriate though, I feel.
Sep 30 2016
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/30/2016 1:14 PM, Minty Fresh wrote:
 Metathesiophobia
Repeatedly suggesting people who don't agree with you have mental disorders does not advance your case and is not appreciated here. A more productive way forward is for you (and those who agree with you) to prepare a formal DIP and submit it. It's the way significant language change proposals are done.
Sep 30 2016
next sibling parent pineapple <meapineapple gmail.com> writes:
On Friday, 30 September 2016 at 22:38:07 UTC, Walter Bright wrote:
 A more productive way forward is for you (and those who agree 
 with you) to prepare a formal DIP and submit it. It's the way 
 significant language change proposals are done.
A good idea. I have written a rough initial draft for this DIP and it currently resides here, in a fork: https://github.com/pineapplemachine/DIPs/blob/operator_overload_expansion/DIPs/DIP1003.md I invite anyone with an opinion - which I imagine is just about everyone who has participated in this thread - to please contribute to the DIP before it's submitted as a PR and for review. I ask that arguments for and against listed in the DIP not include anything to the effect of merely "it would offer more flexibility" or "it would offer too much flexibility", as I think several pages of discussion have made clear that those holding either opinion are not likely to be swayed by arguments taking the opposing form.
Sep 30 2016
prev sibling next sibling parent Russel Winder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Fri, 2016-09-30 at 15:38 -0700, Walter Bright via Digitalmars-d
wrote:

 A more productive way forward is for you (and those who agree with
 you) to=C2=A0
 prepare a formal DIP and submit it. It's the way significant language
 change=C2=A0
 proposals are done.
But is the effort worth it? Will the DIP and PR be assessed? Does it have any chance of success? Is there any chance of this long standing position of D on overloading operators being overturned? Saying "Go prepare a DIP" is both indicating the right thing to do, but also a mechanism of deflecting the idea from having any chance of success at all. So does a well prepared DIP have a chance of changing D's operator overloading or not? =C2=A0 --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 30 2016
prev sibling parent Minty Fresh <mint fresh.com> writes:
On Friday, 30 September 2016 at 22:38:07 UTC, Walter Bright wrote:
 On 9/30/2016 1:14 PM, Minty Fresh wrote:
 Metathesiophobia
Repeatedly suggesting people who don't agree with you have mental disorders does not advance your case and is not appreciated here.
Metathesiophobia is not a mental disorder, it's a phobia. There's quite a bit of distinction there. Specifically it's an ungrounded fear or dislike of change. It's altogether not uncommon, actually.
 A more productive way forward is for you (and those who agree 
 with you) to prepare a formal DIP and submit it. It's the way 
 significant language change proposals are done.
That was sort of the initial intent of this thread. To test the waters and see if the idea would have support. But it seems the community is extremely torn on the matter.
Oct 01 2016
prev sibling next sibling parent reply pineapple <meapineapple gmail.com> writes:
On Friday, 30 September 2016 at 00:50:54 UTC, Jonathan M Davis 
wrote:
 Except that it kind of is. It's an example of a language 
 allowing you to mess with too much and make it so that it 
 doesn't function as expected, which is what happens when you 
 overload operators to act in a way inconsistent with how they 
 work with the built-in types.
Which language is more widely used? D or Perl? Let me see if I understand your argument: We can't make D more expressive because a language far more popular than D is so expressive it makes it possible to do unconventional things, if you are so inclined?
Sep 30 2016
next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Friday, September 30, 2016 09:55:36 pineapple via Digitalmars-d wrote:
 On Friday, 30 September 2016 at 00:50:54 UTC, Jonathan M Davis

 wrote:
 Except that it kind of is. It's an example of a language
 allowing you to mess with too much and make it so that it
 doesn't function as expected, which is what happens when you
 overload operators to act in a way inconsistent with how they
 work with the built-in types.
Which language is more widely used? D or Perl? Let me see if I understand your argument: We can't make D more expressive because a language far more popular than D is so expressive it makes it possible to do unconventional things, if you are so inclined?
perl is always widely considered to be a horrible language even if it is useful. And the example that was given for what you can do with perl is pretty insane. Regardless, D already has a lot of powerful stuff in it, much of which will allow you to blow your foot off if you're really inclined to. The overloaded operators just so happened to be implemented in a way that doesn't let you blow your feet off as freely as C++'s overloaded operators will let you do. - Jonathan M Davis
Sep 30 2016
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 30.09.2016 18:11, Jonathan M Davis via Digitalmars-d wrote:
 Regardless, D already has a lot of powerful stuff in it, much of which will
 allow you to blow your foot off if you're really inclined to. The overloaded
 operators just so happened to be implemented in a way that doesn't let you
 blow your feet off as freely as C++'s overloaded operators will let you do.
OTOH, feet are useless if you are not allowed to walk (even if you choose not to blow them off).
Sep 30 2016
prev sibling parent reply Dominikus Dittes Scherkl <Dominikus.Scherkl continental-corporation.com> writes:
On Friday, 30 September 2016 at 09:55:36 UTC, pineapple wrote:
 On Friday, 30 September 2016 at 00:50:54 UTC, Jonathan M Davis 
 wrote:
 Except that it kind of is. It's an example of a language 
 allowing you to mess with too much and make it so that it 
 doesn't function as expected, which is what happens when you 
 overload operators to act in a way inconsistent with how they 
 work with the built-in types.
Let me see if I understand your argument: We can't make D more expressive because a language far more popular than D is so expressive it makes it possible to do unconventional things, if you are so inclined?
But operator overloading doesn't increase the language expressiveness. They provide nothing that you can't already do using ordinary function calls. So forget expressiveness as an argument. Operator overload is syntactic sugar, added to serve a single purpose: to allow mimic buildin types. So they should provide everything needed to do so, and nothing more. Adding more may be asked for, but this is not reasonable, because it is unrelated to the original purpose but increases only the possibilities to obfuscate the code by doing something misleading (there are already endless such possibilities, but that makes asking for more no more reasonable). On Friday, 30 September 2016 at 19:09:25 UTC, Timon Gehr wrote:
 On 30.09.2016 18:11, Jonathan M Davis via Digitalmars-d wrote:
 Regardless, D already has a lot of powerful stuff in it, much 
 of which will
 allow you to blow your foot off if you're really inclined to. 
 The overloaded
 operators just so happened to be implemented in a way that 
 doesn't let you
 blow your feet off as freely as C++'s overloaded operators 
 will let you do.
OTOH, feet are useless if you are not allowed to walk (even if you choose not to blow them off).
You are allowed to walk. You can express everything that is possible with operator overloading in lots of other ways. And you can express everything that operator overloading was designed for with it - but maybe not everything beyond that. Use other ways to express such. If the compactness of expression written using operators is everything you are interested in - define some language and write a parser for it, and enjoy how short you can express everything you need with it. You can even write such stuff directly in your D code and let some string mixins massage it to compile. I can't see the point to relax the rules for operator overloading unless you can show that they prevent parts of the original design goal. PS: opCmp can return float, so the comparison can result in NaN (not conparable) - and as this is necessary to mimic some basic types (all floatingpoint types) removing this possibility would indeed prevent parts of the original design goal!
Sep 30 2016
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 30.09.2016 23:43, Dominikus Dittes Scherkl wrote:
 On Friday, 30 September 2016 at 09:55:36 UTC, pineapple wrote:
 On Friday, 30 September 2016 at 00:50:54 UTC, Jonathan M Davis wrote:
 Except that it kind of is. It's an example of a language allowing you
 to mess with too much and make it so that it doesn't function as
 expected, which is what happens when you overload operators to act in
 a way inconsistent with how they work with the built-in types.
Please don't do this; it destroys threading.
 On Friday, 30 September 2016 at 19:09:25 UTC, Timon Gehr wrote:
 On 30.09.2016 18:11, Jonathan M Davis via Digitalmars-d wrote:
 Regardless, D already has a lot of powerful stuff in it, much of
 which will
 allow you to blow your foot off if you're really inclined to. The
 overloaded
 operators just so happened to be implemented in a way that doesn't
 let you
 blow your feet off as freely as C++'s overloaded operators will let
 you do.
OTOH, feet are useless if you are not allowed to walk (even if you choose not to blow them off).
You are allowed to walk.
There's a continuum here. Another data point: https://www.youtube.com/watch?v=IqhlQfXUk7w (Though here, one seems to require a good set of feet.)
 You can express everything that is possible
 with operator overloading in lots of other ways.
Everybody knows this. And everyone in the above video is getting where they are going.
 And you can express
 everything that operator overloading was designed for with it
Hopefully. My qualm is with the design. (It is not that significant, it's basically in the "fly that sits on your face at an irregular frequency" corner.)
 - but
 maybe not everything beyond that. Use other ways to express such. If the
 compactness of expression written using operators is everything you are
 interested in
Am not. You might be confusing me with someone else. But don't assume I'm going to accept huge overhead, because this does destroy the point of the original exercise at some point.
 - define some language
Yes, I can design my own programming language. However, I don't currently have the resources to create the perfect tool for every job I face.
 and write a parser for it,
Sure, I also have a parser. Now what? It does not integrate nicely with D code.
 and enjoy how short you can express everything you need with it.
Conciseness never hurts. I'm interested in using notation that is similar to the one I use on paper and in scientific publications. It's also about ensuring correctness by making it easy to understand at a glance what is written down (by e.g. a domain expert). This is understood to have certain limitations (e.g. there's no built-in integral operator), but the notation that does exist corresponds precisely -- there is no misusing of names anywhere.
 You can even write such stuff directly in your D code and let some
 string mixins massage it to compile.
 ...
This does not scale. (It works for some things, not others.)
 I can't see the point to relax the rules for operator overloading unless
 you can show that they prevent parts of the original design goal.
 ...
Then I'm not interested in trying to convince you because you can always just claim that the use case I present was not part of the original design goal (which is not written down formally anywhere).
 PS: opCmp can return float, so the comparison can result in NaN (not
 conparable) - and as this is necessary to mimic some basic types (all
 floatingpoint types) removing this possibility would indeed prevent
 parts of the original design goal!
I know. I believe I was even the first one to point this out on the NG. It was an accident, not designed. The cause was lack of some pointless restriction.
Sep 30 2016
prev sibling parent Russel Winder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Fri, 2016-09-30 at 21:43 +0000, Dominikus Dittes Scherkl via
Digitalmars-d wrote:

 But operator overloading doesn't increase the language=C2=A0
 expressiveness.
Expressiveness is not a metric, there isn't even a partial order, it is a qualitative thing, thus personal to a great extent. What I consider expressive and what you consider expressive likely are entirely unrelated. There can be a shared agreement or a disagreement. What is not acceptable is to state that one person's opinion is true for all people=C2=A0 =C2=A0
 They provide nothing that you can't already do using ordinary=C2=A0
 function calls.
Correct.
 So forget expressiveness as an argument.
No.
 Operator overload is syntactic sugar, added to serve a single=C2=A0
 purpose: to allow mimic buildin types. So they should provide=C2=A0
 everything needed to do so, and nothing more. Adding more may be=C2=A0
 asked for, but this is not reasonable, because it is unrelated to=C2=A0
 the original purpose but increases only the possibilities to=C2=A0
 obfuscate the code by doing something misleading (there are=C2=A0
 already endless such possibilities, but that makes asking for=C2=A0
 more no more reasonable).
All high level languages are syntactic sugar, the one true language is machine code, all else is fluff. It just happens that layers of abstraction and "syntactic sugar" are really rather important to building complex software systems.=C2=A0 Any programming language is in fact a meta-language to enable people to construct new languages. All programs are DSLs for some domain. The question at hand is whether a programming language has the right tools for the job. Operator overloading is one tool in the creation of DSLs. D currently seems to have a very hobbled version of this compared to C++, Python, and a very grandiose scheme compared to Go, Fortran. This debate is about whether D constrains people as Java does or whether it enables people as C++ and Python do.
 You are allowed to walk. You can express everything that is=C2=A0
 possible with operator overloading in lots of other ways. And you=C2=A0
 can express everything that operator overloading was designed for=C2=A0
 with it - but maybe not everything beyond that. Use other ways to=C2=A0
 express such. If the compactness of expression written using=C2=A0
 operators is everything you are interested in - define some=C2=A0
 language and write a parser for it, and enjoy how short you can=C2=A0
 express everything you need with it.
 You can even write such stuff directly in your D code and let=C2=A0
 some string mixins massage it to compile.
Or use C++ or Python which allow for this. Fine, end of D having a future amongst a large section of the programming population. This is fine. Unless D wants to be a player in this game.=C2=A0
 I can't see the point to relax the rules for operator overloading=C2=A0
 unless you can show that they prevent parts of the original=C2=A0
 design goal.
This has already been done, read the thread. SQLAlchemy. The expression language is a a lovely builder DSL for constructing SQL entirely in Python with no parser overhead. No operator overloading, no DSL for builder languages. See same on the JVM: in Java you can't do it, Kotlin, Ceylon, Scala, Groovy, do it beautifully, and a lot of people do. Java only survives as a language for constructing new systems because a very large part of the Java programming community cannot be bothered to learn new stuff that doesn't have Java on the label. Even then many are not sure about this Java 8 thing. Indeed many are not even sure Java 5 was a good thing. Yes there are a lot of people still writing new stuff in Java 1.4.2 because generics, streams, modern programming techniques are new fangled syntactic sugar that is not needed to express the algorithm. I can give lots of anecdotal evidence on this drawn from workshops I have presented. The question here is whether D wants to include these sorts of things or reject them. But at the heart of the debate is whether a DIP will be evolved into a change to the D language or whether it will be rejected even before it is put together. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 30 2016
prev sibling parent reply Minty Fresh <mint fresh.com> writes:
On Friday, 30 September 2016 at 00:50:54 UTC, Jonathan M Davis 
wrote:
 Except that it kind of is. It's an example of a language 
 allowing you to mess with too much and make it so that it 
 doesn't function as expected, which is what happens when you 
 overload operators to act in a way inconsistent with how they 
 work with the built-in types. The perl example is more extreme, 
 but the point still stands that having normal, common 
 constructs operate in a way that's inconsistent with how they 
 normally work tends to make code harder to read and maintain. 
 Certainly, it can result in very unexpected behavior when 
 mixing it with generic code that uses those operations.

 - Jonathan M Davis
It's up to the developer to ensure that their code works correctly with existing facilities, not the language. I can already write code that will work in amazing and ridiculous ways with generic code in the standard library. It does not follow that the language is responsible or at fault for the code behaving in ways that are unexpected. Furthermore, it's completely reasonable to write code that works with the generic facilities in the standard library, even if it doesn't behave exactly like a built in type. ie. foo.reduce!"a + b"; // => produces an integer bar.reduce!"a + b"; // => produces an AST node So long as the types produced by the operation are correct, this will work just fine.
Sep 30 2016
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Friday, September 30, 2016 12:31:45 Minty Fresh via Digitalmars-d wrote:
 It's up to the developer to ensure that their code works
 correctly with existing facilities, not the language. I can
 already write code that will work in amazing and ridiculous ways
 with generic code in the standard library. It does not follow
 that the language is responsible or at fault for the code
 behaving in ways that are unexpected.
Of course, you can write code that behaves badly. There's no way that that can be completely prevented while still allowing you to do useful, productive things. But the folks asking to be able to overload < separately just so that they can make it behave differently than what opCmp does are basically asking for a way to be allowed to make their code behave badly with the comparison operators in a way that opCmp doesn't currently allow. The request is to improve support for an idiom that many consider to be horrible coding practice, and Walter does not think that explicitly supporting such an idiom makes any sense. He hasn't gone to extra effort to prevent every possible misuse of overloaded operators that he could. He simply defined some of the overloaded operators in a way that was a significant improvement for the use case that he thought that overloaded operators should be used for, and as a side effect, it happens to have made it harder for a use case that he thinks is bad practice. I think that he made the right decision. But if you or anyone else wants to do wacky stuff with overloaded operators that is not consistent with the built-in types, you're free to do so within how D's overloaded operators work. You're just not going to be able to do it as freely as you can in C++, because that goes against the goals of the operator overloading feature in D, and some of the improvements that were in line with the goals happen to have gotten in the way of such operator overloading abuse. - Jonathan M Davis
Sep 30 2016
parent reply pineapple <meapineapple gmail.com> writes:
On Friday, 30 September 2016 at 16:25:45 UTC, Jonathan M Davis 
wrote:
 But if you or anyone else wants to do wacky stuff with 
 overloaded operators that is not consistent with the built-in 
 types, you're free to do so within how D's overloaded operators 
 work. You're just not going to be able to do it as freely as 
 you can in C++, because that goes against the goals of the 
 operator overloading feature in D, and some of the improvements 
 that were in line with the goals happen to have gotten in the 
 way of such operator overloading abuse.
In your arguments in favor of this limitation of operator overloading, you keep referring to these goals, of what operator overloads have been intended to do. You've stated and restated that same explanation even though it's completely unconvincing because while stating this intention you have failed entirely to justify it. How many people have to state it how many times in how many different ways before it gets through? These are stupid goals. They reflect intention that has no basis in reason, that has no basis in reality, that is a blindly-enforced dogma. It always would have been simpler if, in the first place, opBinary had caught comparison operators and opCmp and opEquals were omitted. Instead, those making the decisions went out of their way to impose these arbitrary limitations. If we can start now to untangle that mistake, it will make D more tenable for real-world code. And make no mistake: Perl is fantastic for real-world code because real-world code is not elegant, and it doesn't follow the rules, and it doesn't care how you meant for a feature to be used. Practical languages give the programmer a great deal of expressive power, and it's okay if the rules allow nonsense expressions because it's up to the programmer, not the language, to know what's nonsense and what's not.
Sep 30 2016
parent Chris Wright <dhasenan gmail.com> writes:
On Fri, 30 Sep 2016 19:33:33 +0000, pineapple wrote:
 How many people have to state it how many times in how many different
 ways before it gets through? These are stupid goals. They reflect
 intention that has no basis in reason, that has no basis in reality,
 that is a blindly-enforced dogma.
More like: this is the common use case, so let's try to make that as smooth as possible, both for implementors and readers. And mucking about in the same area can add wrinkles that confuse people. The takeaway should be that we should exercise caution, not that we should refuse to change the language. But the basic idea does make sense. I'm not sure it's straightforward to make other operators consistent in the same way. You could try to enforce things like: typeof(a OP b) should be co/contravariant with typeof(a) or typeof(b) for math operators; opApply and opIndex should deal with the same types (though it's valid to add extras); that kind of thing. It does seem inconsistent that no attempt was made, but the language was only Walter Bright for nearly a decade, and one person doesn't have that much time. With most of the language and compiler work still being Walter Bright, he has much more say in the direction of the language than anyone else.
 It always would have been simpler if, in the first place, opBinary had
 caught comparison operators and opCmp and opEquals were omitted.
 Instead, those making the decisions went out of their way to impose
 these arbitrary limitations. If we can start now to untangle that
 mistake, it will make D more tenable for real-world code.
That would have been tricky, or at least unpleasant, before auto return types. Auto return types were introduced after 2010, and opCmp was introduced before 2006.
Oct 01 2016
prev sibling parent reply Sai <test test.com> writes:
    a.isLessThan(b)
I understand the concern of possible mess due to unrestricted use of operator overloading (like C++). Java has clearly driven the point home by banning the operator overloading altogether. Genuine question: In the post Java languages, how many languages allowed unrestricted operator overloading and did that cause any similar mess? Thanks in advance for any answers.
Sep 30 2016
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01.10.2016 01:31, Sai wrote:
 I understand the concern of possible mess due to unrestricted use of
 operator overloading (like C++).
C++ does it in std.
Sep 30 2016
prev sibling next sibling parent Russel Winder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Fri, 2016-09-30 at 23:31 +0000, Sai via Digitalmars-d wrote:

 Genuine question: In the post Java languages, how many languages=C2=A0
 allowed unrestricted operator overloading and did that cause any=C2=A0
 similar mess?
It is not feasible to provide a count, as there is always another language one forgot. Groovy, Kotlin, Ceylon, and Scala certainly allow operator overloading. Scala even allows new operator symbol definition. There are some incomprehensible Scala programs because of this. But then there are many incomprehensible D programs =E2=80=93 you can play code golf in any language. Just because there is a feature in a language doesn't mean it has to be abused. I cannot remember offhand whether Fantom, Golo, Gosu, etc. allow operator overloading. The core lesson of Python is that if you allow everything to happen, there can still be a base of excellent code. Paternalism/maternalism in programming languages is massively overrated. Youngsters will escape the constraints. In the case of D operator overloading restrictions to the glories (!) that is C++. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 30 2016
prev sibling next sibling parent reply Chris Wright <dhasenan gmail.com> writes:
On Fri, 30 Sep 2016 23:31:19 +0000, Sai wrote:
 Genuine question: In the post Java languages, how many languages allowed
 unrestricted operator overloading and did that cause any similar mess?
Groovy doesn't allow you to overload comparison operators individually, and probably most JVM languages likewise. This is to retain compatibility with Java, which has `.compareTo()` instead of `isLessThan()` etc. Ruby allows you to override individual comparison operators, with a special operator `<=>` for combined comparisons. Nim lets you overload arbitrary operators and create your own; some old discussions suggest that the Comparable type is based on `<` alone.
Oct 01 2016
parent reply Russel Winder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sat, 2016-10-01 at 14:55 +0000, Chris Wright via Digitalmars-d
wrote:

 Groovy doesn't allow you to overload comparison operators
 individually,=C2=A0
 and probably most JVM languages likewise. This is to retain
 compatibility=C2=A0
 with Java, which has `.compareTo()` instead of `isLessThan()` etc.
Yes it does. =C2=A0http://groovy-lang.org/operators.html There is *also* compareTo.
 Ruby allows you to override individual comparison operators, with a=C2=A0
 special operator `<=3D>` for combined comparisons. Nim lets you
 overload=C2=A0
 arbitrary operators and create your own; some old discussions
 suggest=C2=A0
 that the Comparable type is based on `<` alone.
Groovy also supports the spaceship operator. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Oct 01 2016
parent Minty Fresh <mint fresh.com> writes:
On Saturday, 1 October 2016 at 17:53:44 UTC, Russel Winder wrote:
 On Sat, 2016-10-01 at 14:55 +0000, Chris Wright via 
 Digitalmars-d wrote:

 Groovy doesn't allow you to overload comparison operators
 individually,
 and probably most JVM languages likewise. This is to retain
 compatibility
 with Java, which has `.compareTo()` instead of `isLessThan()` 
 etc.
Yes it does.  http://groovy-lang.org/operators.html There is *also* compareTo.
 Ruby allows you to override individual comparison operators, 
 with a
 special operator `<=>` for combined comparisons. Nim lets you
 overload
 arbitrary operators and create your own; some old discussions
 suggest
 that the Comparable type is based on `<` alone.
Groovy also supports the spaceship operator.
`<=>` exists for the general case, which is what `opCmp` covers in D. Overloading each relational operator individually is made possible to address any sort of special cases. The issue being, in D there is no room for any manner of special case.
Oct 02 2016
prev sibling parent Minty Fresh <mint fresh.com> writes:
On Friday, 30 September 2016 at 23:31:19 UTC, Sai wrote:
 Genuine question: In the post Java languages, how many 
 languages allowed unrestricted operator overloading and did 
 that cause any similar mess?

 Thanks in advance for any answers.
Although there maybe a bit of bias here, but I'd say Rub does it quite well (although the syntax for unary operator overloads is a bit bizarre), since I work with the language on a daily basis. But going a step further there's languages like Haskell that allow defining completely new operators. Both of the aforementioned have amassed an exceedingly large following at this point.
Oct 01 2016
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 29.09.2016 18:41, Sai wrote:
 I.e. you can overload '+' to do bad things. Yes, you can, and as I
 replied upthread that can be done because there's no way to prevent
 that while having operator overloading at all.

 But that is not justification for allowing such disasters for the
 comparison operators. I.e. one weakness is not justification for
 opening the door to all weakness.
If I understand the issue correctly, one will not be able to overload <=, >, etc for symbolic math, like CAS (mimicking mathematica for example), how can I do it now? Wouldn't the current rules discourage someone from implementing CAS like library in D?
Not really, but it's annoying.
Sep 29 2016
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2016-09-28 03:18, Minty Fresh wrote:
 Currently, D offers fine grained overloading for most of the unary and
 arithmetic binary operators, but at some point a decision was made to
 lump together all of the relational operators (and if necessary, the
 equality operators) into a single function `opCmp`.
 And while it does add a lot of convenience and consistency to how
 operators behave, it does also put a lot of limitations on what they can
 do.

 For example, it's not currently possible to implement comparison
 operators that would behave lazily and only compute a certain value once
 a function call forces the computation.

 Similarly, it's not possible to construct a DSL that would produce code
 or a query in another language, by returning values behave like AST
 nodes rather than actually performing a comparison.

 ie.
   table.users
        .where!((users) => users.joined_on >= 3.days.ago)
        .joins(table.posts)
        .on!((posts, users) => posts.user_id == users.id)
        .limit(10)
        .toSql;

 It's a little odd to me that D puts so little focus on DSLs, since
 language features like template constraints, `opDispatch`, and even the
 fact that binary operators are overloadable via a single templated
 function are all very useful tools for implementing them.
I completely agree. Or we could go with an even more general approach: AST macros [1]. [1] http://wiki.dlang.org/DIP50 -- /Jacob Carlborg
Sep 27 2016
prev sibling next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
Me and Cauterite were toying with the idea of AST macros but in a 
completely new form a while ago.

Below is the usage of it.

Something you'll notice about it is that it could turn the asm block 
into a library solution (which is clearly what we'd want anyway). Not to 
mention Linq style queries.

In theory it shouldn't be too complex to implement since you are only 
doing basic checks to determine if to parse the given statement / block 
to a rewriter function.

```D
void main() {
     // \/ parsed by iasm.c by matches {}'s and sending contents to it
     asm {
         ...
     }

     import linq;
      Linq
     DataSource source = ...;
     Tree[] trees = source.trees.where(name = "abc").limit(20);

     import Assembly_x86;

     asm {
         ...
     }
}

struct Linq {
     string __ast(OnType, ExpectedType)(string statement) {
         assert(statement == "source.trees.where(name = "abc").limit(20);");
         static assert(OnType == DataSource);
         static assert(ExpectedType == Tree[]);
     }
}

// Assembly_x86.d

struct X86 {}
struct ASM {

     string __ast(OnType, ExpectedType)(string statement) {
         assert(statement == "asm {\n        ...\n    };");
         static assert(OnType == X86);
         static assert(ExpectedType == void);
     }
}

 ASM
X86 asm;
```
Sep 29 2016
parent reply Jacob Carlborg <doob me.com> writes:
On 2016-09-29 14:57, rikki cattermole wrote:
 Me and Cauterite were toying with the idea of AST macros but in a
 completely new form a while ago.

 Below is the usage of it.

 Something you'll notice about it is that it could turn the asm block
 into a library solution (which is clearly what we'd want anyway). Not to
 mention Linq style queries.

 In theory it shouldn't be too complex to implement since you are only
 doing basic checks to determine if to parse the given statement / block
 to a rewriter function.

 ```D
 void main() {
     // \/ parsed by iasm.c by matches {}'s and sending contents to it
     asm {
         ...
     }

     import linq;
      Linq
     DataSource source = ...;
     Tree[] trees = source.trees.where(name = "abc").limit(20);

     import Assembly_x86;

     asm {
         ...
     }
 }

 struct Linq {
     string __ast(OnType, ExpectedType)(string statement) {
         assert(statement == "source.trees.where(name = "abc").limit(20);");
         static assert(OnType == DataSource);
         static assert(ExpectedType == Tree[]);
     }
 }

 // Assembly_x86.d

 struct X86 {}
 struct ASM {

     string __ast(OnType, ExpectedType)(string statement) {
         assert(statement == "asm {\n        ...\n    };");
         static assert(OnType == X86);
         static assert(ExpectedType == void);
     }
 }

  ASM
 X86 asm;
 ```
Hmm, I find this to be somewhat difficult to follow. You get the AST as a string? Which means you need to implement a parser. How will the macro invocation be transformed? Return a string from the macro which will be reparsed by the compiler and inserted at the call site? -- /Jacob Carlborg
Sep 29 2016
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 30/09/2016 2:18 AM, Jacob Carlborg wrote:
 On 2016-09-29 14:57, rikki cattermole wrote:
 Me and Cauterite were toying with the idea of AST macros but in a
 completely new form a while ago.

 Below is the usage of it.

 Something you'll notice about it is that it could turn the asm block
 into a library solution (which is clearly what we'd want anyway). Not to
 mention Linq style queries.

 In theory it shouldn't be too complex to implement since you are only
 doing basic checks to determine if to parse the given statement / block
 to a rewriter function.

 ```D
 void main() {
     // \/ parsed by iasm.c by matches {}'s and sending contents to it
     asm {
         ...
     }

     import linq;
      Linq
     DataSource source = ...;
     Tree[] trees = source.trees.where(name = "abc").limit(20);

     import Assembly_x86;

     asm {
         ...
     }
 }

 struct Linq {
     string __ast(OnType, ExpectedType)(string statement) {
         assert(statement == "source.trees.where(name =
 "abc").limit(20);");
         static assert(OnType == DataSource);
         static assert(ExpectedType == Tree[]);
     }
 }

 // Assembly_x86.d

 struct X86 {}
 struct ASM {

     string __ast(OnType, ExpectedType)(string statement) {
         assert(statement == "asm {\n        ...\n    };");
         static assert(OnType == X86);
         static assert(ExpectedType == void);
     }
 }

  ASM
 X86 asm;
 ```
Hmm, I find this to be somewhat difficult to follow. You get the AST as a string? Which means you need to implement a parser. How will the macro invocation be transformed? Return a string from the macro which will be reparsed by the compiler and inserted at the call site?
I'll expand on what I wrote above. There are two kinds of invocations here. Blocks and statements. Statements are the type of thing you expect from e.g. Linq. Where as blocks would be what asm would be defined as being. The invocation defines where the start/end of the input file to be passed to __ast is and that is all it does. In each case, if the first token (or for assignment statements the first token of the expression) is a variable that happens to have a UDA on it with __ast member it will pass said invocation text directly to it. What ever that may be. As far as guarantees go for the input, it will always end in a semicolon. To determine if it was a statement vs a block just check if ExpectedType is void. So something like: ```D Linq DataSource source = ...; Tree[] trees = source.trees.where(name = "abc").limit(20); ``` Could be transformed into: ```D Linq DataSource source = ...; Tree[] trees = mixin(__traits(getAttributes, source)[0].__ast("source.trees.where(name = "abc").limit(20);")); ``` They key here is explicitly marking non-vanilla-D-code as such without adding syntax like ``macro{ stuff here }``.
Sep 29 2016
prev sibling parent Atila Neves <atila.neves gmail.com> writes:
On Wednesday, 28 September 2016 at 01:18:58 UTC, Minty Fresh 
wrote:
 Currently, D offers fine grained overloading for most of the 
 unary and arithmetic binary operators, but at some point a 
 decision was made to lump together all of the relational 
 operators (and if necessary, the equality operators) into a 
 single function `opCmp`.
 And while it does add a lot of convenience and consistency to 
 how operators behave, it does also put a lot of limitations on 
 what they can do.

 [...]
opCmp was a good idea. Allowing opBinary to bypass opCmp is also a good idea. Atila
Oct 02 2016