Thread overview | |||||
---|---|---|---|---|---|
|
November 09, 2020 Value based overload resolution? | ||||
---|---|---|---|---|
| ||||
Today I came across this: ~~~id.d import std.stdio : writeln; T foo (T) (T s) { __PRETTY_FUNCTION__.writeln; return s; } short foo (short s) { __PRETTY_FUNCTION__.writeln; return s; } T id (T) (T t) { return t; } int main () { foo (1); foo (1L); foo (id (1)); foo (id (1L)); foo (0x1_0000); foo (0x1_0000L); return 0; } ~~~ Output: $ ./id short id.foo(short s) short id.foo(short s) int id.foo!int.foo(int s) long id.foo!long.foo(long s) int id.foo!int.foo(int s) long id.foo!long.foo(long s) It appears to me that the overload resolution may depend on the /value/ of the function argument. According to [1] the type of 1 is int and that of 1L is long. Thus I would have expected foo!int and foo!long being called in those cases. [1] https://dlang.org/spec/lex.html#integerliteral |
November 09, 2020 Re: Value based overload resolution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to kdevel | On Monday, 9 November 2020 at 22:04:55 UTC, kdevel wrote:
> It appears to me that the overload resolution may depend on the /value/ of the function argument. According to [1] the type of 1 is int and that of 1L is long.
That's not exactly true because of value range propagation. It is weird in this case.
But the intention is for stuff like
short a = 1;
to work without an explicit cast from 1 being an int. So the compiler looks at what it can see in the expression - exact values of literals, ranges of possible values from other variables - and determines the smallest type it can fit inside. Then it automatically assigns it that type instead.
What gets pretty weird is if you add a bool overload and pass 1.... the compiler considers bool to be a very restrained integral type... and it knows the values of `enum` too which can give some surprising results.
But yeah the values or the possible ranges of values can actually affect the types of arithmetic expressions and this is considered in overloading for better or for worse.
|
November 09, 2020 Re: Value based overload resolution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to kdevel | On Monday, 9 November 2020 at 22:04:55 UTC, kdevel wrote:
> It appears to me that the overload resolution may depend on the /value/ of the function argument. According to [1] the type of 1 is int and that of 1L is long. Thus I would have expected foo!int and foo!long being called in those cases.
>
> [1] https://dlang.org/spec/lex.html#integerliteral
As you've discovered, the types of integer literals (and literals in general) is somewhat fluid: the *default* type of `1` is `int`, but the compiler may infer a different type based on the value, or on the context in which the literal is used.
For example:
static assert(is(typeof([1, 2, 3]) == int[]));
int[] a = [1, 2, 3];
ubyte[] b = [1, 2, 3];
Perhaps even more confusingly, this also applies to manifest (enum) constants:
enum literal = [1, 2, 3];
static assert(is(typeof(literal) == int[]));
int[] a = literal;
ubyte[] b = literal;
|
Copyright © 1999-2021 by the D Language Foundation