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