www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Am I evil for this?

reply solidstate1991 <laszloszeremi outlook.com> writes:
So I watched this video:

https://youtu.be/G6b62HmsO6M

And Walter talked about using operator overloading for 
nonstandard purposes.

So in my collections library, I used it to implement set 
operators, but since set operators don't exist in the D standard 
(and require unicode, which would upset a lot of people, 
especially those who don't know what Win + '.' does), I had to 
use operators that have similar function in other spaces.

I personally haven't used them yet in my projects (except for the 
unittests), so it's not too late to remove them, but I don't know 
if anyone else might be using them or not.

Link to my library with an example offense: 
https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L356
Oct 13 2022
next sibling parent reply Araq <rumpf_a web.de> writes:
On Thursday, 13 October 2022 at 20:28:52 UTC, solidstate1991 
wrote:
 So I watched this video:

 https://youtu.be/G6b62HmsO6M

 And Walter talked about using operator overloading for 
 nonstandard purposes.

 So in my collections library, I used it to implement set 
 operators, but since set operators don't exist in the D 
 standard (and require unicode, which would upset a lot of 
 people, especially those who don't know what Win + '.' does), I 
 had to use operators that have similar function in other spaces.

 I personally haven't used them yet in my projects (except for 
 the unittests), so it's not too late to remove them, but I 
 don't know if anyone else might be using them or not.

 Link to my library with an example offense: 
 https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L356
Before C came along x << y already meant "x is much smaller than y" and x || y sometimes meant "run x and y in parallel". "Nonstandard purposes" hardly means anything. Use the operators as you see fit.
Oct 13 2022
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 13 October 2022 at 21:01:08 UTC, Araq wrote:

 Before C came along x << y already meant "x is much smaller 
 than y" and x || y sometimes meant "run x and y in parallel". 
 "Nonstandard purposes" hardly means anything. Use the operators 
 as you see fit.
"nonstandard purposes" were the OP's words, not Walter's. Walter's was talking about overloading for nonarithmetic purposes. This is not an uncommon criticism. He cited the C++ iostreams library as many who make this criticism do, and also a project he saw in the past that overloaded C++ operators to make a regex DSL. The specific discussion about operator overloading is here: https://youtu.be/G6b62HmsO6M?t=858
Oct 13 2022
parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Fri, Oct 14, 2022 at 02:13:34AM +0000, Mike Parker via Digitalmars-d wrote:
 On Thursday, 13 October 2022 at 21:01:08 UTC, Araq wrote:
 
 Before C came along x << y already meant "x is much smaller than
 y" and x || y sometimes meant "run x and y in parallel".
 "Nonstandard purposes" hardly means anything. Use the operators as
 you see fit.
"nonstandard purposes" were the OP's words, not Walter's. Walter's was talking about overloading for nonarithmetic purposes. This is not an uncommon criticism.
Generally, I agree with Walter. Operator overloading should not be taken as a free license to bend arithmetic operators to do things alien to their basic arithmetic meaning. That's just a big code smell, and leads to hard-to-read code with poor maintainability.
 He cited the C++ iostreams library as many who make this criticism do,
Yeah, using << and >> for I/O is a total eyesore. The precedence doesn't make sense for I/O, if you don't parenthesize, the expression could mean something completely different from what you expect. IMO, this a total code smell, and a symptom of C++'s typical overly-clever-yet-still- incomplete style of addressing language design issues.
 and also a project he saw in the past that overloaded C++ operators to
 make a regex DSL.
