www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Zcoin implementation bug enabled attacker to create 548,000 Zcoins

reply Walter Bright <newshound2 digitalmars.com> writes:
https://makebitcoingreatagain.wordpress.com/2017/02/18/is-the-zcoin-bug-in-checktransaction/#update6

The error is here:

     https://github.com/zcoinofficial/zcoin/blob/81a667867b5d8489...

and the line of code:

     zccoinSpend.denomination == libzerocoin::ZQ_LOVELACE;

In other words, a statement with no effect. In D, such a line gives an error, 
not a warning:

     Error: == has no effect in expression
Mar 06 2017
next sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Tuesday, 7 March 2017 at 05:44:49 UTC, Walter Bright wrote:
 https://makebitcoingreatagain.wordpress.com/2017/02/18/is-the-zcoin-bug-in-checktransaction/#update6

 The error is here:

     
 https://github.com/zcoinofficial/zcoin/blob/81a667867b5d8489...

 and the line of code:

     zccoinSpend.denomination == libzerocoin::ZQ_LOVELACE;

 In other words, a statement with no effect. In D, such a line 
 gives an error, not a warning:

     Error: == has no effect in expression
To be fair, this also would have been caught with proper testing ... which obviously didn't happen. OT from D: Run screaming in the other direction of this shit. For this to pass through I wouldn't trust these devs with $10, let alone any of my financial security. I still have trust issues with coinbase, let alone some fly-by-night custom bitcoin derivative.
Mar 06 2017
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/6/2017 10:06 PM, Jack Stouffer wrote:
 To be fair, this also would have been caught with proper testing ... which
 obviously didn't happen.
My idea of fair is it should never have gotten past the compiler. It's a simple mistake for the compiler to detect.
Mar 06 2017
parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 7 March 2017 at 06:59:38 UTC, Walter Bright wrote:
 On 3/6/2017 10:06 PM, Jack Stouffer wrote:
 To be fair, this also would have been caught with proper 
 testing ... which
 obviously didn't happen.
