Skip to content

Instantly share code, notes, and snippets.

@larsrh
Forked from soc/The Union Type Quiz
Last active December 19, 2015 09:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save larsrh/5936643 to your computer and use it in GitHub Desktop.
Save larsrh/5936643 to your computer and use it in GitHub Desktop.
My answer to @soc's "union type quiz". To be taken with a grain of salt, I'm not even into type theory.
The Union Type Quiz
===================
1. Please describe the guiding principle of your typing approach in one sentence:
For ADTs, do not (in general) expose the cases as types.
2. Should there be predefined implicit widening conversions between numbers?
( ) Yes, even if they are lossy
(X) Yes, but only non-lossy ones
( ) No
( ) Other: ______________________________
3. What should be the inferred type of the expression
List(1, 1.0)?
( ) List[Double]
(X) List[AnyVal]
( ) List[Int|Double]
( ) Other: ______________________________
4. What should be the inferred type of the expression
List(1: java.lang.Integer, 1.0: java.lang.Double)?
( ) List[Number with Comparable[_ >: Double with Integer <: Number with Comparable[_ >: Double with Integer <: Number ...]]]
( ) List[java.lang.Integer|java.lang.Double]
(X) Other: java.lang.Number
(Although this might be seen as a compelling use case for union types.)
5. Do you prefer a union type A|B to Either[A, B]?
( ) Always
( ) Never
( ) Sometimes: ______________________________
(X) Other: Both serve wildly different purpose. It's like asking "do you prefer Option[A] over A".
6. Do prefer a nullable type T? to e. g. Option[T]?
( ) Always
( ) Never
( ) Sometimes: ______________________________
(X) Other: Depends on whether "X?" is a proper type constructor. If not, then it's useless.
8. Given the following declarations ...
trait T
object A extends T
object B extends T
... what should be the inferred type of
if (true) A else B
(X) T
( ) A|B
( ) Other: ______________________________
Would be cool if Scala had a mechanism to specify "don't expose A.type (or A if it would be `trait A` instead of `A`)".
9. Does your answer change if
- trait T is sealed?
( ) Yes, because: __________________________________________________
(X) No, because: __________________________________________________
- A and/or B are classes?
( ) Yes, because: __________________________________________________
(X) No, because: __________________________________________________
- A/B/T are type constructors?
( ) Yes, because: __________________________________________________
(X) No, because: __________________________________________________
10. What should be the inferred type of
if (true) Some(1) else None?
(X) Option[Int]
( ) Some[Int]|None
( ) Other: ______________________________
11. What should be the inferred type of
if (true) Nil else List(1).asInstanceOf[::[Int]]?
(X) List[Int]
( ) Nil|::[Int]
( ) Other: ______________________________
12. When should a nominal type be preferred to a more precise union type?
(X) Always
( ) Never
( ) Only if the element types enumerate all subclasses/subobjects of a sealed supertype
( ) Other: ______________________________
13. When should a more precise structural type be preferred to a union type?
( ) Always
( ) Never
( ) Only if the structural type is specified explicitly
(X) Other: I have not yet made up my mind about inferring structural types when computing a lub. It's probably not the best idea.
14. Given the following declarations ...
trait T { def foo: Int }
class A extends T { def foo: Int = ???; def bar: Int = ??? }
class B extends T { def foo: Int = ???; def bar: Int = ???; def bippy: Int = ??? }
... which members are allowed to be called on an instance aOrB of type A|B?
[X] aOrB.toString
[X] aOrB.foo
[ ] aOrB.bar
[ ] aOrB.bippy
16. Given the following definitions ...
val x: AnyRef { def foo: Int } = null
val y: AnyRef { def foo: Int } = null
... should it be allowed to call xOrY.foo?
(X) Yes
( ) No
( ) Other: ______________________________
I'm not too sure about that one. For nominal types, it's quite clear to me to disallow methods which do not occur in the common (nominal) supertype, since from an OOP perspective two methods with the same name would be unrelated in that case. For structural types, the matter is different. Then again, I'm not a great fan of structural types in the first place.
17. Given the following definitions ...
val x = new AnyRef { def foo: Int = 23}
val y = new AnyRef { def foo: Int = 42}
... should it be allowed to call xOrY.foo?
(X) Yes
( ) No
( ) Other: ______________________________
18. Will your design break existing, valid code?
(X) Yes
( ) Yes, but it doesn't matter because: ______________________________
( ) No, because: ______________________________
( ) Maybe?
19. Describe how null will work with union types:
I don't even care about null.
20. Will your design make a difference whether a type has been inferred and has been specified explicitly?
Probably.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment