I have a Lift project with mixed Java-Scala code. The project has a JPA backend written in Java with EclipseLink, which is accessed by the Scala side, which uses Lift and Lift-NG.
On the Java side, I have the following relevant interfaces:
interface IEntity
interface IDAO<T extends IEntity> {
void persist(T t);
}
On the Scala side, I have the following:
abstract class Binding[T <: IEntity] extends NgModel {
def unbind: T
}
class BasicService[B <: Binding[_ <: IEntity]](serviceName: String, dataAccessObject: IDAO[_ <: IEntity]) {
def persist(binding : B): Unit = {
val entity = binding.unbind
dataAccessObject.persist(entity)
}
}
The purpose of this hierarchy is to let me create Service instances which handle a given Binding for entity E, which can also receive and use an appropriate DAO created to handle type E. For example:
// Java side
class Todo implements IEntity
class TodoManager implements IDAO<Todo>
// Scala side
case class TodoBinding extends Binding[Todo] {
override def unbind: Todo = new Todo()
}
object HelloWorld extends BasicService[TodoBinding]("todoService", new TodoManager)
My problem is a compilation error that occurs inside the persist method of BasicService. On the last line, I get this:
Type mismatch: expected _$1, actual: IEntity
As I am a bit inexperienced with Scala, I might be missing something very obvious with the type system, but I genuinely cannot figure this out. How can I work around this error?
Your definition of BasicService does not require that the type argument of B:
B <: Binding[_ <: IEntity]
is compatible with the type argument of dataAccessObject:
dataAccessObject: IDAO[_ <: IEntity]
What if one is Binding[FooEntity] and the other is IDAO[BarEntity]?
You should take that type variable E that you say you are trying to use, and actually define it:
class BasicService[E <: IEntity, B <: Binding[E]]
(serviceName: String, dataAccessObject: IDAO[E])
Also note that in the example code you posted, the type variable B to BasicService might not be necessary, because you only use it to receive the argument binding to persist(). You could have simply used the type Binding[E] there:
class BasicService[E <: IEntity]
(serviceName: String, dataAccessObject: IDAO[E]) {
def persist(binding: Binding[E]): Unit = // ...
}
Related
I'm new to Scala and new to higher kinded types. I want to write something like this;
trait Actor[E[Dependency] <: Event[Dependency]] {
def execute(dependency: Dependency): Unit
}
However I can't refer to the type parameter Dependency in the execute method - the compiler doesn't know it.
I'm aware I can solve it in the following way without HKTs, but this isn't what this question is about;
trait Actor[T <: Event[Dependency], Dependency] {
def execute(dependency: Dependency): Unit
}
I'd like to understand why it doesn't work with the higher kinded type syntax that I've tried? Is it possible at all to express this with HKTs? Is this a valid use-case for a HKT?
EDIT
A bit more information, Event looks like this;
trait Event[Data] {
val payload: Data
}
...and I'm looking to define an event and an actor like this;
case class FooEvent(payload: Foo) extends Event[Foo]
class FooActor extends Actor[FooEvent] {
def execute(dependency: Foo) = {}
}
I will try to improve Alexey's answer - he is right, but he is too short. But I must say that I'm not an expert in HKT and I think I'm only starting to understand the concept.
In your code E[Dependency] is the same as E[_] which says that you have E with some type as parameter. This means that you do not operate over Dependency as type. You also do not operate over E or E[Dependency] as the type either. E is a type constructor, and E[Dependency] is an existential type if I understood it correctly. Please note that
trait Actor[E[D] <: Event[D]] { def execute(d: E) {} }
or
trait Actor[E[D] <: Event[D]] { def execute(d: E[D]) {} }
won't compile either.
You need to specify the proper type as an argument for execute:
trait Actor[E[D] <: Event[D]] { def execute[B](d: E[B]) {} }
This one will compile as E[B] is the type in this context.
Updated:
Please take a look at this code:
trait Event[P] {
val payload: P
}
case class FooEvent(payload: Int) extends Event[Int]
trait BaseActor {
type E = Event[P]
type P
def execute(dep: P)
def runEvent(event: E)
}
trait IntActor extends BaseActor {
type P = Int
}
class FooActor extends IntActor {
def execute(dependency: P) = {}
def runEvent(event: E) = {}
}
val c = new FooActor()
c.runEvent(FooEvent(5))
c.execute(5)
Basically the trick is to define type P which is our Dependency and type E = Event[P] which is always Event[Dependency] then you can use the actor by defining P without defining E as it is already defined. Not sure whether it solves the issue, but it looks like a way to go to me. There are also too many types here, some like IntActor is not necessary. I've put them so it is easier to understand the example
However I can't refer to the type parameter Dependency in the execute method - the compiler doesn't know it.
You can't because it isn't a parameter of Actor. Consider
val actor = new Actor[Event] // E is Event
actor.execute(???) // what argument is this supposed to take? I.e. what is Dependency for Actor[Event]?
UPDATE: Given your edit, the [Dependency, T <: Event[Dependency]] option is precisely what you need. When you write Actor[E[Dependency] <: Event[Dependency]], this means E itself has to have a type parameter. And FooEvent doesn't, so Actor[FooEvent] won't compile.
UPDATE 2: You could try using type members as follows:
trait Event {
type Dependency
val payload: Dependency
}
trait Actor {
type E <: Event
def execute(e: E#Dependency)
}
class Foo
case class FooEvent(payload: Foo) extends Event {
type Dependency = Foo
}
class FooActor extends Actor {
type E = FooEvent
def execute(e: Foo) = {}
}
I'm trying to implement a few structures from Okasaki's book in Scala, and in tests try to keep the actual tests in the base class, only using subclasses to provide the instance-under-test.
For example, a test for unbalanced (tree) set looks as follows:
class UnbalancedSetSpec
extends SetSpec(new UnbalancedSet[Int])
with IntElements
where
abstract class SetSpec[E, S](val set: Set[E, S]) extends Specification with ScalaCheck {
implicit def elements: Arbitrary[E]
// ...
private def setFrom(es: Seq[E]): S = es.foldRight(set.empty)(set.insert)
}
Now sometimes I want to specialise the child spec, e.g.
class RedBlackSetSpec
extends SetSpec(new RedBlackSet[Int])
with IntElements {
"fromOrdList" should {
"be balanced" ! prop { (a: List[Int]) =>
val s = RedBlackSet.fromOrdList(a.sorted)
set.isValid(s) should beTrue
}
}
}
it fails because there's no method isValid on Set[E, S] — it's defined in RedBlackSet[E]. But if I go ahead and change SetSpec[E, S](val set: Set[E, S]) to SetSpec[E, S, SES <: Set[E, S]](val set: SES), this particular problem disappears, but the code still fails to compile:
Error:(7, 11) inferred type arguments [Nothing,Nothing,okasaki.RedBlackSet[Int]] do not conform to class SetSpec's type parameter bounds [E,S,SES <: okasaki.Set[E,S]]
extends SetSpec(new RedBlackSet[Int])
^
Error:(7, 11) inferred type arguments [Nothing,Nothing,okasaki.UnbalancedSet[Int]] do not conform to class SetSpec's type parameter bounds [E,S,SES <: okasaki.Set[E,S]]
extends SetSpec(new UnbalancedSet[Int])
^
The definition of RedBlackSet is as follows:
package okasaki
class RedBlackSet[E](implicit ord: Ordering[E]) extends Set[E, RBTree[E]] {
so I would expect E to be inferred as Int rather than Nothing, and S as RBTree[Int] — but it doesn't happen.
class RedBlackSetSpec
extends SetSpec[Int, RedBlackSet.RBTree[Int], RedBlackSet[Int]](new RedBlackSet[Int])
with IntElements {
and
class UnbalancedSetSpec
extends SetSpec[Int, BinaryTree[Int], UnbalancedSet[Int]](new UnbalancedSet[Int])
with IntElements
work fine, but look ugly.
I'm struggling to understand why E and S are not inferred here. Any hints?
This is actually a well-known problem with Scala type inference: it can't infer SES "first" and use it to infer E and S. One solution comes to mind:
class RedBlackSetSpec(override val set: RedBlackSet[Int]) extends SetSpec(set) with IntElements {
def this() = this(new RedBlackSet[Int])
...
}
It becomes less ugly if you make set in SetSpec an abstract val instead of a constructor argument, but with a slight tradeoff in cases you don't need to specialize. I think there should be a better one, but this should work.
In Scala I want to return a instance of a class for a method defined in a trait which uses generics, the code example I have is this:
File 1
package packOne
import packTwo.A
trait MyTrait[T <: MyTrait[T <: A]] {
def otherFunct(): String
def funct[T <: A](): T
}
File 2
package packTwo
import packOne.MyTrait
abstract class A(someParameter: String) {}
class B(someParameter: String) extends A(someParameter) {}
object B extends MyTrait[B] { // <--- the B inside MyTrait here is the class not the object, or at least that is what I want
def otherFunct(): String = "Hello"
def funct[B](): C = new B("hi") // <--- I think here is the key
}
basically what I want is an interface that have method to return a concrete implementation of class A, in an implementing object (which happen to be a companion object for a class extending A).
Why do I want that to be on an object?, is because I want to call that method without the need of an instance (like an static method in java), so that I can call B.funct() and have an instance of B class kind of like a factory method, for other classes extending A for example a call to X.funct will return an instance of class X.
I have tried to remove the generic type from the function definition except on the return type of the function and just leave it in the trait definition (like def funct(): T) but that does not work either.
I am quite new to Scala so if you could explain it for dummies and avoid complex scala unique concepts I would appreciate
How about simply:
trait A
class B(someParameter: String) extends A
trait MyTrait[T <: A] {
def otherFunct: String //Parentheses on parameterless methods with no side effects and no serious computation are generally unidiomatic in Scala
def funct: T //Note, no generic parameter on this method
}
object B extends MyTrait[B] {
def otherFunct = "Hello"
def funct = new B("hi")
}
And then:
B.funct //returns a new `B`
The apply method is often used in this factory style (e.g. Seq.apply() which is equivalent to Seq())
I have some simple traits (Entity in the example below) that are extended by case classes in my app. I would like to create an EntityMapper trait that provides an interface for handling the case classes that extend the Entity trait (Foo in the example below). I thought I should be able to do this fairly easily using generics and bounding but I've spent a couple of hours on it already and I haven't gotten it to work correctly. The code below is what I think I should be able to do but it fails with a compiler error. The error is
Test.scala:15: error: value id is not a member of type parameter Foo \
println(e.id)
package experiment
trait Entity {
val id: Option[Long]
}
case class Foo(val id: Option[Long] = None) extends Entity
trait EntityMapper {
def create[E <: Entity](e: E): E
}
object FooMapper extends EntityMapper {
def create[Foo](e: Foo): Foo = {
println(e.id)
e
}
}
object Main extends App {
val foo = FooMapper.create(Foo(None))
}
I've tried several different things to solve the problem but nothing has worked. If I comment out the line in question "println(e.id)", it compiles but that is not useful because I cannot access or modify any of the properties of Foo.
I have tried using a covariant argument to the mapper trait and then supplying the type to the FooMapper object definition but that yields the same error. The code for that attempt is below:
trait EntityMapper[+Entity] {
def create[E <: Entity](e: E): E
}
object FooMapper extends EntityMapper[Foo] {
...
}
I have also tried achieving the same thing with simple inheritance but I cannot correctly restrict the type parameter in FooMapper to only take Foos, I have to make the method signature match the trait exactly which is why I started trying to implement it using generics with a type bound. The code for that attempt is below:
trait EntityMapper {
def create(e: Entity): Entity
}
object FooMapper extends EntityMapper {
def create(e: Foo): Foo = {
println(e.id)
e
}
}
The error code returned is:
Test.scala:13: error: object creation impossible, since method create in trait EntityMapper of type (e: experiment.Entity)experiment.Entity is not defined
(Note that experiment.Entity does not match experiment.Foo: class Foo in package experiment is a subclass of trait Entity in package experiment, but method parameter types must match exactly.)
object FooMapper extends EntityMapper {
^
Any help would be greatly appreciated. I'm using Scala version 2.10.3.
You can fix the error in a couple of ways
1.Specifying the generic type constraint on the trait.
trait EntityMapper[E <: Entity] {
def create(e: E): E
}
object FooMapper extends EntityMapper[Foo] {
def create(e: Foo): Foo = {
println(e.id)
e
}
}
2.Use parameterized types
trait EntityMapper {
type E <: Entity
def create(e: E): E
}
object FooMapper extends EntityMapper {
type E = Foo
def create(e: Foo): Foo = {
println(e.id)
e
}
}
Look at Scala: Abstract types vs generics to get some more background on the two approaches.
I have been working on an issue with implicit conversion for days now, but somehow I just cannot figure out what I am doing wrong. I read through all the other questions on SO that deal with implicits but I still don't understand what the problem is.
As an example, let's consider a Java interface like this(T extends Object for brevity):
public interface JPersistable<T extends Object> {
public T persist(T entity);
}
In scala, I do the following:
case class A()
case class B() extends A
case class C()
case class D() extends C
trait Persistable[DTOType <: A, EntityType <: C] {
// this would be implemented somewhere else
private def doPersist(source: EntityType): EntityType = source
// this does not implement the method from the Java interface
private def realPersist(source: DTOType)(implicit view: DTOType => EntityType): EntityType = doPersist(source)
// this DOES implement the method from the Java interface, however it throws:
// error: No implicit view available from DTOType => EntityType.
def persist(source: DTOType): EntityType = realPersist(source)
}
case class Persister() extends Persistable[B, D] with JPersistable[B]
object Mappings {
implicit def BToD(source: B): D = D()
}
object Test {
def main(args: Array[String]) {
import Mappings._
val persisted = Persister().persist(B())
}
}
As stated in the comment, I get an exception at compile time. I guess my questions are:
1) Why do I need to specify the implicit conversion on the doRealPersist explicitly? I expected the conversion to happen even if I do the following:
trait Persistable[DTOType <: A, EntityType <: C] {
// this would be implemented somewhere else
private def doPersist(source: EntityType): EntityType = source
def persist(source: DTOType): EntityType = doPersist(source)
}
However, this does not compile either.
2) Why does compilation fail at persist and not at the actual method call (val persisted = Persister().persist(B()))? That should be the first place where the actual type of EntityType and DTOType are known, right?
3) Is there a better way to do what I am trying to achieve? Again, this is not the actual thing I am trying to do, but close enough.
Apologies in advance if this question is ignorant and thanks a lot in advance for your help.
You need to make the conversion available within the trait. You can't pass it in from the outside implicitly because the outside doesn't know that persist secretly requires realPersist which requires an implicit conversion. This all fails even without considering JPersistable.
You can for example add
implicit def view: DTOType => EntityType
as a method in the trait and it will then compile. (You can drop realPersist then also.)
Then you need a way to get that view set. You can
case class Persister()(implicit val view: B => D) extends Persistable[B,D]
and then you're all good. (The implicit val satisfies the implicit def of the trait.)
But now you have bigger problems: your Java interface signature doesn't match your Scala signature. The equivalent Scala is
trait JPersistable[T <: Object] { def persist(t: T): T }
See how persist takes and returns the same type? And see how it does not in your Scala class? That's not going to work, nor should it! So you have to rethink exactly what you're trying to accomplish here. Maybe you just want to make the implicit conversion available--not pass it to the method!--and have Scala apply the implicit conversion for you so that you think you've got a persist that maps from DTOType to EntityType, but you really just have the EntityType to EntityType transform that the Java interface requires.
Edit: for example, here's a working version of what you posted just using standard implicit conversion:
trait JPer[T] { def persist(t: T): T }
class A
case class B() extends A
class C
case class D() extends C
trait Per[Y <: C] extends JPer[Y] {
private def doIt(y: Y): Y = y
def persist(y: Y) = doIt(y)
}
case class Perer() extends Per[D] // "with JPer" wouldn't add anything!
object Maps { implicit def BtoD(b: B): D = D() }
object Test extends App {
import Maps._
val persisted = Perer().persist(B())
}
Pay attention to which types are used where! (Who takes B and who takes D and which direction do you need a conversion?)