My idea of fair is it should never have gotten past the compiler. It's a simple mistake for the compiler to detect.
clang 3.9.1 with 0 flags used: $ cat zcoin.cpp int main() { int a, b; a == b; } $ clang++ zcoin.cpp zcoin.cpp:3:7: warning: equality comparison result unused [-Wunused-comparison] a == b; ~~^~~~ zcoin.cpp:3:7: note: use '=' to turn this equality comparison into an assignment a == b; ^~ = 1 warning generated. gcc, sadly, warns about nothing by default but does with `-Wall`. But... anyone not using `-Wall -Wextra -Werror` on a new C++ codebase shouldn't be writing C++ AFAIC*. And then there's the aforementioned lack of adequate testing. Does D do better? Sort of (clang issues a warning, which I know can be and is often ignored). Is this an example of amateur hour by the Zcoin devs? Indubitably. Atila * Maybe there should be something like a driver's license for C++ where devs have to pass a test before they're allowed to write code. Something like "Do you know how to use std::enable_if without looking at cppreference.com? No? Fail." (I'd fail, I _always_ have to look up how to use enable_if. Then again, it _is_ a horrible hacky hack of a hack based on the hack that is SNIFAE).
Mar 07 2017
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/7/2017 9:45 AM, Atila Neves wrote:
 1 warning generated.
Pretty much all C++ compilers will generate warnings for this. The thing about warnings, though, is they imply that there are situations where the code is acceptable. I can't think of any. It needs to be an error. It should never pass the compiler.
 Does D do better?
Yes, it's an error in D.
Mar 07 2017
parent reply Jerry <hurricane hereiam.com> writes:
On Tuesday, 7 March 2017 at 21:34:35 UTC, Walter Bright wrote:
 On 3/7/2017 9:45 AM, Atila Neves wrote:
 1 warning generated.
Pretty much all C++ compilers will generate warnings for this. The thing about warnings, though, is they imply that there are situations where the code is acceptable. I can't think of any. It needs to be an error. It should never pass the compiler.
What about Ketmar's example? It seems to have been glossed over. Still waiting on D to do something about comparisons between signed and unsigned types, or is having no warning or error the desired behavior?
Mar 12 2017
next sibling parent XavierAP <n3minis-git yahoo.es> writes:
On Sunday, 12 March 2017 at 08:03:46 UTC, Jerry wrote:
 On Tuesday, 7 March 2017 at 21:34:35 UTC, Walter Bright wrote:
 On 3/7/2017 9:45 AM, Atila Neves wrote:
 1 warning generated.
Pretty much all C++ compilers will generate warnings for this. The thing about warnings, though, is they imply that there are situations where the code is acceptable. I can't think of any. It needs to be an error. It should never pass the compiler.
What about Ketmar's example? It seems to have been glossed over.
We've discussed it quite thoroughly... Again IMO it's not a good idea to require opEquals and others to be pure. Not much of a discussion really since it would be a breaking change, besides the opposite of an improvement. Again the only good possibility I can think if we really really want to disallow a==b etc. for custom types, is to add a new feature to the specification. This change would also be breaking but at least of bad practice only. But how to introduce it is not easy: it could be either a new very strange attribute (method may have side effects inside the defining type but not outside) too similar to pure and const (no thanks) or rather a special case for some operators, e.g. a==b statement is never allowed even if opEquals isn't pure. The problem is for example that you want to do the same for operator "+" but not "++", and both are overloaded by opUnary, so the solution is even harder here. I think my conclusion is leave the thing as it is :)
 Still waiting on D to do something about comparisons between 
 signed and unsigned types, or is having no warning or error the 
 desired behavior?
For me yes it's the desired one. Implicit casts leading to overflow are a different issue. It looks they are never checked even in safe environments (I know, checked{} and unchecked{} environments: https://msdn.microsoft.com/library/khy08726.aspx But now we're off topic...
Mar 12 2017
prev sibling next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
Jerry wrote:

 On Tuesday, 7 March 2017 at 21:34:35 UTC, Walter Bright wrote:
 On 3/7/2017 9:45 AM, Atila Neves wrote:
 1 warning generated.
Pretty much all C++ compilers will generate warnings for this. The thing about warnings, though, is they imply that there are situations where the code is acceptable. I can't think of any. It needs to be an error. It should never pass the compiler.
What about Ketmar's example? It seems to have been glossed over.
nobody cares, and half (random approximation) of writers didn't even understood the problem -- see the discussion about "opEquals() purity", "language changes", and other things that have absolutely nothing to do with what i wrote.
Mar 12 2017
prev sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Sunday, 12 March 2017 at 08:03:46 UTC, Jerry wrote:
 What about Ketmar's example? It seems to have been glossed over.
It wasn't. * The problem was described by Ketmar * People explained why you can't give the default behavior to that code * A compromise was proposed and documented in a bug report
 Still waiting on D to do something about comparisons between 
 signed and unsigned types
Don't hold your breath. The fix has been approved, but the compiler devs are all working on other things.
Mar 12 2017
parent Jerry <hurricane hereiam.com> writes:
On Sunday, 12 March 2017 at 17:33:23 UTC, Jack Stouffer wrote:
 On Sunday, 12 March 2017 at 08:03:46 UTC, Jerry wrote:
 What about Ketmar's example? It seems to have been glossed 
 over.
It wasn't.
It was (by walter).
 Don't hold your breath. The fix has been approved, but the 
 compiler devs are all working on other things.
I don't expect anything less than nothing.
Mar 12 2017
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Tuesday, 7 March 2017 at 17:45:13 UTC, Atila Neves wrote:
 write code. Something like "Do you know how to use 
 std::enable_if without looking at cppreference.com? No? Fail." 
 (I'd fail, I _always_ have to look up how to use enable_if. 
 Then again, it _is_ a horrible hacky hack of a hack based on 
 the hack that is SNIFAE).
"std::enable_if" is a hack, but I don't think the underlying principle of SFINAE is a hack as such, although it isn't principled in C++... SFINAE basically allows deduction and pattern matching at some level, which is what turned it into a useful programming mechanism. And those can be desirable features. Of course the syntax isn't great for the casual reader, e.g.: "template<T, typename std:enable_if_t<T == MyType, int> == 0> ..." But the crux to making C++ code readable is to use a smaller set of general formulations, make those idioms and avoid all the alternative ways that are less general. void_t is kinda neat: "template<typename T, typename = void_t<>>struct mystuff ..." "template<typename T> struct mystuff<T, void_t<A> > ..." "template<typename T> struct mystuff<T, void_t<B> > ..."
Mar 09 2017
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Thursday, 9 March 2017 at 12:07:54 UTC, Ola Fosheim Grøstad 
wrote:
 "template<typename T, typename = void_t<>>struct mystuff ..."
 "template<typename T> struct mystuff<T, void_t<A> > ..."
 "template<typename T> struct mystuff<T, void_t<B> > ..."
Gah, that made no sense, meant something like this: "template<typename T, typename = std::void_t<>>struct mystuff ..." "template<typename T> struct mystuff<T, std::void_t<typename T::Fish>> > ..." "template<typename T> struct mystuff<T, std::void_t<typename T::Cat>> > ..."
Mar 09 2017
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
Walter Bright wrote:

 https://makebitcoingreatagain.wordpress.com/2017/02/18/is-the-zcoin-bug-in-checktransaction/#update6

 The error is here:

 https://github.com/zcoinofficial/zcoin/blob/81a667867b5d8489...

 and the line of code:

 zccoinSpend.denomination == libzerocoin::ZQ_LOVELACE;

 In other words, a statement with no effect. In D, such a line gives an 
 error, not a warning:

 Error: == has no effect in expression
only for primitive types, sadly. void main () { Object a, b; a == b; } oops. no more error messages. yes, i know that this invokes `opEquals()`, and `opEquals()` can have side-effects. but what are the chances of writing such code *intentionally*? i guess, compiler should emit error for *any* usage of "==" without using the result, even if it lowers to `opEquals()` or something. and if one really want to use it and drop it's result, there is always escape path: cast(void)(a == b);
Mar 07 2017
parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Tuesday, 7 March 2017 at 15:05:45 UTC, ketmar wrote:
 only for primitive types, sadly.

  void main () {
    Object a, b;
    a == b;
  }

 oops. no more error messages. yes, i know that this invokes 
 `opEquals()`, and `opEquals()` can have side-effects. but what 
 are the chances of writing such code *intentionally*?
Hmm, I guess the compiler can (and should) output an error message if it knows that opEquals is `pure`. https://issues.dlang.org/show_bug.cgi?id=17245
Mar 07 2017
parent reply ketmar <ketmar ketmar.no-ip.org> writes:
Jack Stouffer wrote:

 On Tuesday, 7 March 2017 at 15:05:45 UTC, ketmar wrote:
 only for primitive types, sadly.

 void main () {
 Object a, b;
 a == b;
 }

 oops. no more error messages. yes, i know that this invokes 
 `opEquals()`, and `opEquals()` can have side-effects. but what are the 
 chances of writing such code *intentionally*?
Hmm, I guess the compiler can (and should) output an error message if it knows that opEquals is `pure`. https://issues.dlang.org/show_bug.cgi?id=17245
yet Object's `opEquals()` is not pure (and it cannot be, to allow non-pure overloads). still, the code i've written has no sense.
Mar 07 2017
parent reply qznc <qznc web.de> writes:
On Tuesday, 7 March 2017 at 15:34:54 UTC, ketmar wrote:
 Jack Stouffer wrote:

 On Tuesday, 7 March 2017 at 15:05:45 UTC, ketmar wrote:
 only for primitive types, sadly.

 void main () {
 Object a, b;
 a == b;
 }

 oops. no more error messages. yes, i know that this invokes 
 `opEquals()`, and `opEquals()` can have side-effects. but 
 what are the chances of writing such code *intentionally*?
Hmm, I guess the compiler can (and should) output an error message if it knows that opEquals is `pure`. https://issues.dlang.org/show_bug.cgi?id=17245
yet Object's `opEquals()` is not pure (and it cannot be, to allow non-pure overloads). still, the code i've written has no sense.
I'm curious. Where does it make sense for opEquals to be non-pure? Likewise opCmp, etc. Maybe we want to support weird DSLs, where operators are reused with very different semantics? For example, the pyparsing parser generator allows you to write a grammar like [0] this: exp << Group(lparen + op + (number | exp) + (number | exp) + rparen) [0] http://pyparsing.wikispaces.com/file/view/pycalc.py/480674428/pycalc.py
Mar 09 2017
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Thursday, 9 March 2017 at 15:42:22 UTC, qznc wrote:
 I'm curious. Where does it make sense for opEquals to be 
 non-pure? Likewise opCmp, etc.
When the object need some kind of normalization to be comparable and you don't want to do the normalization every single time.
Mar 09 2017
parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Thursday, 9 March 2017 at 15:55:07 UTC, deadalnix wrote:
 On Thursday, 9 March 2017 at 15:42:22 UTC, qznc wrote:
 I'm curious. Where does it make sense for opEquals to be 
 non-pure? Likewise opCmp, etc.
When the object need some kind of normalization to be comparable and you don't want to do the normalization every single time.
I wonder how stupid it would be to cast the implementation to pure in this case.
Mar 09 2017
parent ketmar <ketmar ketmar.no-ip.org> writes:
John Colvin wrote:

 On Thursday, 9 March 2017 at 15:55:07 UTC, deadalnix wrote:
 On Thursday, 9 March 2017 at 15:42:22 UTC, qznc wrote:
 I'm curious. Where does it make sense for opEquals to be non-pure? 
 Likewise opCmp, etc.
When the object need some kind of normalization to be comparable and you don't want to do the normalization every single time.
I wonder how stupid it would be to cast the implementation to pure in this case.
as any other lie. broken promise == UB. while current compiler *may* tolerate it, broken promise is a broken promise.
Mar 09 2017
prev sibling next sibling parent reply Ivan Kazmenko <gassa mail.ru> writes:
On Thursday, 9 March 2017 at 15:42:22 UTC, qznc wrote:
 I'm curious. Where does it make sense for opEquals to be 
 non-pure? Likewise opCmp, etc.
An example would be tracking the number of comparisons made. This sounds like debug information (and then, debug statement can be used to escape purity), but perhaps may be applied beyond simple debugging and profiling. Ivan Kazmenko.
Mar 09 2017
parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Fri, Mar 10, 2017 at 03:45:37AM +0000, Ivan Kazmenko via Digitalmars-d wrote:
 On Thursday, 9 March 2017 at 15:42:22 UTC, qznc wrote:
 I'm curious. Where does it make sense for opEquals to be non-pure?
 Likewise opCmp, etc.
An example would be tracking the number of comparisons made. This sounds like debug information (and then, debug statement can be used to escape purity), but perhaps may be applied beyond simple debugging and profiling.
[...] The main practical use case I can think of is caching, e.g., if computing the (in)equality is expensive and you want to cache the result if the comparison is frequently made. But opEquals/opCmp being non-pure has been a big hindrance in the uptake of pure (and other attributes), because of the way the Object base class defines these methods, and since it was originally done before some of these attributes existed in the language, some derived classes may already depend on them being impure / throwing / etc., so changing it now would break code. Besides, if Object declares opEquals as pure, then *all* classes would be required to declare it as pure, which may be an onerous limitation. T -- This is a tpyo.
Mar 09 2017
prev sibling parent reply XavierAP <n3minis-git yahoo.es> writes:
On Thursday, 9 March 2017 at 15:42:22 UTC, qznc wrote:
 On Tuesday, 7 March 2017 at 15:34:54 UTC, ketmar wrote:
 Jack Stouffer wrote:

 On Tuesday, 7 March 2017 at 15:05:45 UTC, ketmar wrote:
 only for primitive types, sadly.

 void main () {
 Object a, b;
 a == b;
 }

 oops. no more error messages. yes, i know that this invokes 
 `opEquals()`, and `opEquals()` can have side-effects. but 
 what are the chances of writing such code *intentionally*?
Hmm, I guess the compiler can (and should) output an error message if it knows that opEquals is `pure`. https://issues.dlang.org/show_bug.cgi?id=17245
yet Object's `opEquals()` is not pure (and it cannot be, to allow non-pure overloads). still, the code i've written has no sense.
I'm curious. Where does it make sense for opEquals to be non-pure? Likewise opCmp, etc.
I my experience it is a bad idea to require such restrictive contracts at lower inheritance levels when others outside a library are supposed to inherit your class. My case was a calculation object in C++, a calculation is a mathematical formula, so in the base class I made the method const, and the simple implementation inside had no problems with that. But a big project plugged into the rest of calculations in the library, while overriding this calculation with its own FEM engine, which is expensive to run, and should be cached. I had to redesign the library and remove that const. So result caching is indeed an example, like HS Teoh said. Going back to the original question above, if you really want the compiler to complain about a==b statements for custom types, rather than forcing opEquals to be pure, it would make more sense for the compiler to define which operator overloads are allowed in this way (++, --, etc) and which aren't (==, +, -, etc).
 Maybe we want to support weird DSLs, where operators are reused 
 with very different semantics? For example, the pyparsing 
 parser generator allows you to write a grammar like [0] this:
Maybe... I usually hate that stuff a-la-C++ iostream but, inverting the question, do you want to disallow it?
Mar 09 2017
parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Fri, Mar 10, 2017 at 07:47:43AM +0000, XavierAP via Digitalmars-d wrote:
 On Thursday, 9 March 2017 at 15:42:22 UTC, qznc wrote:
[...]
 Maybe we want to support weird DSLs, where operators are reused with
 very different semantics? For example, the pyparsing parser
 generator allows you to write a grammar like [0] this:
Maybe... I usually hate that stuff a-la-C++ iostream but, inverting the question, do you want to disallow it?
AFAIK Walter's stance is that overloading operators with semantics other than generalizations of arithmetic operators are a bad idea. This is why D uses opCmp for overloading <, <=, ==, >=, >, instead of one overload per operator like C++ has. Separately overloading < and <=, for example, means that the programmer can do truly weird things with it, which makes code hard to read (when you see "a < b" and "a <= b", you have no idea what they *really* mean). For DSLs, the official D recommendation is to use string mixins and CTFE instead. This gives you the flexibility to use *any* syntax you want for your DSL, including syntax that doesn't even fit in D syntax. You could even implement Unicode operators. CTFE lets you parse such strings at compile-time and emit code for them via string mixins, so runtime performance is not a concern. And I would tend to agree: I find iostream's (ab)use of << and >> to mean anything other than bitshifting very ugly and hard to read. Look at the Boost.Xpressive library for an even more extreme example of this. (Though thankfully, they appear to be moving towards string DSLs by taking advantage of the latest C++ features, so there is hope that this will soon be just an ugly footnote in history.) A long-standing item on my todo list is to implement compile-time writefln format strings using this technique. I don't even want to imagine how ugly code will become if I were to do compile-time format strings the C++ way by overloading arithmetic operators... imagine format strings written using operators... Ugh! T -- He who sacrifices functionality for ease of use, loses both and deserves neither. -- Slashdotter
Mar 10 2017
next sibling parent reply XavierAP <n3minis-git yahoo.es> writes:
On Friday, 10 March 2017 at 19:02:06 UTC, H. S. Teoh wrote:
 On Fri, Mar 10, 2017 at 07:47:43AM +0000, XavierAP via 
 Digitalmars-d wrote:
 On Thursday, 9 March 2017 at 15:42:22 UTC, qznc wrote:
[...]
 Maybe we want to support weird DSLs, where operators are 
 reused with very different semantics? For example, the 
 pyparsing parser generator allows you to write a grammar 
 like [0] this:
Maybe... I usually hate that stuff a-la-C++ iostream but, inverting the question, do you want to disallow it?
AFAIK Walter's stance is that overloading operators with semantics other than generalizations of arithmetic operators are a bad idea. This is why D uses opCmp for overloading <, <=, ==, >=, >, instead of one overload per operator like C++ has. Separately overloading < and <=, for example, means that the programmer can do truly weird things with it, which makes code hard to read (when you see "a < b" and "a <= b", you have no idea what they *really* mean).
* D does not use opCmp for == but I'm sure it slipped your tongue ;) I agree with that stance on style myself, and also with the hard restriction to keep the (in)equality and comparison operators consistent with each other. But the question is whether to restrict programmers further with no other reason than style. D's philosophy is maximum system freedom (just like C/C++) within sanity. Also operator overloading style may depend on each engineer's background. Walter's education is mechanical engineering and mathematics (coincidentally just like myself), so he dislikes usage of operators not analogous to algebra or set theory. Me too; beyond that I would rather create methods with self-documenting names. But there are software engineers and computer scientists who don't care about math, and they may even love iostream's "arrows" indicating the direction of the "stream". Leaving aside the specific example of iostream, this style discussion is not one where anyone can prove or claim to be right. Live and let live.
Mar 10 2017
parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Fri, Mar 10, 2017 at 09:07:36PM +0000, XavierAP via Digitalmars-d wrote:
 On Friday, 10 March 2017 at 19:02:06 UTC, H. S. Teoh wrote:
[...]
 AFAIK Walter's stance is that overloading operators with semantics
 other than generalizations of arithmetic operators are a bad idea.
 This is why D uses opCmp for overloading <, <=, ==, >=, >, instead
 of one overload per operator like C++ has.  Separately overloading <
 and <=, for example, means that the programmer can do truly weird
 things with it, which makes code hard to read (when you see "a < b"
 and "a <= b", you have no idea what they *really* mean).
* D does not use opCmp for == but I'm sure it slipped your tongue ;)
Haha, you got me there. :-P But in fact, the very fact that == is handled by opEquals and inequalities are handled by opCmp has led to some amount of debate some time ago, because it's possible for them to be inconsistent with each other. (Sorry, I'm too lazy to look up the thread right now, but you can search the forum archives for the (rather lengthy!) discussion.) This goes to show that overloading individual operators separately from other related operators can eventually become a source of problems.
 I agree with that stance on style myself, and also with the hard
 restriction to keep the (in)equality and comparison operators
 consistent with each other. But the question is whether to restrict
 programmers further with no other reason than style. D's philosophy is
 maximum  system freedom (just like C/C++) within sanity.
 
 Also operator overloading style may depend on each engineer's
 background.  Walter's education is mechanical engineering and
 mathematics (coincidentally just like myself), so he dislikes usage of
 operators not analogous to algebra or set theory. Me too; beyond that
 I would rather create methods with self-documenting names.
 
 But there are software engineers and computer scientists who don't
 care about math, and they may even love iostream's "arrows" indicating
 the direction of the "stream". Leaving aside the specific example of
 iostream, this style discussion is not one where anyone can prove or
 claim to be right. Live and let live.
