I'm trying to do something in Scala that I'm not sure is possible. I'd love some feedback from the community.
Say I have a sealed trait for some 'thing', a few concrete extensions of it, and a generic class which works with some implementation of that trait..
sealed trait Thing
class CoolThing extends Thing
class OtherThing extends Thing
class BoxOfThings[T <: Thing]
Now, I can define another class which handles two 'boxes of things' like so..
class PairOfBoxes(boxOne: BoxOfThings[_ <: Thing], boxTwo: BoxOfThings[_ <: Thing])
However, here it's perfectly fine to create a PairOfBoxes with one box of CoolThings and the other of OtherThings. I would like to declare that boxOne and boxTwo contain the same type of Thing.. is that at all possible?
For example:
// Cool things..
val boxOfCoolThings = new BoxOfThings[CoolThing]
val anotherBoxOfCoolThings = new BoxOfThings[CoolThing]
// Other things..
val boxOfOtherThings = new BoxOfThings[OtherThing]
// A pair of cool boxes, no problem:
new PairOfBoxes(boxOfCoolThings, anotherBoxOfCoolThings)
// A pair of different boxes, compiles but I don't want it to:
new PairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThings)
I could do this by making the PairOfBoxes generic itself, like so..
class TypedPairOfBoxes[T <: BoxOfThings[_ <: Thing]](boxOne: T, boxTwo: T)
It works, but it's ugly..
// A pair of cool boxes, no problem:
new TypedPairOfBoxes[BoxOfThings[CoolThing]](boxOfCoolThings, anotherBoxOfCoolThings)
// A pair of different boxes, doesn't compile:
val mixedPair = new TypedPairOfBoxes[BoxOfThings[CoolThing]](boxOfOtherThings, anotherBoxOfCoolThings)
I would like to avoid this is I can. It pushes the problem upstream and forces us to specify the contents of each TypedPairOfBoxes. It would be ideal to simply use an untyped PairOfBoxes which asserts it's parameters are of the same type.
Possible?
Thanks!
You just need to write as:
class TypedPairOfBoxes[T <: Thing](one: BoxOfThings[T], two: BoxOfThings[T])
Then:
scala> new TypedPairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThings)
<console>:15: error: type mismatch;
found : BoxOfThings[OtherThing]
required: BoxOfThings[Thing]
Note: OtherThing <: Thing, but class BoxOfThings is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
new TypedPairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThings)
^
<console>:15: error: type mismatch;
found : BoxOfThings[CoolThing]
required: BoxOfThings[Thing]
Note: CoolThing <: Thing, but class BoxOfThings is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
new TypedPairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThings)
^
scala> new TypedPairOfBoxes(boxOfCoolThings, anotherBoxOfCoolThings)
res3: TypedPairOfBoxes[CoolThing] = TypedPairOfBoxes#2f5e1167
I <3 Scala
Scala can infer the generic types such that I can define an 'ugly' typed class but don't need to specify the specific implementation when I use it.
With this realization, I was able to define a typed class similar to the one in my question above..
class TypedPairOfBoxes[T, BoxOfThings[T <: Thing]](boxOne: BoxOfThings[T], boxTwo: BoxOfThings[T])
.. it looks a bit gnarly, but can be used as simply as this:
// Both boxes contain cool things, no problem:
new TypedPairOfBoxes(boxOfCoolThings, anotherBoxOfCoolThing)
// These boxes contain different things, doesn't compile:
new TypedPairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThing)
Amazing.
Edit:
As #Eastsun demonstrated, the latter part of of the generic definition is unused. So can be written, instead, as:
class TypedPairOfBoxes[T <: Thing](boxOne: BoxOfThings[T], boxTwo: BoxOfThings[T])
This looks very much like Java. But the amazing thing here being that Scala infers the generic types from the parameters.
Related
Here is a simple example:
trait Base {
type Out
def v: Out
}
object Base {
type Aux[T] = Base { type Out = T }
class ForH() extends Base {
type Out = HNil
override def v: Out = HNil
}
object ForH extends ForH
}
class TypeClass[B]
trait TypeClassLevel1 {
def summon[B](b: B)(implicit ev: TypeClass[B]): TypeClass[B] = ev
}
object TypeClass extends TypeClassLevel1 {
implicit def t1: TypeClass[Base.Aux[HNil]] = new TypeClass[Base.Aux[HNil]]
implicit def t2: TypeClass[Int] = new TypeClass[Int]
}
it("No Aux") {
val v = 2
TypeClass.summon(v) // works
}
it("Aux") {
val v = new Base.ForH()
TypeClass.summon(v) // oops
TypeClass.summon(Base.ForH) // oops
val v2 = new Base.ForH(): Base.Aux[HNil]
TypeClass.summon(v2) // works!
}
The object Base/ForH clearly has a stable path, this eliminate the possibility of the compiler not being able to resolve type ForH.Out.
What bothers me is not how incapable the compiler is to figure out the fact that ForH <:< Aux[HNil], but how easy it is to patch it up, just by a simple type upcast (last 2 lines). IMHO both features (type lambda & type classes) are important aspect of functional programming, why they can't work together at the same time?
If you are familiar with the compiler design I'll have an extra question: what does it take to improve the type class search algorithm to make it happen? Thanks a lot for your opinion.
UPDATE 1: a specific fix has been proposed but I have another problem trying to generalise it, please see In scala, how to make type class working for Aux pattern? - Part 2 for detail
So the compiler is able to infer ForH <:< Aux[HNil], but (tbh I don't know exactly why) when resolving an implicit when the return type uses a type lambda, it gets confused if you don't use a type bound.
Anyway that's probably not a great explanation, but at least I can make your code compile. Just change t1 to:
implicit def t1[T <: Base.Aux[HNil] ]: TypeClass[T] = new TypeClass[T]
this works for me in scastie using Scala 2.13.4.
What bothers me is not how incapable the compiler is to figure out the fact that ForH <:< Aux[HNil]
Surely the compiler does see that Base.ForH <:< Base.Aux[HNil]. You can check that
implicitly[Base.ForH <:< Base.Aux[HNil]]
compiles.
IMHO both features (type lambda & type classes) are important aspect of functional programming, why they can't work together at the same time?
Why are you talking about type lambdas? I can't see type lambdas in your question.
By the way, type lambdas is not a part of Scala 2 and ({ type λ[X] = ...F[X]... })#λ for a type lambda is more or less a hack. Actual type lambdas are added to Scala 3.
val v = new Base.ForH() has type Base.ForH (not Base.Aux[HNil] without upcasting via type ascription val v = new Base.ForH(): Base.Aux[HNil] or manual type specification val v: Base.Aux[HNil] = new Base.ForH()). TypeClass.summon(v) shouldn't compile since there is no implicit TypeClass[Base.ForH]. What implicit would you consider as a candidate? TypeClass.t1? But it's not a candidate, you can check that explicitly resolved
TypeClass.summon(v)(TypeClass.t1)
can't compile.
what does it take to improve the type class search algorithm to make it happen?
Implicit search algorithm shouldn't be improved in this specific place. It works properly, as intended.
You can make the type class contravariant
class TypeClass[-B]
Then TypeClass.t1 will be a candidate for TypeClass[Base.ForH] and TypeClass.summon(v) will compile.
In scala 2.13, how to use implicitly[value singleton type]?
I have an issue working with existentials in Scala. My problem started when creating a mini workflow engine. I started on the idea that it was a directed graph, implemented the model for the latter first and then modeled the Workflow like this:
case class Workflow private(states: List[StateDef], transitions: List[_, _], override val edges: Map[String, List[StateDef]]) extends Digraph[String, StateDef, Transition[_, _]](states, edges) { ... }
In this case class, the first two fields are a list of states which behave as node, transitions which behave as edges.
The Transition parameter types are for the input and output parameters, as this should behave as an executable piece in the workflow, like a function of some sort:
case class Transition[-P, +R](tailState: StateDef, headState: StateDef, action: Action[P, R], condition: Option[Condition[P]] = None) extends Edge[String, StateDef](tailState, headState) {
def execute(param: P): Try[State[R]] = ...
}
I realized soon enough that dealing with a list of transitions in the Workflow object was giving me troubles with its type parameters. I tried to use parameters with [[Any]] and [[Nothing]], but I couldn't make it work (gist [1]).
If I'd do Java, I'd use a wildcard ? and use its 'less type safe and more dynamic' property and Java would have to believe me. But Scala is stricter and with variance and covariance of the Transition parameter types, it's hard to define wildcards and handle these properly. For example, using forSome notation and having a method in Workflow, I would get this error (gist [2]):
Error:(55, 24) type mismatch;
found : List[A$A27.this.Transition[A$A27.this.CreateImage,A$A27.this.Image]]
required: List[A$A27.this.Transition[P forSome { type P },R forSome { type R }]]
lazy val w = Workflow(transitions)
^
Hence then I created an existential type based on a trait (gist [3]), as explained in this article.
trait Transitions {
type Param
type Return
val transition: Transition[Param, Return]
val evidenceParam: StateValue[Param]
val evidenceReturn: StateValue[Return]
}
So now I could plug this existential in my Workflow class like this:
case class Workflow private(states: List[StateDef], transitions: List[Transitions], override val edges: Map[String, List[StateDef]])
extends Digraph[String, StateDef, Transitions](states, edges)
Working in a small file proved to be working (gist [3]). But when I moved on to the real code, my Digraph parent class does not like this Transitions existential. The former needs an Edge[ID, V] type, which Transition complies with but not the Transitions existential of course.
How in Scala does one resolve this situation? It seems troublesome to work with parameter types to get generics in Scala. Is there an easier solution that I haven't tried? Or a magic trick to specify the correct compatible parameter type between Digraph which need an Edge[ID, V] type and not an existential type that basically erase type traces?
I am sorry as this is convoluted, I will try my best to update the question if necessary.
Here are the Gist references for some of my trials and errors:
https://gist.github.com/jimleroyer/943efd00c764880b8119786d9dd6c3a2
https://gist.github.com/jimleroyer/1ce238b3934882ddc02a09485f52f407
https://gist.github.com/jimleroyer/17227b7e334d020a21deb36086b9b978
EDIT-1
Based on #HTNW answer, I've modified the scope of the existentials using forSome and updated the solution: https://gist.github.com/jimleroyer/2cb4ccbec13620585d21d53b4431ce22
I still have an issue though to properly bind the generics with the matchTransition & getTransition methods and without an explicit cast using asInstanceOf. I'll open another question specific to that one issue.
You scoped your existential quantifiers wrong.
R forSome { type R }
is equal to Any, because every single type is a type, so every single type is a subtype of that existential type, and that is the distinguishing feature of Any. Therefore
Transition[P forSome { type P }, R forSome { type R }]
is really
Transition[Any, Any]
and the Transitions end up needing to take Anys as parameter, and you lose all information about the type of the return. Make it
List[Transition[P, R] forSome { type P; type R }] // if every transition can have different types
List[Transition[P, R]] forSome { type P; type R } // if all the transitions need similar types
// The first can also be sugared to
List[Transition[_, _]]
// _ scopes so the forSome is placed outside the nearest enclosing grouping
Also, I don't get where you got the idea that Java's ? is "less safe". Code using it has a higher chance of being unsafe, sure, because ? is limited, but on its own it is perfectly sound (modulo null).
I am working on a slick project and I am trying to make my database layer easily swappable between different profiles in order to write tests on an in-memory database. This question is inspired by this problem but it doesn't have anything to do with slick itself.
I don't have a great deal of experience with dependent types, in my case I have the following trait that I use to abstract away some types from the database:
trait Types {
type A <: SomeType
type B <: SomeOtherType
val bTag: ClassTag[B]
}
Then I have another trait which is basically a slice of my (faux) cake pattern:
trait BaseComponent {
type ComponentTypes <: Types
val a: Types#A
implicit val bTag: ClassTag[Types#B]
}
Then I have an actual implementation of my component that can be seen as follows:
trait DefaultTypes {
type A = SomeConcreteType
type B = SomeOtherConcreteType
val bTag = implicitly[ClassTag[B]]
}
trait DefaultBaseComponent extends BaseComponent {
type ComponentTypes = DefaultTypes
val ct = new ComponentTypes {}
implicit val bTag = ct.bTag
}
I need the tag because later on a service will need it (in my actual implementation I use this type to abstract over different type of exceptions thrown by different DB libraries); I am quite sure that there is a much better way to do what I am trying to do.
If I do not instantiate the ComponentTypes trait in order to get the tag and I move the implicit-conjuring code in the DefaultBaseComponent it will conjure a null in place of the ClassTag. I need to have a way to refer to the actual types that I am using (the different A and B that I have in my different environments) and I need to do it in other components without knowing which actual types they are.
My solution works, compiles and pass all the tests I wrote for it, can anyone help me in getting it better?
Thank you!
Your example is a bit unclear with all these Defaults and Components - maybe a more concrete example (e.g. DatabaseService / MysqlDatabaseService) would make it clearer?
You need to pass the ClassTag around wherever it's abstract - you can only "summon" one when you have a concrete type. You might like to package up the notion of a value and its tag:
trait TaggedValue[A] {val a: A; val ct: ClassTag[A]}
object TaggedValue {
def apply[A: ClassTag](a1: A) =
new TaggedValue[A] {
val a = a1
val ct = implicitly[ClassTag[A]]
}
}
but this is just a convenience thing. You could also turn some of your traits into abstract classes, allowing you to use [A: ClassTag] to pass the tags implicitly, but obviously this affects which classes you can multiply inherit.
If you're hitting nulls that sounds like a trait initialization order problem, though without a more specific error message it's hard to help. You might be able to resolve it by replacing some of your vals with defs, or by using early initializers.
I am unable to find out how to programatically construct existential types in Scala macros.
For example, let's assume that I have a ClassSymbol that represents a class C[T] that has one type parameter.
Now, how do I programatically construct the type C[_ <: java.lang.Number] ?
In particular, I have no idea how to use the ExistentialType constructor object. Looking at its signature:
def apply(quantified: List[Symbol], underlying: Type): ExistentialType
What do I pass as quantified?
From what I understand, you need to create quantified symbols yourself, setting their signatures manually. Here's an abridged and adapted version of what -Ymacro-debug-lite printed when I compiled typeOf[C[_ <: Number]]. Maybe Jason or Paul know a shortcut that avoids creating symbols manually, but I'm not sure the one exists in the public API.
class C[T]
object Test extends App {
import scala.reflect.runtime.universe._
val c = typeOf[C[_]].typeSymbol
val targ = build.newNestedSymbol(NoSymbol, newTypeName("_$1"), NoPosition, build.flagsFromBits(34359738384L), false)
build.setTypeSignature(targ, TypeBounds(typeOf[Nothing], typeOf[Number]))
println(ExistentialType(List(targ), TypeRef(c.owner.asClass.thisPrefix, c, List(TypeRef(NoPrefix, targ, Nil)))))
}
Is there a way to generically obtain a Scala type's manifest? For example, if I only have a Class reference to work with, is there a way I can obtain its corresponding manifest?
Scala's built-in implicitly[T] will get you an implicit value of type T (if one exists). So implicitly[Manifest[T]] will return a Manifest for type T.
If you have a Class reference, you can get the Manifest for the Class like this:
def manifestFor[T: Manifest](c: Class[T]) = implicitly[Manifest[T]]
class Foo
val x = new Foo
manifestFor(x.getClass)
//scala.reflect.Manifest[_ <: Foo] = _ <: Foo
The Manifest's type is _ <: Foo instead of just Foo, but they are equal.
implicitly[Manifest[Foo]] == manifestFor(x.getClass)
//Boolean = true
Well, I was trying to do something similar, but reflectively. I had no class symbol at compile time available. I had to use this code, not so obvious from the scaladocs, whith multiple non-obvious and misleading methods present near that point, so that it would likely be useful to others out there.
Manifest.classType(Class.forName(className))