Deprecating fromIntegral

Niklas Hambüchen mail at nh2.me
Thu Sep 21 15:34:07 UTC 2017


Hey Henning,

On 21/09/17 15:21, Henning Thielemann wrote:
> That's all very true! Other safety oriented languages like Modula-3 at
> least perform a runtime check on integer conversion.
> 
> However, I'd like to see practical solutions first before adding
> deprecations.

I agree, deprecating before finding a solution doesn't make sense.

I intend this thread to be mainly about discussing possible solutions
and problems with them, hopefully we'll find something good.

> fromInteger will always be partial when converting to a fixed width
> integer. fromInteger is used for converting number literals to the
> wanted type. Thus every number literal will issue a warning and I cannot
> see how to circumvent this.

Yes. I would say though that `fromInteger` being partial is a less
severe problem than `fromIntegral`'s silent overflow; if a `fromInteger`
fails partially, you'd at least get a nice run-time error, which would
be better.

(Though, in practice the current `fromInteger is not partial, e.g.
`(fromInteger 256 :: Word8) == 0` without error, and I suspect it would
be good if we added a partial function in addition to the silently
wrapping one here too.)

> Another problem I see is that integralUpsize and integralDownsize are
> not Haskell 98 and multi-parameter type classes are not really
> satisfying here because you have to define n^2 instances for n types. A
> convenient conversion function would certainly need even more advanced
> types, e.g. type-level comparison of bit widths.

That's a good point, and that's why I think that...

> For now the least invasive solution would be to provide a partial
> integer conversion function.

... this might be a good first step.

It would turn

 "You ship code into production and 50 days later it corrupts your data"

into

 "You ship code into production and 50 days later it crashes"

which is already much better, and, I believe, easy to implement.

> If we have fixed fromIntegral then the next natural question would
> arise: How to protect arithmetic operations plus, minus, times against
> overflow? Aren't overflows as dangerous as losing bits on integer
> conversion? Is there a solution that works both for conversion and
> arithmetics?

Yes, all types of overflows can be problematic and dangerous.

You could say though that overflows "within the type" are somewhat less
problematic: Arithmetic overflows are more well-known and in people's
minds, it is relatively easy for a programmer to pick a type that is
large enough so that "+" doesn't overflow, and that only stops working
once you need to convert to another type, when the `fromIntegral`
problem occurs.
In "their own types", people work confidently, it's when interfacing
with others' code where the big bugs occur (like in the example I gave).

Haskell provides easy methods to prevent overflow *within* one's own
numeric types if one desires (like implementing "+" with `error` if it
doesn't fit); but currently our conversion functions *between* types
don't give us good explicit means to do so.

Also, how to deal with in-type overflows is an unsolved problem in
general, while C already solves much of the conversion problem.

I think solving the parts that C has solved would already avoid a good
amount of bugs.

> As always, I object to use the terms 'safe' and 'unsafe' when actually
> 'total' and 'partial' are meant. LLVM uses 'ext' and 'trunc'. I'd prefer
> names along these lines.

Good point.

I used "safe" and "unsafe" to express the idea that one kind would
always succeed in the naturally expected fashion and one would not, but
the more precisely the naming is, the better.


More information about the Libraries mailing list