It's not only about style or math, though. You may or may not have encountered lovely C++ snippets like this one: int x, y, bitmask; cout << x & bitmask << y; // what do you think this does? // vs. what it actually does? The problem is that "<<" was designed to be a bit-shift operator, and as such it has a specific precedence level in the hierarchy of operators. Overloading it to mean something completely unrelated like "output" may not give it a "sensible" precedence relative to its new meaning. You end up needing to add parentheses everywhere just to be sure (unless you can memorize the entire C/C++ operator precedence chart -- I can't). Operators also have their own associativity according to their intended semantics; this can make code that abuse operator overloading outside its intended usage quite unreadable, if the built-in associativity doesn't match its new meaning. Basically, operator syntax is just too specific to the arithmetical meanings of the operators that overloading them to mean something else seems like just asking for trouble. T -- The volume of a pizza of thickness a and radius z can be described by the following formula: pi zz a. -- Wouter Verhelst
Mar 10 2017
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10.03.2017 23:41, H. S. Teoh via Digitalmars-d wrote:
 Basically, operator syntax is just too specific to the arithmetical
 meanings of the operators that overloading them to mean something else
 seems like just asking for trouble.
OTOH, restricting how operators can be overloaded means they cannot be used for symbolic mathematics, which is annoying.
Mar 11 2017
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11.03.2017 13:46, Timon Gehr wrote:
 On 10.03.2017 23:41, H. S. Teoh via Digitalmars-d wrote:
 Basically, operator syntax is just too specific to the arithmetical
 meanings of the operators that overloading them to mean something else
 seems like just asking for trouble.