[...] That would be Boost.Xpressive, I think. Makes me cringe every time I look at it. In typical C++ hammer-a-nail-with-a-chainsaw fashion, compile-time regexes take operator overloading abuse to a whole new level and the result looks nothing like a regex, introducing a maintenance nightmare (the same regex gets written in two *completely* different ways depending on whether it's runtime or compile-time -- and good like trying to read the compile-time one). Now that constexpr is a thing, here's to hoping that this horrendous operator overload abuse will soon be relegated to the dustbin of history. T -- Caffeine underflow. Brain dumped.
Oct 13 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/13/2022 7:44 PM, H. S. Teoh wrote:
 and also a project he saw in the past that overloaded C++ operators to
 make a regex DSL.
[...] That would be Boost.Xpressive, I think.
Here it is: #include <boost/spirit.hpp> using namespace boost; int main() { spirit::rule<> group, fact, term, expr; group = '(' >> expr >> ')'; fact = spirit::int_p | group; term = fact >> *(('*' >> fact) | ('/' >> fact)); expr = term >> *(('+' >> term) | ('-' >> term)); assert( spirit::parse("2*(3+4)", expr).full ); assert( ! spirit::parse("2*(3+4", expr).full ); } https://studylib.net/doc/10029968/text-processing-with-boost---northwest-c---users--group slide 40 It's a technical marvel, but the embedded DSL looks like C++ expressions yet does something completely different. One cannot distinguish the C++ code from the DSL code. It's in the same category as macros, and I can't recommend it.
Oct 13 2022
parent reply Max H <maxhaton gmail.com> writes:
On Friday, 14 October 2022 at 06:59:43 UTC, Walter Bright wrote:
 On 10/13/2022 7:44 PM, H. S. Teoh wrote:
 and also a project he saw in the past that overloaded C++ 
 operators to
 make a regex DSL.
[...] That would be Boost.Xpressive, I think.
Here it is: #include <boost/spirit.hpp> using namespace boost; int main() { spirit::rule<> group, fact, term, expr; group = '(' >> expr >> ')'; fact = spirit::int_p | group; term = fact >> *(('*' >> fact) | ('/' >> fact)); expr = term >> *(('+' >> term) | ('-' >> term)); assert( spirit::parse("2*(3+4)", expr).full ); assert( ! spirit::parse("2*(3+4", expr).full ); } https://studylib.net/doc/10029968/text-processing-with-boost---northwest-c---users--group slide 40 It's a technical marvel, but the embedded DSL looks like C++ expressions yet does something completely different. One cannot distinguish the C++ code from the DSL code. It's in the same category as macros, and I can't recommend it.
Potentially controversial response: Who cares? The alternative in D is basically just the same code with some quotes around it (a DSL like pegged). You can do real sin with operating overloading, or just badly chosen operators, but this particular one really isn't that bad. The alternative is preprocessor macros, which are considerably worse.
Oct 14 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/14/2022 1:49 PM, Max H wrote:
 Potentially controversial response: Who cares? The alternative in D is
basically 
 just the same code with some quotes around it (a DSL like pegged).
With color syntax highlighting, nobody will think the quoted string is ordinary D code. It's also why the `mixin` keyword is a keyword - to make it stand out.
 You can do real sin with operating overloading, or just badly chosen
operators, 
 but this particular one really isn't that bad. The alternative is preprocessor 
 macros, which are considerably worse.
The best alternative to a proper DSL is to simply use functions instead of operators.
Oct 14 2022
prev sibling parent Max Samukha <maxsamukha gmail.com> writes:
On Thursday, 13 October 2022 at 21:01:08 UTC, Araq wrote:
 Before C came along x << y already meant "x is much smaller 
 than y" and x || y sometimes meant "run x and y in parallel". 
 "Nonstandard purposes" hardly means anything. Use the operators 
 as you see fit.
Indeed. Even * and + hardly have a standard meaning outside of elementary school arithmetic.
Oct 13 2022
prev sibling next sibling parent "H. S. Teoh" <hsteoh qfbox.info> writes:
On Thu, Oct 13, 2022 at 08:28:52PM +0000, solidstate1991 via Digitalmars-d
wrote:
 So I watched this video:
 
 https://youtu.be/G6b62HmsO6M
 
 And Walter talked about using operator overloading for nonstandard
 purposes.
 
 So in my collections library, I used it to implement set operators,
 but since set operators don't exist in the D standard (and require
 unicode, which would upset a lot of people, especially those who don't
 know what Win + '.' does), I had to use operators that have similar
 function in other spaces.
