Programming languages without garbage collection send us down a long path of design decisions that lead to slow compile times and fragile runtime performance cliffs.
-
Show this thread
-
First is the abandoning of covariance and contravariance, the property which guarantees sensible subtyping: that bytes are also integers, and integers are also objects, extending systematically to container types and functions.
3 replies 3 retweets 44 likesShow this thread -
Without garbage collection, offering an array of bytes where an array of integers is required requires stack-allocating an array of integers and converting each byte to an integer every time a subtype is used in place of an actual type. This is so absurd that it’s not done.
6 replies 4 retweets 38 likesShow this thread -
So now when we want to recover performance, we need to write all containers and their operations using an increasingly elaborate set of templates or generic functions, which the compiler must specialize for each type at significant cost. This is what C++ and Rust do.
4 replies 5 retweets 40 likesShow this thread -
Or we can create a very clunky wrapper like array_of_anything that is used wherever generic types are required, which manually casts and converts values among types dynamically each time it’s accessed. Java generics did this and they were awful.
3 replies 4 retweets 28 likesShow this thread -
But if we have garbage collection, we can store our large data structures once with whatever type is required, then dynamically create wrappers that reinterpret it as any subtype that’s required. We pay the cost of GC and indirect control flow for accessors but that’s all.
7 replies 4 retweets 40 likesShow this thread -
Unfortunately, most languages missed this opportunity. The C family including C# and Java are overly imperative and lost variance due to wrongly-scoped mutability. And functional languages have generally chosen type systems lacking subtypes, covariance, and contravariance.
7 replies 5 retweets 57 likesShow this thread -
Replying to @TimSweeneyEpic
C# behaves differently for ref and val types here. Top one doesn't work. Bottom one does. int[] a = new byte[] { 1, 2, 3 }; object[] b = new string[] { "a", "b", "c" };https://stackoverflow.com/questions/12454794/why-covariance-and-contravariance-do-not-support-value-type …
1 reply 0 retweets 1 like -
Replying to @wakebrdkid @TimSweeneyEpic
A reference to a string array IS a reference to an object array (and so is a reference to a byte array, I suppose), but a reference to a byte array IS NOT a reference to an int array. Makes perfectly sense to me.
2 replies 0 retweets 1 like -
Replying to @evecitizen36339 @TimSweeneyEpic
It makes more sense in terms of the bit representations in memory, but less in terms of the program semantics of valid byte values being a subset of valid ints. But also the following program compiles fine and then crashes due to these convenience features.pic.twitter.com/IDrsJenvwr
3 replies 0 retweets 1 like
Java does it wrong. To be safe, either arrays need to be immutable to respect covariance (so that an array of byes is observably equivalent to an array of ints) or array subtyping needs to be invariant.
-
-
Replying to @TimSweeneyEpic @evecitizen36339
The covariant IEnumerable<T> interface provides that immutable observer for all collections in C# (still only with ref types though). When declaring an interface you can use “out” and “in” on the type params to mark co and contra variance.
0 replies 0 retweets 1 likeThanks. Twitter will use this to make your timeline better. UndoUndo
-
Loading seems to be taking a while.
Twitter may be over capacity or experiencing a momentary hiccup. Try again or visit Twitter Status for more information.