OTOH, restricting how operators can be overloaded means they cannot be used for symbolic mathematics, which is annoying.
Example: https://scala-lms.github.io/
Mar 11 2017
prev sibling parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Sat, Mar 11, 2017 at 01:46:31PM +0100, Timon Gehr via Digitalmars-d wrote:
 On 10.03.2017 23:41, H. S. Teoh via Digitalmars-d wrote:
 
 Basically, operator syntax is just too specific to the arithmetical
 meanings of the operators that overloading them to mean something
 else seems like just asking for trouble.
OTOH, restricting how operators can be overloaded means they cannot be used for symbolic mathematics, which is annoying.
I think you misunderstand my intent. By "arithmetical meanings" I meant any meanings to which mathematics may assign to said operators, so using "x + y" for vector addition, for example, is fair game. And perhaps even field addition for general fields. But using "x + y" for division is abusive, for example, and so is using "+" for appending to a file. But in any case, this isn't something that's enforceable. Deciding whether an implementation of an overload of "+" is "addition-like" is probably undecidable. It's just bad practice to use "+" for something that someone reading the code wouldn't expect. The bottom line is really readability and maintainability than anything else. T -- My program has no bugs! Only unintentional features...
Mar 11 2017
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11.03.2017 20:39, H. S. Teoh via Digitalmars-d wrote:
 On Sat, Mar 11, 2017 at 01:46:31PM +0100, Timon Gehr via Digitalmars-d wrote:
 On 10.03.2017 23:41, H. S. Teoh via Digitalmars-d wrote:
 Basically, operator syntax is just too specific to the arithmetical
 meanings of the operators that overloading them to mean something
 else seems like just asking for trouble.
