March 10, 2017
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
March 11, 2017
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.
March 11, 2017
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/

March 11, 2017
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");}));
}

March 11, 2017
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.
March 11, 2017
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...
March 11, 2017
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 ("+", "-", "*"...).

March 11, 2017
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.
March 12, 2017
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?
March 12, 2017
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...