[swift-evolution] Proposal: Auto-convert for numbers when safe

Brent Royal-Gordon brent at architechies.com
Sat Dec 5 07:10:03 CST 2015

> I understand why you can’t auto-convert from a Double to a Float or Int32 to Int8.  It is good that we have to add the cast explicitly and think though the implications.
> …but I don’t think through the implications because we currently have a boy who cried wolf situation where we have to explicitly cast everything (even the safe stuff).
> I think all of the numeric types should be able to auto-convert if the conversion is safe (without loss of precision or overflow).
> For example:
> • If an Int is casting to a larger size (Int16 -> Int32)
> • Float -> Double
> • Float -> CGFloat
> • Int -> Float, Double, or CGFloat (but not the other way)
> I don’t see why these aren’t allowed. The forced casts make my code much less readable.  Are the casts above dangerous in a way I am not aware of?

Well, certain large Ints may not have a corresponding Float, and very large ones (on 64-bit platforms) might not have an exact Double. In fact, even Float -> Double conversions can go subtly wrong, as I recall. 

One reason not to do this is that I suspect it may slow down type inference, and thus the compiler. If every numeric type can be implicitly converted to a long list of larger types, that’s a lot more types for the compiler to think about every time you add two numbers.

Another is simply that it’s not clear how you would express to the type system which conversions could be done implicitly and which were verboten. Remember, Int and friends are all ordinary Swift structs; we don’t want to give them magical powers that aren’t available to other types. (I seem to recall that in the early Swift betas, there was a magic _convert() method or something that you could overload, but this was dropped as the language was redesigned. Perhaps the people who actually did the dropping could explain that one.)

A third is that conversions can, in some cases, cost time. Usually not much, but in a tight arithmetic loop it might matter.

A fourth: your code should probably not be using so many numeric types. There’s rarely a good reason to use an explicitly-sized integer, an unsigned integer, or a Float. That means most of your code should be using only Int, Double, and CGFloat (which is unavoidable). If you’re converting because an awkwardly-bridged API uses an explicitly sized type, overload the API with a wrapper that’s correctly typed. If you’re converting because you’re doing bit-twiddling, you probably need fine control over when values are resized.

Finally, if all that fails and you do need to convert, I prefer the strategy of marking your conversion sites explicitly. This (old, possibly out-of-date) code sample shows what I mean: <https://gist.github.com/brentdax/f85ede7dd7b26c6e716e> Marking conversions explicitly with a low-visual-impact operator which only allows widening conversions gets you the same safety as your proposal and nearly the same convenience, but also makes your meaning explicit, is kinder to the type checker, and doesn’t require any new features to be added to the type system.

Brent Royal-Gordon

More information about the swift-evolution mailing list