OTOH, restricting how operators can be overloaded means they cannot be used for symbolic mathematics, which is annoying.
I think you misunderstand my intent.
I'm not disagreeing with your point, I'm just adding that the language should not necessarily attempt to enforce it.
 By "arithmetical meanings" I meant
 any meanings to which mathematics may assign to said operators, so using
 "x + y" for vector addition, for example, is fair game. And perhaps even
 field addition for general fields. But using "x + y" for division is
 abusive, for example, and so is using "+" for appending to a file.

 But in any case, this isn't something that's enforceable. Deciding
 whether an implementation of an overload of "+" is "addition-like" is
 probably undecidable.
It's the same with "<=", and the current approach has false negatives.
 It's just bad practice to use "+" for something
 that someone reading the code wouldn't expect. The bottom line is really
 readability and maintainability than anything else.


 T
This is not really specific to operators at all though. The general point is that functions should be named reasonably.
Mar 11 2017
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Friday, 10 March 2017 at 22:41:43 UTC, H. S. Teoh wrote:
 The problem is that "<<" was designed to be a bit-shift 
 operator, and as such it has a specific precedence level in the 
 hierarchy of operators.
Fair point. IIRC Algol68 allowed custom precedence levels. Found this: http://www.kestrel.edu/home/people/meertens/publications/papers/Operator-Priority_Grammar_for_ALGOL_68+.pdf At the other end of the spectrum Pony requires explicit parens for operators outside the most familiar ones ("+", "-", "*"...).
Mar 11 2017
parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Sat, Mar 11, 2017 at 08:55:12PM +0000, Ola Fosheim Grøstad via Digitalmars-d
wrote:
 On Friday, 10 March 2017 at 22:41:43 UTC, H. S. Teoh wrote:
 The problem is that "<<" was designed to be a bit-shift operator,
 and as such it has a specific precedence level in the hierarchy of
 operators.
