Bind wildcard type argument in Scala - scala

In Scala 2, you can of course use use wildcard or existential types as type arguments. However, this means that you do not always have a name for a type you'd like to use. This sometimes leads to odd situations where you need to lean on type inference to circumvent writing a type explicitly.
Here is a somewhat contrived example of what I mean:
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
def identity[T](container: Container[T]): Container[T] = {
// A weird way of writing the identity function,
// but notice that I have essentially given the name
// `T` to the `_`
container.replace(container.value)
}
var x: Container[_] = Container[Int](1)
// This works, but as far as I know, there's no way to explicitly
// pass the type for `T`. For example, something like identity[_](x) won't work.
identity(x)
// This also fails to work, but if we could assign a name to the `_`, like `T`,
// then it would become obvious that this should work.
// x.replace(x.value)
Is there a way to get around this more cleanly? It would be really great if you could write something like:
let Container[T] = x.type in {
// Now there is a type T in this scope,
// and x has type `Container[T]`
}
As far as I'm aware, nothing of the sort exists in Scala. Is there a feature I'm missing. Also, does anyone know of similar features in other languages?

Use type pattern matching (tested with 2.13):
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
val x: Container[_] = Container[Int](1)
val y: Container[_] = x match {
case c => c.replace(c.value)
}
The actual type itself does not have a name in code, and isn't actually visible, but what's basically happening is this:
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
val x: Container[_] = Container[Int](1)
val y: Container[_] = x match {
case c: Container[t] =>{
val v: t = c.value
c.replace(v)
}
}
The type pattern t binds the existentially quantified type, and can be used in subsequent expressions, so that v: t can be typed, and c.replace(v) is also properly typed.
See also the following related questions:
Mapping over a list of existential types
Why does this snippet with pattern matching and higher kinded types no longer compile in Scala 2.12?

One more option is to make T a type member rather than type parameter. In such case the existential type corresponds to just Container while a specific type is Container { type T = ... } (aka Container.Aux[...]). Unfortunately, type-member type can't be used in the class primary constructor
case class Container(value: T) { // not found: type T
type T
//...
}
so I'm replacing the case class with a trait + factory method
trait Container {
type T
def value: T
def replace(value: T): Container.Aux[T] = Container(value)
}
object Container {
type Aux[_T] = Container { type T = _T }
// factory method
def apply[_T](_value: _T): Aux[_T] = new Container {
override type T = _T
override val value: T = _value
}
}
val x: Container = Container[Int](1)
x.replace(x.value) // compiles
def identity[T](container: Container.Aux[T]): Container.Aux[T] =
container.replace(container.value)
identity[x.T](x) // compiles
Please notice that I made x a val rather than var so that the path-dependent type x.T makes sense.
Maybe you prefer to keep a case class because of all the syntax sugar the compiler generates for case classes. In such case we could introduce an additional trait
trait IContainer {
type T
def value: T
def replace(value: T): IContainer.Aux[T]
}
object IContainer {
type Aux[_T] = IContainer { type T = _T }
}
case class Container[_T](value: _T) extends IContainer {
override type T = _T
override def replace(value: T): Container[T] = Container(value)
}
val x: IContainer = Container[Int](1)
x.replace(x.value) // compiles
def identity[T](container: IContainer.Aux[T]): IContainer.Aux[T] =
container.replace(container.value)
identity[x.T](x) // compiles

Related

How to return subtype of a generic trait in scala?

