January 17, 2023
On Tue, Jan 17, 2023 at 12:16:25PM -0800, Walter Bright via Digitalmars-d wrote: [...]
> It's not a question of "can we come up with a set of rules to make it all work". We certainly can. Whether the rules are predictable and intuitive rather than arbitrary and capricious is another matter entirely.
>
> Case in point - C++ overloading rules. [...]
[...]
> So how do people deal with it? This is what they tell me - they try random things until it works. They don't know why it works, and don't really care, they just move on.

In some areas, D already feels like this.

Errors in function literals are an especially egregious instance of this problem. When you have a long UFCS chain inside a template function, an error inside one of the lambdas can cause the entire template to fail to instantiate; but no thanks to error gagging/SFINAE, the compiler just moves on to the next overload to try. That overload may (partially) succeed, but since it wasn't the intended recipient it will also inevitably fail. By the time the compiler has exhausted the list of overloads, it has already gone far beyond the actual location of the error, and any error messages that it may try to give will be mostly irrelevant except perhaps for that one needle buried in pages and pages of haystack.

When the error is a syntax error, there's still a way (albeit tedious and frustrating) to track it down; when the problem is a wrong parameter type, attribute, or overload that got unexpectedly matched instead of the intended one, it quickly devolves into a game of "let me try to stick random attributes on the lambda until it works, and call it a day".

D's integer promotion rules are especially bad for this: an overload that takes char will happily accept an integer literal argument; and an overload that takes int will happily accept (in some cases, even prefer) a bool rather than the bool overload.  In isolation, this isn't a big deal; you just learn the integer promotion rules and design your API around the issue to avoid it.  But when this happens deep inside generic code within several nested layers of templates in 3rd party library code, the actual cause of the problem is just about impossible to locate.


[...]
> (The "least as specialized" rule is what C++ uses for template overloading, the C++ developers found a better way than the rats' nest of function overloading rules. I thought that would work better for function overloading, and indeed it does.)

That's arguable when it comes to integer promotion rules. When calling a f(true) prefers a char overload over an int overload, when a char literal implicit converts to an int whereas arithmetic involving ubytes require an explicit cast to be assigned back to a ubyte, that's not intuitive at all; that's counterintuitive and capricious.  It only (barely) makes sense when you're the one who wrote the rules and therefore take them for granted; to anyone else, it's completely backwards and nonsensical.


[...]
> Deciding what to leave out of a language is just as important as deciding what to put in. In fact, maybe it's *more* important.

At least on this we agree. :-D


T

-- 
Your inconsistency is the only consistent thing about you! -- KD
January 17, 2023
On Tuesday, 17 January 2023 at 20:16:25 UTC, Walter Bright wrote:
> On 1/17/2023 10:16 AM, 12345swordy wrote:
>> We don't need alias this for classes, we just need custom implicit conversion for structs and classes. Other OOP languages have them, yet it from the cpp world that I keep hearing complaints regarding implicit conversions.
>
> Implicit conversion is fine by itself. But consider the combinations of:
>
> 1. inheritance
> 2. alias this
> 3. overloading
> 4. implicit conversion
> 5. multiple inheritance
> 6. multiple alias this
> 7. integer promotion
>
> (which all can be considered forms of implicit conversion) and it becomes incomprehensible.
>
> It's not a question of "can we come up with a set of rules to make it all work". We certainly can. Whether the rules are predictable and intuitive rather than arbitrary and capricious is another matter entirely.
>
> Case in point - C++ overloading rules. Last time I checked, they are two rather dense pages in the C++ Standard. I don't know anyone who can keep those rules in their head. I know I can't, and I implemented them correctly.
>
> So how do people deal with it? This is what they tell me - they try random things until it works. They don't know why it works, and don't really care, they just move on.
>

This is true. Nevertheless, the C++ rule (at least on that specific matter) are sensible and I very rarely am surprised by them, even though I couldn't tell you what they are on top of my mind.

> Deciding what to leave out of a language is just as important as deciding what to put in. In fact, maybe it's *more* important.

Fair enough, but this need to be motivated by the concrete. Let me take a detour with chess.

Beginner player know the rules of chess, but not much more. As the improve, they learn general rules, such as developing your pieces during the opening, controlling the center, etc... You note that there are no rule in chess that say you win if you develop your pieces or control the center, in fact, these things don't show up in the rules at all and are nowhere close to being the goal of the game, which is to get at the enemy kind.

But what make the difference between the intermediate player, who know these principles, and a master of the game? Well the master of the game knows these rules, obviously, but he doesn't follow them, he uses them as a proxy to know what to calculate.

When you ask an intermediate player why they play 2. Nf3, they tell you it is because it is the opening and they want to develop their pieces. When you do the same on the same move with a master player, they tell you that it'll control the knight controls the dark square in the center, put pressure on the e5 pawn, forcing the opponent to defend, and can jump on g5 and form an attack on the kind if it castle king side or if the f7 pawn is weak.

In the same way, yes, complex resolution rules in a programing language are generally to be avoided. This is the general principle. But this is not the goal of the programming language to avoid such rules, it is because it is fairly common that these rules cause problems and/or confusing behavior.

It is self evident that this heuristic is not always true: we have overloads, we have inheritance, and people see value from this. On the other hand, we do not allow implicit conversion of integer to smaller types if VRP cannot prove it is safe. We can point to concrete example of program with are broken in subtle ways, or even big security problems caused by this feature of C/C++.

In the case of alias this, we should be able to point at the concrete problems it causes, and if we cannot, then either we need to step up our game because we aren't at the master level, or maybe these problem are just small and can proceed.
1 2
Next ›   Last »