Trying to use this trick, by Miles Sabin, to create a function which accepts a parameter of only a set of predefined types.
val bool = Boolean
val timestamp = new Timestamp(date.getTime())
val str = "My String"
and then following should pass at compile time
takeValue(bool)
takeValue(timestamp)
takeValue(str)
but
where takeValue should fail for takeValue(someIntValue) if implicit for type Int isn't defined.And this failure will be at compile time.
trait MyConv[K] { type V; def convert: AnyRef => V }
def iMakeConv[V0](con: AnyRef => V0) = new MyConv[con.type] {
override type V = V0
val convert = con
}
def takeValue(value:AnyRef)(implicit conv :MyConv[value.type]) : \/[Throwable,conv.V] = \/.fromTryCatch(conv.convert(value))
And then
implicit val strAny = iMakeConv((x:Any) => x.toString)
Then I would want takeValue(str) to work at compile time but takeValue(someIntValue) to fail at compile time since there isn't any appropriate implicit defined for it. Basically want to limit(at compile time) type of types takeValue can take and fail for others.
Certainly I am doing something wrong here because when calling
takeValue("string")
it throws following at compile time
could not find implicit value for parameter conv:
MyConv[String("string")]
- not enough arguments for method takeValue: (implicit conv:
MyConv[String("string")])scalaz.\/[Throwable,conv.V].
Unspecified value parameter conv.
The meaning of .type is often misunderstood. The type value.type is a type with only a single value - value. Even if value is known to be String, value.type is not String, but specifically only one String - value.
As a result, the code tries to find a MyConv[value.type], of which none exist, even if there is a MyConv[String] available.
Have takeValue use a type parameter instead:
def takeValue[T](value: T)(implicit conv: MyConv[T]) : \/[Throwable, conv.V] = \/.fromTryCatch(conv.convert(value))
Or alternatively make the type parameter of MyConv contravariant:
trait MyConv[-K] { type V; def convert: AnyRef => V }
Which would allow a MyConv[T] to be used if value.type is a subtype of T.
You also need a different MyConv and iMakeConv:
trait MyConv[K] { type V; def convert: K => V }
def iMakeConv[K, V0](con: K => V0) = new MyConv[K] {
override type V = V0
val convert = con
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With