Reputation: 41909
Given the following Phantom Type example in Haskell from phadej:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Distance a = Distance Double
deriving (Num, Show)
data Kilometer
data Mile
marathonDistance :: Distance Kilometer
marathonDistance = Distance 42.195
distanceKmToMiles :: Distance Kilometer -> Distance Mile
distanceKmToMiles (Distance km) = Distance (0.621371 * km)
marathonDistanceInMiles :: Distance Mile
marathonDistanceInMiles = distanceKmToMiles marathonDistance
I attempted to translate that to Scala:
case class Distance[A](x: Double) extends AnyVal
case object Kilometer
case object Mile
def marathonDistance: Distance[Kilometer.type] = Distance[Kilometer.type](42.195)
def distanceKmToMiles(kilos: Distance[Kilometer.type]): Distance[Mile.type] =
Distance[Mile.type](kilos.x * 0.621371)
def marathonDistanceInMiles: Distance[Mile.type] = distanceKmToMiles( marathonDistance )
Assuming this Phantom Type implementation is valid in Scala, will this usage of Distance
result in an allocation, i.e. use the heap, not the stack?
If it will allocate, what's the reason?
Upvotes: 2
Views: 110
Reputation: 55569
As is, your code shouldn't result in any allocation of a Distance
class, because it doesn't do any of the things that would cause it:
- a value class is treated as another type.
- a value class is assigned to an array.
- doing runtime type tests, such as pattern matching.
It doesn't treat them as another type, there are no arrays, and no type tests.
In these examples, an instance of Distance
would be allocated, boxed, and unboxed:
Type tests:
def d(dist: Distance[Mile.type]): Double = dist match {
case Distance(x) if x > 0 => 1.0
case Distance(x) => x
}
Treated as another type (generic A):
def identity[A](t: A): A = t
Arrays:
val dist = Distance[Meter.type](1.0)
val arr = Array[Distance[Meter.type]](dist)
The same is true whether the type parameter is there or not.
Upvotes: 4