I've also written set operators for one of my projects. I also succumbed to the temptation of overloading bit operators (`|` for set union and `&` for set intersection), because of the obvious analogy to bit vectors. Originally I wanted to use `+` and `*`, but on second thoughts that's too remote from the usual meaning of + and *, and would make the resulting code too easy to misread, so I settled on | and & instead. At least the meaning corresponds, if you think of your set in terms of a glorified set of bits indicating the presence/absence of each element. `*` would be too easy to misunderstand as a Cartesian product in the context of sets.
 I personally haven't used them yet in my projects (except for the
 unittests), so it's not too late to remove them, but I don't know if
 anyone else might be using them or not.
 
 Link to my library with an example offense:
https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L356
My personal opinion -- keep | and &, get rid of + and *. T -- It is the quality rather than the quantity that matters. -- Lucius Annaeus Seneca
Oct 13 2022
prev sibling next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Thursday, 13 October 2022 at 20:28:52 UTC, solidstate1991 
wrote:
 So I watched this video:

 https://youtu.be/G6b62HmsO6M

 And Walter talked about using operator overloading for 
 nonstandard purposes.

 So in my collections library, I used it to implement set 
 operators, but since set operators don't exist in the D 
 standard (and require unicode, which would upset a lot of 
 people, especially those who don't know what Win + '.' does), I 
 had to use operators that have similar function in other spaces.

 I personally haven't used them yet in my projects (except for 
 the unittests), so it's not too late to remove them, but I 
 don't know if anyone else might be using them or not.

 Link to my library with an example offense: 
 https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L356
On Thursday, 13 October 2022 at 20:28:52 UTC, solidstate1991 wrote:
 So I watched this video:

 https://youtu.be/G6b62HmsO6M

 And Walter talked about using operator overloading for 
 nonstandard purposes.

 So in my collections library, I used it to implement set 
 operators, but since set operators don't exist in the D 
 standard (and require unicode, which would upset a lot of 
 people, especially those who don't know what Win + '.' does), I 
 had to use operators that have similar function in other spaces.

 I personally haven't used them yet in my projects (except for 
 the unittests), so it's not too late to remove them, but I 
 don't know if anyone else might be using them or not.

 Link to my library with an example offense: 
 https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L356
AFAIC, operators are infix functions with funny names. I think Haskell got it this exactly right syntax-wise, but definitely not culture-wise given their abuse of operators. If you have to tell people that you "pronounce" `>>=` as "shove", well... As Bjarne said once in response to complaints that operator overloading lets people write code that doesn't do what you expect: ``` // notice how the code and the docs lie /** * Adds two numbers */ int sum(int i, int j) { return i - j; // oops } ```
Oct 14 2022
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/14/2022 12:54 AM, Atila Neves wrote:
 As Bjarne said once in response to complaints that operator overloading lets 
 people write code that doesn't do what you expect:
 
 ```
 // notice how the code and the docs lie
 /**
   * Adds two numbers
   */
 int sum(int i, int j) {
      return i - j;  // oops
 }
 ```
True that documentation often (always?) lies about what the code actually does. But the causes of this are usually because of programmer laziness and/or error in documenting it correctly. But operating overloading for non-arithmetic purposes is *deliberately* doing the unexpected.
Oct 14 2022
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 14 October 2022 at 18:29:10 UTC, Walter Bright wrote:
 [snip]
 True that documentation often (always?) lies about what the 
 code actually does. But the causes of this are usually because 
 of programmer laziness and/or error in documenting it correctly.

 But operating overloading for non-arithmetic purposes is 
 *deliberately* doing the unexpected.
