On Saturday, 3 February 2024 at 02:14:00 UTC, H. S. Teoh wrote:
>I agree. In my early D code I also used a ton of alias this
- it's very convenient, and lets me drop in replacements for existing types without a lot of tedious refactoring work. After a lot of experience working with it, though, I've come to think that in the long term it's not a good idea. While alias this
lets you pretend that type T is type U, in the end it's still type T, and there comes a point where the distinction becomes important.
In one of my larger D codebases where I liberally used alias this
for a handful of very frequently-used types, it got to a point where I had 3 different types for representing exactly the same thing. It really should have been 1 type, but I had a wrapper type for the underlying static array using alias this
, then an extension over this wrapper some additional functionality. But (no) thanks to alias this, these types could interconvert, so for the most part things Just Worked(tm). Except sometimes they can't, then it's a head-scratching exercise of asking "now which of the 3 types is being used here, and which one should it have been?!". This question is a lot harder than it looks when stuff is being passed between templated generic code, where it's not obvious which concrete type is actually at work. And of course, there's the risk of instantiating the same template with 3 different types that ultimately represent exactly the same thing. Needless template bloat.
I really should have just refactored the code to use a single, consistent type throughout.
The above is overtly about implicit conversions as a consequence of using alias this
. I largely agree about that particular construct. It can lead to conversions occurring almost anywhere a value of a type containing the alias this
occurs, i.e. pervasive implicit conversion.
Another place where implicit conversions occur is in initialization in a variable declaration, where a single parameter constructor of the variable's type may be implicitly called. I think this is a good thing, and I haven't seen any complaints about this in D despite looking for them. Here implicit conversion is confined to only one kind of context. It is not pervasive.
>And in general, my experience has been that implicit conversions tend to do more harm than good. They're really tempting in the short term because of the convenience. But in the long term they're really more trouble than they're worth. Living without implicit conversions is inconvenient, but in the long term it helps keep code easier to understand and more maintainable.
Perhaps that's because various implicit conversions have often been defined dangerously in the languages you have used.
I think having some flexibility to define a single parameter constructor of your type to be implicitly called in a narrow context only by flagging it in your type's definition with say @implicit
is valuable.
It would only occur when passing a value to a parameter in the same way as it would be already be implicitly called when initializing a variable of your type to such a value. So the context for conversion would be limited, and have the same semantics as initialization does now in D.
It would simply turn parameter passing into limited initialization for your type. The same limited initialization that D already has in variable declarations with initialization.
Furthermore, if the view is that implicit conversion should be limited by default, the semantics of variable initialization could now be limited, and only constructors annotated with @implicit
could be implicitly called in initializations too.