
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.