|
|
|
|
|
by kibwen
2097 days ago
|
|
The internal behavior can trivially be made different just by operating on the value: fn foo<T>() -> usize {
let x = std::mem::size_of::<T>();
if x % 2 == 0 {
panic!();
}
}
foo::<u8>(); // 1
foo::<u16>(); // panic
That the body is the same isn't necessarily the issue at hand (though of course it's still a useful property in its own right), what matters is that reasoning about what this function will do requires knowing which specific types it is used with.> this seems pedantic The first code example is merely the simplest demonstration, in the wild I would expect lots of `size_of` in generic contexts to result in type-dependent behavior somehow. I'm not saying this is necessarily a very bad thing, nor do I have strong opinions on the usefulness of strict parametricity (which AFAIK Haskell doesn't have either). But in discussions relevant to parametricity, it's useful to know the ways a given language can subvert it (and Rust will further encourage it to be subverted, once the specialization feature is developed). |
|
In practice Haskell seems to have pretty strong views on enforcing parametric polymorphism, doesn't it?
Haskell gives you ad-hoc polymorphism via typeclasses and there are also existential types and GADTs etc, if you need those. But once you declare something to abide by parametric polymorphism, you are expected to keep your end of the bargain.
(Yes, you could violate the pact via some unsafePerformIO trickery, but that's considered bad form.)