DIP 1015--Deprecation of Implicit Conversion of Int. & Char. Literals to bool--Formal Assement
Steven Schveighoffer
schveiguy at gmail.com
Thu Nov 15 16:42:25 UTC 2018
On 11/14/18 4:32 PM, Neia Neutuladh wrote:
> On Wed, 14 Nov 2018 13:40:46 -0500, Steven Schveighoffer wrote:
>> You don't think this is confusing?
>>
>> enum A : int {
>> val
>> }
>>
>> A a;
>> foo(a); // error: be more specific
>> int x = a;
>> foo(x); // Sure
>
> I find this confusing:
>
> void foo(int i) {}
> void foo(ubyte b) {}
> enum A : int { val = 0 }
> foo(A.val); // calls foo(ubyte)
> A a = A.val;
> foo(a); // calls foo(int)
>
> If it instead produced an error, the error would look like:
>
> Error: foo called with argument types (E) matches both:
> example.d(1): foo(int i)
> and:
> example.d(2): foo(ubyte i)
I'm reminded of my son, who I sometimes give him a glass of water when
he asks for it, and after I hand it to him, he says "should I drink this?"
To me, making the user jump through these hoops will be insanely
frustrating.
>
> Or else:
>
> Error: none of the overloads of foo are callable using
> argument types (A), candidates are:
> example.d(1): foo(int i)
> example.d(2): foo(ubyte i)
>
> These aren't the intuitively obvious thing to me, but they're not going to
> surprise me by calling the wrong function, and there are obvious ways to
> make the code work as I want. Of the two, I'd prefer the former.
I prefer the correct version which calls foo(int). I think truly this is
a misapplication of the overload rules, and can be fixed.
> The intuitively obvious thing for me is:
>
> * Don't use VRP to select an overload. Only use it if there's only one
> candidate with the right number of arguments.
> * Don't use VRP if the argument is a ctor, cast expression, or symbol
> expression referring to a non-builtin. Maybe disallow with builtins.
> * Don't use VRP if the argument is a literal with explicitly indicated type
> (0UL shouldn't match to byte, for instance).
To me, an enum based on int is an int before it's a typeless integer
value. VRP should be trumped by type (which it normally is). I would say
an enum *derives* from int, and is a more specialized form of int. It is
not derived from byte or ubyte. For it to match those overloads *over*
int is surprising.
Just like you wouldn't expect the `alias this` inside a class to match
an overload over its base class.
Oh, crap, it actually does... But I think that's a different bug.
>
> I think this would make things more as most people expect:
>
> foo(A.val); // A -> int, but no A -> byte; calls foo(int)
> foo(0); // errors (currently calls foo(int))
If you have foo(int) and for some reason you can't call it with foo(0),
nobody is going to expect or want that.
> foo(0L); // errors (currently calls foo(ubyte))
> foo(cast(ulong)0); // errors (currently calls foo(ubyte))
I'm actually OK with this being the way it is, or even if it called the
foo(int) version. Either way, as long as there is a clear definition of
why it does that.
>
> And when there's only one overload:
>
> void bar(byte b) {}
> bar(A.val); // errors; can't convert A -> byte
> bar(0); // type any-number and fits within byte, so should work
> bar(0UL); // errors; explicit incorrect type
> bar(0UL & 0x1F); // bitwise and expression can do VRP
> bar("foo".length); // length is a builtin; maybe do VRP?
> bar(byte.sizeof); // sizeof is a builtin; maybe do VRP?
>
I am OK with VRP calls, even in the case of the enum when there's no int
overload.
-Steve
More information about the Digitalmars-d-announce
mailing list