I am trying to create a factory pattern, and the return type is a parametrized trait, and the actual return type will be a subtype of that trait, but I do not know the generic type beforehand, so I don't know how to specify the return type. A simplified version is like this:
trait Mapper[T] {
def createMap(a: T, b: T): T
}
class MapperA extends Mapper[String]{
override def createMap(a: String, b: String): String = {
a + b
}
}
class MapperB extends Mapper[Int]{
override def createMap(a: Int, b: Int): Int = {
a + b + b + b
}
}
def factory(typeOfMapper: String): Mapper = {
typeOfMapper match {
case "mapperA" => new MapperA()
case "mapperB" => new MapperB()
}
}
val mapper = factory("mapperA")
This will give me and error of
trait Mapper takes type parameters
but I do not know the generic type beforehand. What should the return type be for the factory method here?
Well, you could return Mapper[_] ... that will compile, but isn't really very useful, as pointed out in the comments: you won't be able to use the returned value in any meaningful way, because actual type of create will be unknown.
If different instances of your mapper will always have different type parameters (at least, within the same scope), then a neat solution would be using implicits:
object Mapper {
implicit def strMapper: Mapper[String] = new MapperA
implicit def intMapper: Mapper[Int] = new MapperB
}
Then everywhere you have these visible, you can just do:
val m1: Mapper[String] = implicitly[Mapper[String]]
val m2: Mapper[Int] = implicitly[Mapper[Int]]
You could also write your factory function (though, I am not sure why you'd want to) like this:
def mapperFactory[T: Mapper] = implicitly[Mapper[T]]
and use it like this:
val m: Mapper[String] = mapperFactory
or like this
def intMapper = mapperFactory[Int]
If you want different mappers for the same type parameter, it's basically the same idea, except it does't look as neat without implicits. The key is different factories for different types:
class Mapper {
def str(`type`: String): Mapper[String] = `type` match {
case "foo" => FooMapper()
case "bar" => BarMapper()
}
def int(`type`: String): Mapper[Int] = `type` match {
case "baz" => BazMapper()
case "bak" => BakMapper()
}
}
val fooMapper = Mapper.str("foo")
val bakMapper = Mapper.int("bak")

Scala Design using reflection, implicit and generics

I have different sources and corresponding parameters
Source1, Source2, Source3
Parameter1, Parameter2, Parameter3,
Source: is trait (can be changed)
trait Source[T] {
def get(Parameter)(implicit c: Context): MyData[T]
}
Parameter is also a trait
trait Parameter
I have different OutputType class: T1, T2, T3
I need output as: MyData[OutputType]
Fixed API signature (changes to the signature not quite preferable):
val data1: MyData[T1] = MyAPI.get[T1](Parameter1("a", "b")) // this should give MyData from Source1 of type T1
val data2: MyData[T2] = MyAPI.get[T2](Parameter3(123)) // this should give MyData from Source3 of type T2
Some source supports some output types (say T1, T2), but some may not.
What I did:
I tried using scala reflection typeTag to determine the type at runtime, but since return type will be MyData[T], and is in contra-variant position, it wont know the actual return type. (Why does TypeTag not work for return types?)
e.g.
object MyAPI {
get[T: TypeTag](p: Parameter)(implicit c: Context): MyData[T] = {}
}
I also tried using type-class pattern. Scala TypeTag Reflection returning type T
I can work with different OutputType creating implicit val for each, but would only work for single Source1. I can't manage to work for all sources.
I was trying to do:
object MyAPI {
get[T: SomeConverter](p: Parameter)(implicit c: Context): MyData[T] = {
p match {
case Parameter1 => Source1[T].read(p.asInstanceOf(Parameter1)
case Parameter2 => Source2[T].read(p.asInstanceOf(Parameter2)
}
}
}
Disclaimer: I think I figured out what you want. I'm also learning to design type-safe APIs, so here's one.
Provided variant uses implicits. You have to manually establish mapping between parameter types and results they yield, which may or may not include sources. It does not work on runtime, however, so I also removed common trait Parameter. It also does not impose any restrictions on the Sources at all.
It also "looks" the way you wanted it to look, but it's not exactly that.
case class User(id: Int) // Example result type
// Notice I totally removed any and all relation between different parameter types and sources
// We will rebuild those relations later using implicits
object Param1
case class Param2(id: Int)
case class Param3(key: String, filter: Option[String])
// these objects have kinda different APIs. We will unify them.
// I'm not using MyData[T] because it's completely irrelevant. Types here are Int, User and String
object Source1 {
def getInt = 42
}
object Source2 {
def addFoo(id: Int): Int = id + 0xF00
def getUser(id: Int) = User(id)
}
object Source3 {
def getGoodInt = 0xC0FFEE
}
// Finally, our dark implicit magic starts
// This type will provide a way to give requested result for provided parameter
// and sealedness will prevent user from adding more sources - remove if not needed
sealed trait CanGive[Param, Result] {
def apply(p: Param): Result
}
// Scala will look for implicit CanGive-s in companion object
object CanGive {
private def wrap[P, R](fn: P => R): P CanGive R =
new (P CanGive R) {
override def apply(p: P): R = fn(p)
}
// there three show how you can pass your Context here. I'm using DummyImplicits here as placeholders
implicit def param1ToInt(implicit source: DummyImplicit): CanGive[Param1.type, Int] =
wrap((p: Param1.type) => Source1.getInt)
implicit def param2ToInt(implicit source: DummyImplicit): CanGive[Param2, Int] =
wrap((p: Param2) => Source2.addFoo(p.id))
implicit def param2ToUser(implicit source: DummyImplicit): CanGive[Param2, User] =
wrap((p: Param2) => Source2.getUser(p.id))
implicit val param3ToInt: CanGive[Param3, Int] = wrap((p: Param3) => Source3.getGoodInt)
// This one is completely ad-hoc and doesn't even use the Source3, only parameter
implicit val param3ToString: CanGive[Param3, String] = wrap((p: Param3) => p.filter.map(p.key + ":" + _).getOrElse(p.key))
}
object MyApi {
// We need a get method with two generic parameters: Result type and Parameter type
// We can "curry" type parameters using intermediate class and give it syntax of a function
// by implementing apply method
def get[T] = new _GetImpl[T]
class _GetImpl[Result] {
def apply[Param](p: Param)(implicit ev: Param CanGive Result): Result = ev(p)
}
}
MyApi.get[Int](Param1) // 42: Int
MyApi.get[Int](Param2(5)) // 3845: Int
MyApi.get[User](Param2(1)) // User(1): User
MyApi.get[Int](Param3("Foo", None)) // 12648430: Int
MyApi.get[String](Param3("Text", Some(" read it"))) // Text: read it: String
// The following block doesn't compile
//MyApi.get[User](Param1) // Implicit not found
//MyApi.get[String](Param1) // Implicit not found
//MyApi.get[User](Param3("Slevin", None)) // Implicit not found
//MyApi.get[System](Param2(1)) // Same. Unrelated requested types won't work either
object Main extends App {
sealed trait Parameter
case class Parameter1(n: Int) extends Parameter with Source[Int] {
override def get(p: Parameter): MyData[Int] = MyData(n)
}
case class Parameter2(s: String) extends Parameter with Source[String] {
override def get(p: Parameter): MyData[String] = MyData(s)
}
case class MyData[T](t: T)
trait Source[T] {
def get(p: Parameter): MyData[T]
}
object MyAPI {
def get[T](p: Parameter with Source[T]): MyData[T] = p match {
case p1: Parameter1 => p1.get(p)
case p2: Parameter2 => p2.get(p)
}
}
val data1: MyData[Int] = MyAPI.get(Parameter1(15)) // this should give MyData from Source1 of type T1
val data2: MyData[String] = MyAPI.get(Parameter2("Hello World")) // this should give MyData from Source3 of type T2
println(data1)
println(data2)
}
Does this do what you want?
ScalaFiddle: https://scalafiddle.io/sf/FrjJz75/0

Proving equivalence of nested path dependent types members

This is a simplified case, and I am totally open to a different/better way to achieve this
trait Container {
type T
def data: List[T]
}
trait Transform {
val from: Container
val to: Container
def xform: from.T => to.T
}
case class Identity(c: Container) extends Transform {
val from = c
val to = c
def xform = { t: from.T => t }
}
This yields the predictable error of:
<console>:12: error: type mismatch;
found : t.type (with underlying type Identity.this.from.T)
required: Identity.this.to.T
def xform = { t: from.T => t }
The goal is basically to have a transform which transforms objects underlying the container, but to be able to convince the type checker (without horrible horrible casts all over the place) that the types are the same.
What is the best way to be able to show equivalences and relationships of types in this way?
Like I said, totally open to restructuring the code and I promise in the actual example it is for a real purpose :)
I think generic parameters might be an easier way to describe this pattern.
You can avoid the generic parameter all together, however, by explicitly identifying the type T on both the Container instances:
case class Identity(c: Container) extends Transform {
val from: Container { type T = c.T } = c
val to: Container { type T = c.T } = c
def xform = { t: from.T => t }
}
Or even simpler:
case class Identity(c: Container) extends Transform {
val from: c.type = c
val to: c.type = c
def xform = { t: from.T => t }
}
If you're OK with only avoiding the generic parameters on Container and Transform, you can convince the compiler that the types works by doing:
case class Identity[U](c: Container { type T = U }) extends Transform {
val from = c
val to = c
def xform = { t: c.T => t }
}
The generic parameter U does nothing other than give another name to the T type on the Container parameter, but that is enough to do the trick!
To me, all these solutions really just underscore how seemingly arbitrary the power of the type checker is when it comes to these sorts of types. I can't really explain why they are necessary or sufficient. In my experience, it is much more predictable to work with generic parameters (although of course it can be much messier).
Because the type in Container isn't exposed, you can't infer anything about the Identity class. Think about if you were using this from another library, there's no way to know what type xform is if you're just given and Identity object. Really, the only definition that you could use for xform is something like:
def xform = { t: from.T => to.data.head }
And the only way you could call would be with from.data.head.
An alternative is to drop path dependent types and use higher kinded types:
trait Container[T] {
def data: List[T]
}
trait Transform[A, B] {
val from: Container[A]
val to: Container[B]
def xform: A => B
}
case class Identity[A](c: Container[A]) extends Transform[A, A] {
val from = c
val to = c
def xform = { t: A => t }
}
If one is ever stuck with dependent types, structural refinement is an ugly but effective bail-out.
abstract class ContainerRefiner {
val container: Container
}
trait Container {
type T
def data: List[T]
}
trait Transform {
val from: Container
val to: Container
def xform: from.T => to.T
}
case class Identity(c: Container) extends Transform {
val refiner = new {val container: c.type = c} with ContainerRefiner
val from = refiner.container
val to = refiner.container
def xform = { t: from.T => t }
}
Can anyone please comment on the pros and cons between this approach and higher kinded types?

Add a trait to parametric type in a class

I have a library where an abstract class Base[T] is over a type T supplied by the user. There are many specific Base[T] sub-classes, some are over types T and S, like Specific[T, S], but this is irrelevant. The user might specify any T of course while creating and instance, but I want to treat it as T with a trait AdditionalAbilities or in other words I want to 'gift' the user's type with AdditionalAbilities. How can I do that in Scala? I hope the title is correct for this question.
Example (might not be syntactically correct)
class Specific[T **with trait Additional**]() extends Base[T](){
def doSomething() : T = {
val something = new T()
something.ability(2)
println(something.additional)
something
}
}
trait Additional{
var additional : Integer
def ability(i : Integer) : Unit = {
additional = i
}
}
Would work with any T.
When you define a parametric class you can require the parameter type to descend from a certain type:
trait AdditionalAbilities {
def doStuff(): Unit = println("Hey There")
}
object NoAbility extends AdditionalAbilities {
override def doStuff(): Unit = ()
}
abstract class Base[T] { ... }
class Specific[T <: AdditionalAbilities] extends Base[T] {
def f(t: T): Unit = t.doStuff()
}
Then when you try to instantiate a Specific type:
scala> new Specific[Int] {}
<console>:13: error: type arguments [Int] do not conform to class Specific's type parameter bounds [T <: AdditionalAbilities]
scala> val b = new Specific[NoAbility.type] {}
b: Specific[NoAbility.type] = $anon$1#517cd4b
scala> b.f(NoAbility)
//did nothing
Also, if you want to add a behaviour to an existing concrete class, you can do so at the time of instantiation:
trait CoolAbilities { def doStuff(): Unit = println("Hey there") }
class A { }
scala> val a = new A with CoolAbilities
a: A with CoolAbilities = $anon$1#6ad3381f
scala> a.doStuff()
Hey there
Perhaps implicit classes could help? Implicit classes allow you to add functionality to an existing type without needing to modify the existing type, or be the one instantiating it (so that you could mix in a trait).
The following compiles, and prints: 3
class Specific[T] {
implicit class TAdditional(t: T) {
var additional: Integer = 0
def ability(i: Integer) = {
additional = i
}
}
def doSomething(t: T) = {
doSomethingAdditional(t)
}
private def doSomethingAdditional(t: TAdditional) = {
t.ability(3)
println(t.additional)
}
}
val s = new Specific[Int]
s.doSomething(5)
Note: We need to do something to make sure we are accessing the same instance
of TAdditional, that's why I made the private doSomethingAdditional method that takes a TAdditional as an argument. If we call ability and additional in 'doSomething', separate instances of TAdditional would be created when we try to access #ability and #additional, and '0' would be printed.

Scala: retrieve type parameter from generic collection (ClassTag?)

I am defining an abstract class taking a type parameter, along with several concrete classes which set this type.
abstract class GenericFoo[T: ClassTag] {
def defaultValue: T
def useTheValue(v: T): T
}
object DoubleFoo extends GenericFoo[Double] {
def defaultValue = 42.0
def useTheValue(v: Double) = v * 2
}
object IntFoo extends GenericFoo[Int] {
def defaultValue = 1337
def useTheValue(v: Int) = v + 64
}
But when storing my Foos in a mixed collection, it seems that my type parameter T always ends up being inferred up to Any.
val fooCollection:List[GenericFoo[_]] = List(DoubleFoo, IntFoo)
for {
foo <- fooCollection
defaultValue = foo.defaultValue
result = foo.useTheValue(defaultValue)
// Error: `defaultValue` has type `Any`, cannot call `useTheValue`
} yield result
Based on several answers to similar questions, I thought using type parameter wildcard (GenericFoo[_]), and maybe ClassTag would help keep type information, but I couldn't get this example to work as I wanted.
In the snippet above, I would want foo.defaultValue to be recognized as having the correct type (T) to be applicable in foo.useTheValue(). Have I missed something?
Edit: #gzm0 was prompt to suggest that I use abstract type members. My original use-case was a little more involved, as I am also defining an abstract type for a companion object. My actual code does something similar to:
trait GenericCompanion[T] {
// Some "static" members
def defaultValue: T
def useTheValue(v: T): T
}
abstract class GenericFoo[T] {
def getCompanion: GenericCompanion[T]
// Because of this operation, it's important that we have the same type `T`
def useCompanion: T = getCompanion.useTheValue(theActualValue)
val theActualValue: T
}
object ConcreteCompanion[Double] extends GenericCompanion[Double] {
// ...
}
object ConcreteFoo[Double] extends GenericFoo[Double] {
def getCompanion = ConcreteCompanion
}
Each concrete implementation of GenericFoo[T] also comes with a CompanionFoo[T]. Concrete sub-classes of GenericFoo are supposed to instantiated, while CompanionFoo[T] objects are here to hold "static" properties and operations. In this context, it is very important that the type parameter in GenericFoo is the same as the type parameter in GenericCompanion.
(I hope this is clear enough, sorry if my example is convoluted!)
This is a vanilla example for abstract type members. Try this:
abstract class GenericFoo {
type V
def defaultValue: V
def useTheValue(v: V): V
}
object DoubleFoo extends GenericFoo {
type V = Double
def defaultValue = 42.0
def useTheValue(v: Double) = v * 2
}
object IntFoo extends GenericFoo {
type V = Int
def defaultValue = 1337
def useTheValue(v: Int) = v + 64
}
val fooCollection:List[GenericFoo] = List(DoubleFoo, IntFoo)
Rest of the code remains unchanged.
If you use an abstract type member (rather than a type parameter), Scala will take track of the concrete types it knows for a given value.
From your example explained:
val foo: GenericCollection = ???
val defaultValue = foo.defaultValue
// defaultValue: foo.V
foo.useTheValue(defaultValue)
// foo.useTheValue: (foo.V): foo.V
Although the compiler does not know what true type foo.V is, it can nevertheless figure out that the type signatures match and that using calling useTheValue with defaultValue is OK.
As far as I can tell, this would also be a perfectly OK reasoning with type parameters, Scala just does not do it.
UPDATE
You can still do this, even with the more involved example:
trait GenericCompanion {
type T
// Some "static" members
def defaultValue: T
def useTheValue(v: T): T
}
abstract class GenericFoo { self =>
type T
def getCompanion: GenericCompanion { type T = self.T }
// Because of this operation, it's important that we have the same type `T`
def useCompanion: T = getCompanion.useTheValue(theActualValue)
val theActualValue: T
}
And the concrete implementations:
object ConcreteCompanionDouble extends GenericCompanion {
type T = Double
def defaultValue: Double = ???
def useTheValue(v: Double): Double = ???
// ...
}
object ConcreteFooDouble extends GenericFoo {
type T = Double
def getCompanion = ConcreteCompanionDouble
val theActualValue: Double = ???
}