TL;DR: Don't offer implicit casts at all (besides trivial, reliable ones that you define in your language specification, e.g. casts from
(Disclaimer: I am an old-school Java enthusiast, so my answer might be biased.)
I prefer a language to be clear, meaning that everything that happens (1) is visible in the source code. And when knowing a language, I can always tell where to look for the "contract" of that element: either in the language specification, or in an easily-found place in user or library code.
E.g. if I see an assignment opererator, I like its semantics to be well-defined in the language specification, without the need to search (or navigate) through source code and libraries to grasp its meaning.
If every non-trivial action is found explicitly in the source code, it not only makes the code clear, it also gives your IDE a logical place from where to navigate to the relevant definition.
If you have hidden, non-trivial casting (no matter whether single or multiple steps), you see a variable of type B being assigned an expression of type A, and nothing in the source code that represents the conversion. Only a sophisticated IDE can give you a hint that there is more than just an assignment going on.
Even for this IDE it's non-trivial to provide a navigation point where to offer the "goto definition" action. In an assignment statement, it might choose the
= operator, which might already be overloaded depending on your language features, so it needs a submenu, offering the overloaded assignment operator and the various cast implementations involved here.
Probably, you'll also allow implicit casting not only for assignments, but also within expressions, e.g. in method call arguments. Where do you expect the IDE to offer the navigation point then?
Ambiguity and Complexity
Others have already discussed that in-depth, so there's no need to repeat those aspects here.
But I'd like to mention one additional pitfall. If you write
B b = a;
This calls the A-to-B cast. If now, a developer introduces a superclass (or interface, supertype or whatever you might call it in your language) of
SB, and follows the good practice to declare a variable with the most generic type that still matches the requirements:
SB b = a;
Then another cast, being A-to-SB, appears as candidate, and probably a few others if
SB has more than one subclass. Now you need a disambiguation rule which one to choose, and it's very likely that it will no longer result in the A-to-B cast. So, by just following a good practice, this developer broke the program.
Evrything you can do with implicit casts, you can as well do with explicit ones. It only saves you a few characters. IMHO these few characters aren't worth the pain.
(1) What counts as "happens" is subject to interpretation.
Is treating an
int32 something that matters enough to become a visible action? You can argue that it's now a longer bit string, containing 32 instead of 8 bits, but you can also argue that a number like e.g.
96 stays the same, no matter whether you store it as an 8-bit or a 32-bit pattern. Many existing languages do implicit casts with this type of conversion, and force you to write explicit casts only if there is a risk of losing some information.
If the conversion involves user code, then probably everybody will agree that there is something "happening", and then I like that to be explicitly visible.