| |
 | Posted by Jonathan M Davis in reply to ShadoLight | Permalink Reply |
|
Jonathan M Davis 
Posted in reply to ShadoLight
| On Sunday, February 16, 2025 4:54:46 AM MST ShadoLight via Digitalmars-d-learn wrote:
> On Sunday, 16 February 2025 at 05:39:07 UTC, Jonathan M Davis wrote:
> > _especially_ when VRP comes into play, because then you get nonsense like foo(1) calling the bool overload.
> >
>
> I have often seen this mentioned, but I only see this happen if there *isn't* an integer overload i.e. this...
When I'm saying integer here, I mean integer types in general, not necessarily int specifically. If you have an int overload specifically, then foo(1) will call the int overload, because that's an exact match given that integer literals are typed as int by default. However, it _is_ possible for foo(1) to match a bool overload if there isn't an int overload, because then implicit conversions come into play.
> ```d
> //void foo(int x) { writeln("I"); } //Comment to remove 'int'
> overload
> void foo(long x) { writeln("L"); }
> void foo(ulong x) { writeln("UL"); }
> void foo(bool x) { writeln("B"); }
>
> void main()
> {
> foo(17UL);
> foo(1);
> foo(true);
> }
> ```
> ...will output:
> UL
> B
> B
>
> But if you uncomment the 'int' overload, you get...
> UL
> I
> B
> ...which is what I would expect. Or am I misunderstanding your
> point? With the 'int' overload commented, are you arguing it
> should match the best overloaded type that can VRP from 'int',
> such as 'long' above?
The problem is two-fold:
1. It's actually possible for foo(1) to call a bool overload. This behavior is almost always surprising to folks and almost never what they actually want, because 1 is an integer value, not a boolean value, and almost everyone expects that passing an integer value to a function is going to call one of the integer overloads, not a bool overload. If this were C, it would make sense insofar as C doesn't have an actual bool type, but D does. A number of us tried to talk Walter out of this conversion behavior but unfortunately failed, basically because he's just too used to thinking like a C programmer. IMHO, integer literals should _never_ implicitly convert to bool, and in most languages, they don't.
And for those who like to use integer values in conditional statements, those are different insomuch as they aren't actually implicit conversions. Rather, the compiler implicitly inserts an explicit cast to bool, which is why you can do stuff like if(ptr) instead of if(ptr !is null) even though pointers do not implicitly convert to bool. It's also why if you overload opCast!bool for a type, it will get used in the conditions for if statements, loops, and assertions.
2. Once VRP gets involved in general, the exact behavior you get can be surprising. Someone who really understands the rules and thinks it through can accurately determine which overload will be called, but to many programmers, the results tend to be surprising - especially if you don't sit down and carefully think through which overloads exist and how they interact with literals. It's also made worse by the fact that plenty of folks don't even know that VRP exists.
VRP can at times be nice, because it reduces the need for explicit casts, but it tends to add to the confusion that can come with function overloads. And the fact that integer literals can be implicitly converted to bool just makes it worse.
And honestly, I would think that it would be better to simply give an error if you pass any kind of integer literal to a function with multiple integer overloads rather than assuming the exact type of the literal, because it's _very_ easy to end up in a situation where you assume the type of the literal incorrectly (especially for less experienced D programmers). That's not how the language works, and I wouldn't expect it to change any more than integer literals will stop implicitly converting to bool, but I think that the current behavior in both cases is a mistake and error-prone. And there's just too much magic in general in D with regards to literals which tends to make certain stuff simpler at the cost of increasing complexity and confusion.
- Jonathan M Davis
|