implicit cast and overload priority

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sun Feb 16 17:04:39 UTC 2025


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





More information about the Digitalmars-d-learn mailing list