Explicit implicit conversions

Quirin Schroll qs.il.paperinik at gmail.com
Thu Feb 6 02:32:54 UTC 2025


Inspired by [this 
post](https://forum.dlang.org/post/khqsgbrnorbclxhvtpxy@forum.dlang.org).

The idea is simple: Extend implicit conversions to all types and 
values. For built-in types, one can do this: `ushort(myUByte)` 
That works because a `ubyte` can be converted to `ushort`. In 
some cases, the static type has to be changed by explicitly 
requesting a conversion that is intended to be fool-proof. (A 
`cast` would allow for narrowing or other unsafe conversions.)

D has many implicit conversions that are “obviously” correct:
- Numeric types when the range of the operand is fully included 
in the target type, e.g.:
   - `ubyte` → `ushort` → `uint` → `ulong`
   - `byte` → `short` → `int` → `long`
   - `ubyte` → `short`
   - `ushort` → `int`
   - `uint` → `long`
   - `float` → `double` → `real`
- Adding `const`
- Removing function attributes that make guarantees, e.g. `@safe` 
or `pure`.
- Derived to base class or interface

The idea is to allow, e.g. `Type(expression)` evaluate to 
`expression` with a static type of `Type`.

Something like this is needed to aid the compiler in figuring out 
what you want:
```d
interface I { }
interface J { }

class C : I, J { }
class D : I, J { }

void main()
{
     I[] xs = [new C, new D]; // Error: cannot implicitly convert 
expression `[new C, new D]` of type `Object[]` to `I[]`
}
```

One solution: Use `cast(I)`, but `cast` is not the right tool: It 
results in `null` for a failed cast, but we want to express the 
cast shouldn’t fail, and we want an error should we be mistaken.
```d
auto xs = [I(new C), new D]; // proposed: good, typeof(xs) is 
`I[]`
```

Another examples is when you want to control what type is 
inferred by IFTI:
```d
void f(T)(T x, T y) { pragma(msg, T); }

f(new C, new D); // Error: template `f` is not callable using 
argument types `!()(C, D)`
f(I(new C), I(new D)); // proposed: good, prints "I"
```

It could be implemented by lowering to `((Type __result) => 
__result)(expression)`.

Of course, that lowering can be provided by a function template:
```d
auto ref R implicitCast(R, T)(auto ref T x) => x;
```
The main issue with that is that it’s much wordier.


More information about the dip.ideas mailing list