Fair point. IIRC Algol68 allowed custom precedence levels. Found this: http://www.kestrel.edu/home/people/meertens/publications/papers/Operator-Priority_Grammar_for_ALGOL_68+.pdf
Custom precedence levels make the language a pain to parse, esp. by external 3rd party tools. Which generally also means (good) tooling will be harder to come by. Doesn't seem like a commensurate price with the little replaceable benefit that you get.
 At the other end of the spectrum Pony requires explicit parens for
 operators outside the most familiar ones ("+", "-", "*"...).
This may not be a bad idea, actually. How many among us can actually memorize the entire precedence hierarchy of C/C++ operators? I certainly can't. Meaning that most of the time you'd already be writing parentheses anyway, just to be sure, so it wouldn't be an onerous requirement to always write them. T -- My program has no bugs! Only undocumented features...
Mar 13 2017
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Friday, 10 March 2017 at 19:02:06 UTC, H. S. Teoh wrote:
 A long-standing item on my todo list is to implement 
 compile-time writefln format strings using this technique.
Yes, the actual checking seems straightforward - here I implemented CT format as an overload: import std.format : format; auto format(string fmt, A...)(A args) { static assert(__traits(compiles, {enum s = .format(fmt, A.init);}), "Arguments do not match format string: '" ~ fmt ~ "' with " ~ A.stringof); return .format(fmt, args); } unittest { auto s = format!"%s is %s"(5, "five"); static assert(!__traits(compiles, {s = format!"%d"("four");})); }
Mar 11 2017
parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Sat, Mar 11, 2017 at 03:03:30PM +0000, Nick Treleaven via Digitalmars-d
wrote:
 On Friday, 10 March 2017 at 19:02:06 UTC, H. S. Teoh wrote:
 A long-standing item on my todo list is to implement compile-time
 writefln format strings using this technique.
