3 ms·
> co/contravariant representations represent exactly the point at which formal typesafety starts hurting instead of helping as an engineering practice. I can't
by tome 8y ago
> co/contravariant representations represent exactly the point at which formal typesafety starts hurting instead of helping as an engineering practice.
I can't understand what you mean by this. The Python 'list' type is covariant in its contents and comparison functions such as 'operator.lt' are contravariant in their arguments regardless of whether Python has types or not.
Co- and contravariance just are. They're not things that dynamic languages somehow don't have. They do have them! It's just harder to see them (and harder to take advantage of them for your own benefit).
- a1369209993 8y ago> The Python 'list' type is covariant in its contents l1 = [0,1,1,0] # list(unsigned) l2 = l2 # list(int) includes all list(unsigned) l2[1] = -42 # error: l1 is no longer all unsigned Mutatable references are pretty much never covariant. Immutable containers like `tuple` might be, but/because there's no support for appending to or otherwise modifying them.
- tome 8y agoA mutable array in Haskell is most certainly covariant so you may have to rethink your counterexample.
- a1369209993 8y agoHaskell's Data.Array.IO IOArrays (which I assume you're talking about) are not covariant; they are invariant, with a very nice type inference system to paper over this in most cases. {-# OPTIONS_GHC -W -XRankNTypes -XImpredicativeTypes -XFlexibleContexts #-} import Data.Array.IO type Subtype = (forall a . a->Int) type Suptype = (Int -> Int) esub = (\_ -> 0) :: Subtype esup = (\x -> x+1) :: Suptype wantsub = (\f -> f 'a') :: Subtype -> Int wantsup = (\f -> f 0) :: Suptype -> Int writeArraySup :: IOArray Int Suptype -> IO () writeArraySup a = writeArray a 1 esup main = do asub <- newArray (1,1) esub writeArraySup asub a1sub <- readArray asub 1 print $ wantsub a1sub In the above code, asub can be either (ie, not both) `IOArray Int Suptype` (in which case wantsub will fail to typecheck) or `IOArray Int Subtype`, in which case writeArraySup will fail to typecheck, because A'Sub isn't actually a subtype of A'Sup, because IOArray Int isn't actually covariant. You can see, I hope, that if they were covariant, and writeArraySup did typecheck, then we would end up passing 'a' (a Char) into (+) (expects Int) in violation of type safety. If you meant some other mutable array type, then the same reasoning applies, but I can't be arsed to work out another concise example.
- tome 8y agoThat's not the sort of variance that was discussed in the article, where an explicit mapping function is applied, not an implicit subtying relationship.
- ufo 8y agoSome languages intentionally have an unsound type system in respect to variance, and rely on runtime checks for safety. It is a facet of the old static typing vs dynamic typing tradeoff.