Skip to content

Instantly share code, notes, and snippets.

View bbarker's full-sized avatar

Brandon Elam Barker bbarker

View GitHub Profile
@bbarker
bbarker / Example3a.scala
Created December 12, 2021 04:41
create a new class and a few example values
case class ScalaBean[A](initA: A):
private var theA: A = initA
def getTheA: A = theA
def setTheA(a: A): Unit = {
this.theA = a
}
val bean1: ScalaBean[Int] = ScalaBean(1)
val bean2: ScalaBean[String] = ScalaBean("Foo")
val bean3: ScalaBean[Int] = ScalaBean(2)
val outsFromInsEx: List[Outer[?]] = List(in1, in2).map(Outer.apply)
@bbarker
bbarker / Example2g.scala
Created December 12, 2021 04:37
the values were from a third-party library we don't control. We can emulate such behavior here
val in1any2: Inner[Any] = (Inner("foo"): Inner[String])
// ❌ Found: Playground.Inner[String]
// Required: Playground.Inner[Any]
@bbarker
bbarker / Example2f.scala
Last active December 12, 2021 04:28
If we explicitly type the list values, then we can create our list of `Any`s
val in1any: Inner[Any] = Inner("foo")
val in2any: Inner[Any] = Inner(3)
val outsFromInsAny2: List[Outer[Any]] = List(in1any, in2any).map(Outer.apply)
@bbarker
bbarker / Example2e.scala
Last active December 12, 2021 04:29
If we explicitly ascribe more precise types for each value, then we run into the same kind of error
val someStuffAny2: List[SomeClass[Any]] =
List(SomeClass("foo"): SomeClass[String], SomeClass(1): SomeClass[Int])
// ❌ Found: Playground.SomeClass[Int]
// Required: Playground.SomeClass[Any]
// ❌ Found: Playground.SomeClass[String]
// Required: Playground.SomeClass[Any]
@bbarker
bbarker / Example2d.scala
Created December 12, 2021 04:23
we construct a list of values that are invariant in their type parameter
val someStuffAny: List[SomeClass[Any]] = List(SomeClass("foo"), SomeClass(1))
@bbarker
bbarker / Example2c.scala
Created December 12, 2021 04:22
This problem would not arise if either or both of Outer or Inner had been declared with a covariant type parameter (+A) (try it), e.g.:
case class Inner[+A](a: A)
// Or:
case class Outer[+A](a: Inner[A])
@bbarker
bbarker / Example2b.scala
Created December 12, 2021 04:19
To see what is going wrong in outsFromInsAny, we can look at a simpler problem:
val outer1: Outer[Any] = Outer.apply(in1)
// ❌ Found: (Playground.in1 : Playground.Inner[String])
// Required: Playground.Inner[Any]
@bbarker
bbarker / Example2a.scala
Created December 12, 2021 03:42
List of nested invariants
case class Inner[A](a: A)
case class Outer[A](a: Inner[A])
val in1 = Inner("foo")
val in2 = Inner(3)
// Doesn't work as we'd hoped
val outsFromInsAny: List[Outer[Any]] = List(in1, in2).map(Outer.apply)
// ❌ Found: Playground.Inner[?1.CAP]
// Required: Playground.Inner[Any]
@bbarker
bbarker / Example1b.scala
Created December 12, 2021 03:39
Errors that occur when using "polymorphic" functions
// These don't work, but why?
val u1 = funPoly(someStuffEx)
// ❌ Found: (Playground.someStuffEx : List[Playground.SomeClass[?]])
// Required: List[Playground.SomeClass[A]]
// where: A is a type variable
val u2 = funAny(someStuffEx)
// ❌ Found: (Playground.someStuffEx : List[Playground.SomeClass[?]])
// Required: List[Playground.SomeClass[Any]]
// This works fine