Yes, the actual checking seems straightforward - here I implemented CT format as an overload: import std.format : format; auto format(string fmt, A...)(A args) { static assert(__traits(compiles, {enum s = .format(fmt, A.init);}), "Arguments do not match format string: '" ~ fmt ~ "' with " ~ A.stringof); return .format(fmt, args); } unittest { auto s = format!"%s is %s"(5, "five"); static assert(!__traits(compiles, {s = format!"%d"("four");})); }
Yes, that's the general idea of it. But I want to go further: to eliminate unnecessary dependencies of format() based on the contents of the format string. More specifically, currently calling format() will instantiate a whole bunch of stuff for typesetting *all* possible format strings, like floating-point, array expansion, etc.. That means a simple format("%s",s) will pull in a whole bunch of code into your executable that may not actually be used. (And not even LTO can get rid of it, because the code is inside if- or switch-statements, and technically is "referenced" by the caller; the linker has no way to know it won't actually get called.) Not to mention, "%s" itself pulls in a whole bunch of code for dealing with things like field width, max width, padding, etc. (i.e., to handle things like "%10s", "%10.5s", and so on), all of which isn't actually needed to implement plain ole "%s". So the idea is to analyse the format string at compile-time to determine exactly what functionality is actually used, and instantiate only that. Think of it as a format-string mini-compiler: given a format string and a list of argument types, compile it into the equivalent minimal D code. E.g.: format("abc%sdef", s) should get compiled into: "abc" ~ s ~ "def" // N.B.: no floating-point code, no // width handling, etc. and so on. T -- What doesn't kill me makes me stranger.
Mar 11 2017
parent Nick Treleaven <nick geany.org> writes:
On Saturday, 11 March 2017 at 19:28:16 UTC, H. S. Teoh wrote:
 So the idea is to analyse the format string at compile-time to 
 determine exactly what functionality is actually used, and 
 instantiate only that. Think of it as a format-string 
 mini-compiler: given a format string and a list of argument 
 types, compile it into the equivalent minimal D code. E.g.:

 	format("abc%sdef", s)

 should get compiled into:

 	"abc" ~ s ~ "def"	// N.B.: no floating-point code, no
 				// width handling, etc.
