What is the reasoning behind the lack of conversions when passing parameters

Jonathan M Davis newsgroup.d at jmdavisprog.com
Fri Feb 2 22:02:30 UTC 2024


On Friday, February 2, 2024 2:16:33 PM MST Carl Sturtivant via Digitalmars-d 
wrote:
> ```
> import std.variant, std.math, std.stdio;
>
> void f(Variant z) {
>   writeln(z);
> }
>
> void main() {
>   auto x = sqrt(2.0);
>   Variant v = x;
>   f(v);
>   //f(x);
> }
> ```
>
> The commented out call `f(x)` is illegal in D.
> `f(VariantN!32LU v) is not callable using argument types (double)`
>
> Yet in principle it is an attempt to create and initialize a
> variable `z` local to `f` of type Variant.
>
> Exactly like the legal `Variant v = x` declaration.
>
> Why exactly is vanilla parameter passing not given the same
> semantics as initialization?

I want to say that TDPL discusses this somewhere, but I can't find where at
the moment. So, I can't provide the (probably better) answer that it would
have.

However, I'm pretty sure what it comes down to is that it simplifies
function overloading (which can get fairly complex in C++ thanks to it
allowing such conversions). It also reduces the number of bugs that you get
from implicit conversions (though we do have alias this). By having alias
this without the implicit construction with function arguments, we make it
so that the conversion is only in one direction, whereas if we also allowed
conversion based on constructors, then it would complicate the choices
considerably in some cases.

In contrast, when you're explicitly initializing a variable, there's no
question as to what the type is. The same would be true with a function that
wasn't overloaded, but allowing conversions based on constructors when there
are no overloads but disallowing them when there are would be confusing and
would result in code breakage when adding function overloads.

It's similar to how D usually doesn't determine the type of an expression
based on where it's used (it does in a few cases with literals, but it
mostly doesn't). We _could_ allow it, which would enable some things which
might be nice, but it's just simpler to disallow it and require that the
programmer be explicit. We still have plenty of type inferrence going on.
It's just that it only goes in one direction, which is much easier for the
compiler to handle as well as generally being easier for the programmer to
understand and reason about.

And if you want to pass something to a function where construction is
required, it's as simple as calling the constructor, which isn't
particularly onerous, and it makes the code easier to understand.

- Jonathan M Davis





More information about the Digitalmars-d mailing list