What is your opinion about R's custom infix binary operators? (ignoring that R is dynamically typed) So for instance, you can make a function ``` `%foo%` <- function(x, y) { #does something } ``` and use it like `x %foo% y` The surrounding `%` lets the user know that anything could be happening in there. However, it doesn't have to just be some string, it could be anything. For instance, R comes with %*% built-in for matrix multiplication and a few others. From D's perspective, it doesn't really make sense to use a string since we have UFCS and it is just as easy to use `x.foo(y)` [in R you would have to do foo(x, y) if this feature didn't exist]. However, it is useful when it is some symbol that would otherwise have a longer name. Code that is full of `X.matmul(Y)` is harder to read than `X %*% Y`.
Oct 14 2022
next sibling parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Fri, Oct 14, 2022 at 08:24:47PM +0000, jmh530 via Digitalmars-d wrote:
[...]
 So for instance, you can make a function
 ```
 `%foo%` <- function(x, y) { #does something }
 ```
 and use it like `x %foo% y`
 
 The surrounding `%` lets the user know that anything could be
 happening in there. However, it doesn't have to just be some string,
 it could be anything. For instance, R comes with %*% built-in for
 matrix multiplication and a few others.
IMO, %*% is extremely ugly to read.
 From D's perspective, it doesn't really make sense to use a string
 since we have UFCS and it is just as easy to use `x.foo(y)` [in R you
 would have to do foo(x, y) if this feature didn't exist]. However, it
 is useful when it is some symbol that would otherwise have a longer
 name. Code that is full of `X.matmul(Y)` is harder to read than `X %*%
 Y`.
It's just a matter of formatting; just write it like this: X .mul (Y) and it will read just fine. The mandatory parentheses are actually a good thing to prevent confusion with operator precedence. (Making operator precedence user-configurable may not be a good idea -- it forces you to do semantic analysis before the syntax can be parsed, and will add far more complexity to the parser than is justifiable by the marginal benefits.) For this specific example, though, I'd say just overload *. Matrix multiplication is called "multiplication" because it generally *does* behave like a multiplicative arithmetic operator. As opposed to like array manipulation or I/O. So I'd call it an appropriate use of operator overloading in this case. T -- One Word to write them all, One Access to find them, One Excel to count them all, And thus to Windows bind them. -- Mike Champion
Oct 14 2022
parent jmh530 <john.michael.hall gmail.com> writes:
On Friday, 14 October 2022 at 21:15:12 UTC, H. S. Teoh wrote:
 [snip]
 For this specific example, though, I'd say just overload *. 
 Matrix multiplication is called "multiplication" because it 
 generally *does* behave like a multiplicative arithmetic 
 operator. As opposed to like array manipulation or I/O.  So I'd 
 call it an appropriate use of operator overloading in this case.


 T
D's built-in slices already have * as element-wise multiplication. It makes things a little more confusing to switch it up.
Oct 15 2022
prev sibling next sibling parent reply Dennis <dkorpel gmail.com> writes:
On Friday, 14 October 2022 at 20:24:47 UTC, jmh530 wrote:
 So for instance, you can make a function
 ```
 `%foo%` <- function(x, y) { #does something }
 ```
 and use it like `x %foo% y`
You can actually do that in D with some hacks: ```D struct Operator(alias fn, string operator = "/") { static auto opBinaryRight(string op : operator, T...)(T value1) { struct Result { auto opBinary(string op : operator, U...)(U value2) if (__traits(compiles, fn(value1, value2))) { return fn(value1, value2); } } Result result; return result; } } void main() { import std.algorithm.comparison; alias min = Operator!(std.algorithm.comparison.min, "%"); assert(1 %min% 3 == 1); } ``` Credit to Simen Kjærås: https://forum.dlang.org/post/ldiwiffdyzeswggytudh forum.dlang.org
Oct 14 2022
parent jmh530 <john.michael.hall gmail.com> writes:
On Friday, 14 October 2022 at 21:49:31 UTC, Dennis wrote:
 On Friday, 14 October 2022 at 20:24:47 UTC, jmh530 wrote:
 [...]
You can actually do that in D with some hacks: ```D struct Operator(alias fn, string operator = "/") { static auto opBinaryRight(string op : operator, T...)(T value1) { struct Result { auto opBinary(string op : operator, U...)(U value2) if (__traits(compiles, fn(value1, value2))) { return fn(value1, value2); } } [...]
That's a new one to me. Very interesting.
Oct 15 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/14/2022 1:24 PM, jmh530 wrote:
 What is your opinion about R's custom infix binary operators? (ignoring that R 
 is dynamically typed)
 
 So for instance, you can make a function
 ```
 `%foo%` <- function(x, y) { #does something }
 ```
 and use it like `x %foo% y`
I've thought about it many times. It keeps coming back to "it's just too ugly." Operator precedence is also a problem.
Oct 14 2022
parent reply rassoc <rassoc posteo.de> writes:
On 10/15/22 00:44, Walter Bright via Digitalmars-d wrote:
 I've thought about it many times. It keeps coming back to "it's just too ugly."
 
 Operator precedence is also a problem.
Raku (formerly Perl 6) is very interesting in that regard. They not only allow you to define custom operators, but also specify their precedence and associativity right in the function signature. sub prefix:<Σ>(...) sub infix:<!!>(...) is tighter(&infix:<+>) sub infix:<§>(...) is assoc<right> sub circumfix:<[ ]>(...) And they go even further and allow you to combine these to form meta operators.
 my  a = 1, 2, 3

((1 1) (2 2) (3 3))
  a Z+  a
If only the language wasn't dog slow. :)
Oct 14 2022
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/14/2022 6:11 PM, rassoc wrote:
 Raku (formerly Perl 6) is very interesting in that regard. They not only allow 
 you to define custom operators, but also specify their precedence and 
 associativity right in the function signature.
Doing that means the code cannot be successfully parsed without semantic analysis. One goal of D was to be able to keep the lexing, parsing, and semantic analysis as distinct passes.
Oct 14 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 15.10.22 08:59, Walter Bright wrote:
 On 10/14/2022 6:11 PM, rassoc wrote:
 Raku (formerly Perl 6) is very interesting in that regard. They not 
 only allow you to define custom operators, but also specify their 
 precedence and associativity right in the function signature.
Doing that means the code cannot be successfully parsed without semantic analysis. One goal of D was to be able to keep the lexing, parsing, and semantic analysis as distinct passes.
You can parse it as a single "operator expression" and resolve precedence during semantic analysis.
Oct 15 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/15/2022 5:41 AM, Timon Gehr wrote:
 You can parse it as a single "operator expression" and resolve precedence
during 
 semantic analysis.
The operator precedence drives the parse.
Oct 15 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 15.10.22 18:45, Walter Bright wrote:
 On 10/15/2022 5:41 AM, Timon Gehr wrote:
 You can parse it as a single "operator expression" and resolve 
 precedence during semantic analysis.
The operator precedence drives the parse.
It does not _have_ to work that way.
Oct 15 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/15/2022 10:42 AM, Timon Gehr wrote:
 On 15.10.22 18:45, Walter Bright wrote:
 On 10/15/2022 5:41 AM, Timon Gehr wrote:
 You can parse it as a single "operator expression" and resolve precedence 
 during semantic analysis.
The operator precedence drives the parse.
It does not _have_ to work that way.
I know. The tokens can be "parsed" by just storing them in an array, deferring constructing the AST until the semantics are known. But that isn't really parsing, and makes 3rd party tools much more complex.
Oct 15 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/15/22 20:22, Walter Bright wrote:
 On 10/15/2022 10:42 AM, Timon Gehr wrote:
 On 15.10.22 18:45, Walter Bright wrote:
 On 10/15/2022 5:41 AM, Timon Gehr wrote:
 You can parse it as a single "operator expression" and resolve 
 precedence during semantic analysis.
The operator precedence drives the parse.
It does not _have_ to work that way.
I know. The tokens can be "parsed" by just storing them in an array, deferring constructing the AST until the semantics are known. But that isn't really parsing,
You can parse everything except operator precedence, no need to store a token stream. In general, aspects of the AST that depend on semantic information should be resolved during semantic analysis, and if that is the case for operator precedence that's how you parse it. There's no need to have any feedback from semantic to the parser.
 and makes 3rd party tools much more complex.
Depends a bit on the tool. I guess it is true for a tool whose only purpose is to parenthesize expressions according to operator precedence. :) It's not adding much complexity to tools that already need to run full semantic.
Oct 16 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/16/2022 12:53 PM, Timon Gehr wrote:
 You can parse everything except operator precedence, no need to store a token 
 stream.
Well, an array of terms. Given a*b*c, is that (a*b)*c or a*(b*c)? You'd have to wait for semantics to not only know precedence, but left and right associativity. I can see how that's possible, but don't like it.
Oct 26 2022
prev sibling parent solidstate1991 <laszloszeremi outlook.com> writes:
On Saturday, 15 October 2022 at 01:11:02 UTC, rassoc wrote:
 Raku (formerly Perl 6) is very interesting in that regard. They 
 not only allow you to define custom operators, but also specify 
 their precedence and associativity right in the function 
 signature.

 sub prefix:<Σ>(...)
 sub infix:<!!>(...) is tighter(&infix:<+>)
 sub infix:<§>(...) is assoc<right>
 sub circumfix:<[ ]>(...)

 And they go even further and allow you to combine these to form 
 meta operators.

 my  a = 1, 2, 3

((1 1) (2 2) (3 3))
  a Z+  a
If only the language wasn't dog slow. :)
At least Σ is perfectly doable in D thanks to its unicode support (if I remember correctly) ```d public double Σ(...) { //code goes here } ``` Languages with custom operators will compile slow and will run even slower if they're scripting languages. My alternative for D would be just expand upon the currently existing number of operators with unicode characters, but also give them some alternative way to access them (e.g. having both an `⋃` operator and an `__opUnion` substitute), so people won't get a heart attack if they don't know how to get them on their keyboards.
Oct 16 2022
prev sibling next sibling parent reply Max H <maxhaton gmail.com> writes:
On Friday, 14 October 2022 at 18:29:10 UTC, Walter Bright wrote:
 On 10/14/2022 12:54 AM, Atila Neves wrote:
 As Bjarne said once in response to complaints that operator 
 overloading lets people write code that doesn't do what you 
 expect:
 
 ```
 // notice how the code and the docs lie
 /**
   * Adds two numbers
   */
 int sum(int i, int j) {
      return i - j;  // oops
 }
 ```
True that documentation often (always?) lies about what the code actually does. But the causes of this are usually because of programmer laziness and/or error in documenting it correctly. But operating overloading for non-arithmetic purposes is *deliberately* doing the unexpected.
A slightly more useful way of thinking about this I think is to think about it algebraically, i.e. If the nu-operation is confusing algebraically then it is *definitely* wrong versus merely not to taste. You can do useful algebra on things that wouldn't typically be considered arithmetic, that algebra often has an analogue in familiar arithmetic on numbers (we'll gloss over floating point arithmetic...) In the case of `sum`, we'd expect it to be associative - it's not, something has gone wrong. This is a more precise way of expressing that "Go home, you're drunk" feeling from this kind of code. D not using + for strings was something that helped sell me on it early on. Intuitively we all know concatenation isn't commutative anyway, but it doesn't hurt to express it lexically.
Oct 14 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/14/2022 2:07 PM, Max H wrote:
 D not using + for strings was something that helped sell me on it early on. 
When I was working on that, I could not believe that other languages persisted in conflating add with concatenate, which continues to cause confusion.
Oct 14 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 14 October 2022 at 22:48:51 UTC, Walter Bright wrote:
 On 10/14/2022 2:07 PM, Max H wrote:
 D not using + for strings was something that helped sell me on 
 it early on.
When I was working on that, I could not believe that other languages persisted in conflating add with concatenate, which continues to cause confusion.
Perhaps ironically, one of the languages that got this right was Perl: it used + for numeric addition and . (period) for string concatenation.
Oct 14 2022
parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Sat, Oct 15, 2022 at 12:26:17AM +0000, Paul Backus via Digitalmars-d wrote:
 On Friday, 14 October 2022 at 22:48:51 UTC, Walter Bright wrote:
 On 10/14/2022 2:07 PM, Max H wrote:
 D not using + for strings was something that helped sell me on it
 early on.
When I was working on that, I could not believe that other languages persisted in conflating add with concatenate, which continues to cause confusion.
Perhaps ironically, one of the languages that got this right was Perl: it used + for numeric addition and . (period) for string concatenation.
In spite of all the hate (and actual flaws), I actually quite like many aspects of Perl. Built-in AA's is one, which is also a draw for me in D, in spite of the flaws in the current implementation in D. As is built-in regexes. D has std.regex, but not having direct language support does increase the friction a little. And the current implementation is a bit over-heavy on templates and so slows down compilation significantly for shell-script replacements, which detracts from an otherwise perfect niche for D. Sigils is another feature that most people love to hate, but it's actually very useful: the variable namespace will never collide with keywords, and when glancing at code you can immediately tell which identifiers are variables are even if you don't know the definitions of the identifiers. Having said that, though, the quirky use of $ with arrays/hashes when referring to individual elements does detract from Perl's implementation of sigils. T -- The trouble with TCP jokes is that it's like hearing the same joke over and over.
Oct 14 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/14/2022 5:58 PM, H. S. Teoh wrote:
 Built-in AA's is one, which is also a draw for me in D, in spite of the
 flaws in the current implementation in D.  As is built-in regexes. D has
 std.regex, but not having direct language support does increase the
 friction a little. And the current implementation is a bit over-heavy on
 templates and so slows down compilation significantly for shell-script
 replacements, which detracts from an otherwise perfect niche for D.
You can always use the D1 regexes, which are still around in the unDead library. They don't use templates.
 Sigils is another feature that most people love to hate, but it's
 actually very useful: the variable namespace will never collide with
 keywords, and when glancing at code you can immediately tell which
 identifiers are variables are even if you don't know the definitions of
 the identifiers. Having said that, though, the quirky use of $ with
 arrays/hashes when referring to individual elements does detract from
 Perl's implementation of sigils.
Syntax highlighting works delightfully in distinguishing keywords from identifiers.
Oct 15 2022
next sibling parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Sat, Oct 15, 2022 at 12:01:54AM -0700, Walter Bright via Digitalmars-d wrote:
 On 10/14/2022 5:58 PM, H. S. Teoh wrote:
 Built-in AA's is one, which is also a draw for me in D, in spite of the
 flaws in the current implementation in D.  As is built-in regexes. D has
 std.regex, but not having direct language support does increase the
 friction a little. And the current implementation is a bit over-heavy on
 templates and so slows down compilation significantly for shell-script
 replacements, which detracts from an otherwise perfect niche for D.
You can always use the D1 regexes, which are still around in the unDead library. They don't use templates.
But why aren't we improving Phobos regexes then?
 Sigils is another feature that most people love to hate, but it's
 actually very useful: the variable namespace will never collide with
 keywords, and when glancing at code you can immediately tell which
 identifiers are variables are even if you don't know the definitions
 of the identifiers. Having said that, though, the quirky use of $
 with arrays/hashes when referring to individual elements does
 detract from Perl's implementation of sigils.
Syntax highlighting works delightfully in distinguishing keywords from identifiers.
I find syntax highlighting more distracting than helpful. Especially when they make unfounded assumptions about the background color of my terminal, such that some items end up being unreadable or barely readable. (I know, it's configurable, etc., etc., but then I'm spending time struggling with a problem that didn't need to be there in the first place, rather than focusing on my programming problem.) T -- Life is unfair. Ask too much from it, and it may decide you don't deserve what you have now either.
Oct 15 2022
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/15/2022 5:56 PM, H. S. Teoh wrote:
 But why aren't we improving Phobos regexes then?
It requires someone taking the initiative to improve them.
Oct 16 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/15/2022 5:56 PM, H. S. Teoh wrote:
 I find syntax highlighting more distracting than helpful.  Especially
 when they make unfounded assumptions about the background color of my
 terminal, such that some items end up being unreadable or barely
 readable. (I know, it's configurable, etc., etc., but then I'm spending
 time struggling with a problem that didn't need to be there in the first
 place, rather than focusing on my programming problem.)
This is why it's configurable - some people like it, some don't. Personally, I prefer to use subtle colors for it. The default is what most people seem to like.
Oct 16 2022
prev sibling parent rassoc <rassoc posteo.de> writes:
On 10/16/22 02:56, H. S. Teoh via Digitalmars-d wrote:
 But why aren't we improving Phobos regexes then?
No takers yet, see: https://forum.dlang.org/post/thzswscbklnndbaeknvv forum.dlang.org I tried fixing a regex backtracking bug I encountered a while ago, but felt quite a bit lost in that code base. One of these days. :)
Oct 15 2022
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 14 October 2022 at 18:29:10 UTC, Walter Bright wrote:
 On 10/14/2022 12:54 AM, Atila Neves wrote:
 As Bjarne said once in response to complaints that operator 
 overloading lets people write code that doesn't do what you 
 expect:
 
 ```
 // notice how the code and the docs lie
 /**
   * Adds two numbers
   */
 int sum(int i, int j) {
      return i - j;  // oops
 }
 ```
True that documentation often (always?) lies about what the code actually does. But the causes of this are usually because of programmer laziness and/or error in documenting it correctly. But operating overloading for non-arithmetic purposes is *deliberately* doing the unexpected.
It depends. I don't think this is unexpected: struct Path { string value; Path opBinary(string op)(in string path) if(op == "/") { import std.path : buildPath; return Path(buildPath(value, path)); } } void main() { assert(Path("/foo") / "bar" == Path("/foo/bar")); }
Oct 24 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 24 October 2022 at 11:25:58 UTC, Atila Neves wrote:
 It depends. I don't think this is unexpected:


 struct Path {
     string value;
     Path opBinary(string op)(in string path) if(op == "/") {
         import std.path : buildPath;
         return Path(buildPath(value, path));
     }
 }

 void main() {
     assert(Path("/foo") / "bar" == Path("/foo/bar"));
 }
version (Windows) { assert(Path("C:\Users") / "Paul" == Path("C:\Users\Paul")); } Better to just use ~ for concatenation and not try to be cute here, IMO. (Also, if the inverse of division is multiplication, does that mean Path("/foo/bar") * "bar" == Path("/foo")?)
Oct 24 2022
parent Atila Neves <atila.neves gmail.com> writes:
On Monday, 24 October 2022 at 14:16:57 UTC, Paul Backus wrote:
 On Monday, 24 October 2022 at 11:25:58 UTC, Atila Neves wrote:
 It depends. I don't think this is unexpected:


 struct Path {
     string value;
     Path opBinary(string op)(in string path) if(op == "/") {
         import std.path : buildPath;
         return Path(buildPath(value, path));
     }
 }

 void main() {
     assert(Path("/foo") / "bar" == Path("/foo/bar"));
 }
version (Windows) { assert(Path("C:\Users") / "Paul" == Path("C:\Users\Paul")); }
Yes? That's what I'd expect the result to be.
 Better to just use ~ for concatenation and not try to be cute 
 here, IMO.
Also valid.
 (Also, if the inverse of division is multiplication, does that 
 mean Path("/foo/bar") * "bar" == Path("/foo")?)
That'd be... horrible. The "it depends" I wrote would definitely be in favour of killing this with fire during code review.
Oct 25 2022
prev sibling parent cc <cc nevernet.com> writes:
On Friday, 14 October 2022 at 07:54:40 UTC, Atila Neves wrote:
 As Bjarne said once in response to complaints that operator 
 overloading lets people write code that doesn't do what you 
 expect:

 ```
 // notice how the code and the docs lie
 /**
  * Adds two numbers
  */
 int sum(int i, int j) {
     return i - j;  // oops
 }
 ```
``` struct APerfectlyHarmlessDefaultZeroInitializedStruct { int i; long l; string s; Object o; float f; // oops! } ```
Oct 14 2022
prev sibling parent kdevel <kdevel vogtner.de> writes:
On Thursday, 13 October 2022 at 20:28:52 UTC, solidstate1991 
wrote:

 require unicode, which would upset a lot of people
Require unicode and break another convention in one go is even more effective: - https://forum.dlang.org/thread/pwotyniksrskdzmeafin forum.dlang.org "1 - 17 ms, 553 ╬╝s, and 1 hnsec" May 16, 2019
Oct 14 2022