Sounds good, and it would be more efficient at runtime. But as the type checking is easier, and the interface is the same, I think we could add type checking now and hopefully do the CT parsing later.
Mar 13 2017
prev sibling next sibling parent Arun Chandrasekaran <aruncxy gmail.com> writes:
On Tuesday, 7 March 2017 at 05:44:49 UTC, Walter Bright wrote:
 https://makebitcoingreatagain.wordpress.com/2017/02/18/is-the-zcoin-bug-in-checktransaction/#update6

 The error is here:

     
 https://github.com/zcoinofficial/zcoin/blob/81a667867b5d8489...

 and the line of code:

     zccoinSpend.denomination == libzerocoin::ZQ_LOVELACE;

 In other words, a statement with no effect. In D, such a line 
 gives an error, not a warning:

     Error: == has no effect in expression
Coincidentally, saw this in https://www.youtube.com/watch?v=A8Btr8TPJ8c&feature=youtu.be&t=469, while watching DConf 2015. No one spotted this bug (wasFound) in the conf?
Mar 09 2017
prev sibling parent Inquie <Inquie data1.com> writes:
On Tuesday, 7 March 2017 at 05:44:49 UTC, Walter Bright wrote:
 https://makebitcoingreatagain.wordpress.com/2017/02/18/is-the-zcoin-bug-in-checktransaction/#update6

 The error is here:

     
 https://github.com/zcoinofficial/zcoin/blob/81a667867b5d8489...

 and the line of code:

     zccoinSpend.denomination == libzerocoin::ZQ_LOVELACE;

 In other words, a statement with no effect. In D, such a line 
 gives an error, not a warning:

     Error: == has no effect in expression
Probably an inside job... probably designed that way from the start...
Mar 12 2017