Scala passing in traits as parameters to be mixed in - scala

I have (for lack of a better term) a factory method that encapsulates constructing an object:
def createMyObject = new SomeClass(a, b, c, d)
Now, depending on the context, I will need to mix in one or more traits into SomeClass:
new SomeClass with Mixin1
or
new SomeClass with Mixin2 with Mixin3
Instead of creating multiple separate factory methods for each "type" of instantiation, how can I pass in the traits to be mixed in so that it can be done with a single method? Or perhaps there is a good pattern for this that is structured differently?
I'd like to maintain the encapsulation so I'd rather not have each consumer just create the class on its own.

If you need only mixins without method overriding, you can just use type classes:
trait Marker
class C[+T <: Marker] { def b = 1 }
trait Marker1 extends Marker
implicit class I1[T <: Marker1](c: C[T]) {def a = 6 + c.b}
trait Marker2 extends Marker
implicit class I2[T <: Marker2](c: C[T]) {def a = 5 + c.b}
trait Marker3 extends Marker
implicit class I3[T <: Marker3](c: C[T]) {def k = 100}
trait Marker4 extends Marker3
implicit class I4[T <: Marker4](c: C[T]) {def z = c.k + 100} //marker3's `k` is visible here
scala> def create[T <: Marker] = new C[T]
create: [T <: Marker]=> C[T]
scala> val o = create[Marker1 with Marker3]
o: C[Marker1 with Marker3] = C#51607207
scala> o.a
res56: Int = 7
scala> o.k
res57: Int = 100
scala> create[Marker4].z
res85: Int = 200
But it won't work for create[Marker1 with Marker2].a (ambiguous implicits), so no linearization here. But if you want to just mix-in some methods (like in javascript's prototypes) and maybe inject something - seems to be fine. You can also combine it with traditional linearized mix-in by adding some traits to C, I1, I2, etc.

You can instantiate the class differently depending on the context.
def createMyObject =
if (context.foo)
new SomeClass
else
new SomeClass with Mixin1
However, if the consumers are the ones that know the traits that are supposed to be mixed in, then why wouldn't you just instantiate things there?

Related

Question about Scala implicits with multiple type parameters

I am having a hard time understanding an error related to "could not find value for implicits" error. Here is a minimal example to highlight the error.
sealed trait BehaviourA
final case object A1 extends BehaviourA
final case object A2 extends BehaviourA
sealed trait BehaviourB
final case object B1 extends BehaviourB
final case object B2 extends BehaviourB
trait factory[O<:BehaviourA, R<:BehaviourB]{ ... }
// Define an implicit value for each combination of the two behaviours
object factory {
implicit val behaviour1 = new factory[A1, B1] { ... }
... (one for each Ai, Bj)
}
object genElement {
import factory._
def apply[O <: BehaviourA, R<:BehaviourB](...)(implicit c: factory[O, R])
}
When I try to call it from another method, however, it complains about no value found for implicit c in the genExample.
def callerMtd[T<:BehaviourA](){
genElement[T, B1](...)
}
or
def callerMtd[T<:BehaviourA, R<:BehaviourB](){
genElement[T, R](...)
}
If I call them directly like below, it is fine. Why can't I use type parameters in the caller method?
def callerMtd(){
genElement[A1, B2](...)
}
Even though the types are sealed and seemingly you provided all type class instances
(one for each Ai, Bj)
this does not cover all the possible cases specified by type bounds in
def callerMtd[T <: BehaviourA, R <: BehaviourB]
For example here are types that fit the bounds and yet you probably did not provide an instance for them
callerMtd[A1.type with A2.type, B1.type with B2.type]
For compiler to be sure it can summon an instance for factory[T, R] where T <: BehaviourA and R <: BehaviourB you would have to instruct it how to generate it with corresponding implicit def
implicit def foo[T <: BehaviourA, R <: BehaviourB]

Scalaz instancing typeclass and case class

This problem is pretty hard to explain. I try to implement a kind of Arrow, call it MyArr, which extends the Arrow trait from scalaz. However, MyArr is also a kind of Algbraic Data Type, so I make a few case classes out of if, and wrote down code like this(minimal example):
package org.timeless
import scalaz._
import Scalaz._
import std.option._, std.list._
sealed trait MyArr[A,B] extends Arrow[MyArr] {
def id[A]: MyArr[A,A] = SId()
def compose[A,B,C](s1: MyArr[B,C], s2: MyArr[A,B]): MyArr[A,C] =
SRight(s2, s1)
def arr[A,B](f: A=>B): MyArr[A,B] = SPure(f)
def first[A,B,C](s: MyArr[A,B]): MyArr[(A,C),(B,C)] = SPar(s, SId())
}
case class SId[A] () extends MyArr[A,A]()
case class SRight[M[_],A,B,C](s1: MyArr[A,B], s2: MyArr[B,C]) extends MyArr[A,C]
case class SPure[A,B](f: A=>B) extends MyArr[A,B]
case class SPar[M[_],A,B,C,D](s1: MyArr[A,B], s2: MyArr[C,D]) extends MyArr[(A,C),(B,D)]
object MyArr {
val b = SId[Int]()
val c = SId[Int]()
// val a: MyArr[Int,Int] = id[Int] // Error
// val d = c compose b // Error
// val d = b >>> c // Error
val d = b >>> (b,c) // ??? Arguments
}
As easily seen, the id function is actually the constructor of SId, etc. The classes themselves compile fine, but I don't see any way to actually use it as an Arrow. I actually came from Haskell programming, so I might be doing it totally wrong, but equivalent code in Haskell should be like this(with GADTs):
data MyArr a b where
SId :: MyArr a b
SRight :: MyArr a b -> MyArr b c -> MyArr a c
SPure :: (a -> b) -> MyArr a b
SPar :: MyArr a b -> MyArr c d -> MyArr (a,c) (b,d)
instance Category MyArr where
id = SId
(.) = SRight
instance Arrow MyArr where
arr = SPure
first s = SPar s SId
Typeclasses in Scala
Typeclasses in Scala are not built into the language like in Haskell. They are just a design pattern and are usually implemented with the help of implicit arguments:
def pure[M[_], T](
implicit monad: Monad[M] // Fetching a monad instance for type M
): M[T] =
monad.pure[T] // Using methods of the monad instance
You don't have to extend the typeclass trait to provide a typeclass instance for some ADT. The typeclass instance has to be defined somewhere as an implicit val, implicit def, implicit object, etc. Then you can import the relevant instance into scope before using it.
There is also a way to supply the typeclass instance automatically, without having to import it explicitly. To do that the instance should be declared in the companion object of either the typeclass class/trait or ADT class/trait, or one of their parent classes/traits; or in a package object in which one of those is defined. You can read more on the topic of implicit resolution in this answer: Where does Scala look for implicits?
Defining a typeclass instance
So to get back to your problem, you can define your ADT like this:
sealed trait MyArr[A,B]
case class SId[A] () extends MyArr[A,A]()
case class SRight[M[_],A,B,C](s1: MyArr[A,B], s2: MyArr[B,C]) extends MyArr[A,C]
case class SPure[A,B](f: A=>B) extends MyArr[A,B]
case class SPar[M[_],A,B,C,D](s1: MyArr[A,B], s2: MyArr[C,D]) extends MyArr[(A,C),(B,D)]
And provide the Arrow instance in the companion object of MyArr:
object MyArr {
implicit val arrow: Arrow[MyArr] = new Arrow[MyArr] {
def id[A]: MyArr[A,A] = SId()
def compose[A,B,C](s1: MyArr[B,C], s2: MyArr[A,B]): MyArr[A,C] =
SRight(s2, s1)
def arr[A,B](f: A=>B): MyArr[A,B] = SPure(f)
def first[A,B,C](s: MyArr[A,B]): MyArr[(A,C),(B,C)] = SPar(s, SId())
}
def apply[T]: MyArr[T, T] = arrow.id[T]
}
Using the typeclass instance
I believe it's not possible to provide a generic id function (or return, pure, etc.) in Scala due to some limitations of Scala's type inference.
Instead you can use the MyArr.apply method defined above:
val a: MyArr[Int,Int] = MyArr[Int]
As the ADT doesn't extend the typeclass, it doesn't inherit its methods like compose or >>>. They can be provided separately using the 'Pimp My Library' pattern.
Indeed, the >>> method in scalaz comes from the ComposeOps class, which is defined like this:
final class ComposeOps[F[_, _],A, B] private[syntax]
(self: F[A, B])
(val F: Compose[F])
extends Ops[F[A, B]]
And there is an implicit conversion defined from some type F[_, _] to this class ComposeOps, if there as a Compose instance available for F:
implicit def ToComposeOps[F[_, _],A, B](v: F[A, B])(implicit F0: Compose[F])
This conversion is imported with import Scalaz._, and that's why this line works now:
val d = b >>> c
But there is no extension in scalaz that provides a compose method on ADTs with an Arrow instance, so this line still gives an error:
val e = c compose b
To make it work, you can provide an extension yourself. A simple example could look like this:
// implicit class is equivalent to a normal class
// with an implicit conversion to this class
implicit class ArrowOps[T[_, _], A, B](f: T[A, B])(implicit arrow: Arrow[T]) {
def compose[C](g: T[C, A]): T[C, B] = arrow.compose(f, g)
}

Context bounds for generic polymorphic data in collection

I have the simplified situation:
abstract sealed trait Top
class A[T] extends Top
class B[T] extends Top
class Typeclass[T]
implicit def a[T] = new Typeclass[A[T]]
implicit def b[T] = new Typeclass[B[T]]
Now I have a Map[String, Top] and want to use an operation on all values in the map that require the presence of an instance of Typeclass to be available in the context. This will not compile as the concrete types of the values in the map are not visible from its type and I can therefore not set a context bound for them.
Is there a way to tell the compiler that in fact there will always be an instance available? In this example this is given as there are implicit functions to generate those instances for every concrete subtype of Top.
Or is the only solution to use a HList and recurse over its type requiring all the instances to be in context?
I recommend using some variation on this adaptation of Oleg's Existentials as universals in this sort of situation ... pack the the type class instance along with the value it's the instance for,
abstract sealed trait Top
class A[T] extends Top
class B[T] extends Top
class Typeclass[T]
implicit def a[T] = new Typeclass[A[T]]
implicit def b[T] = new Typeclass[B[T]]
trait Pack {
type T <: Top
val top: T
implicit val tc: Typeclass[T]
}
object Pack {
def apply[T0 <: Top](t0: T0)(implicit tc0: Typeclass[T0]): Pack =
new Pack { type T = T0 ; val top = t0 ; val tc = tc0 }
}
val m = Map("a" -> Pack(new A[Int]), "b" -> Pack(new B[Double]))
def foo[T: Typeclass](t: T): Unit = ()
def bar(m: Map[String, Pack], k: String): Unit =
m.get(k).map { pack =>
import pack._ // imports T, top and implicit tc
foo(top) // instance available for call of foo
}
bar(m, "a")
As discussed in comment it would be more convenient to have the typeclass defined on Top, and it might be done with pattern matching.
supposing part of the definition of the typeclass is
def f[T](t: T): FResult[T],
and you have the corresponding implentations
def fOnA[T](t: A[T]): FResult[A[T]] = ...
def fOnB[T](t: B[T]): FResult[B[T]] = ...
Then you can define
def fOnT(t: Top) : FResult[Top] = t match {
case a: A[_] => fOnA(a)
// provided an FResult[A[T]] is an FResult[Top],
// or some conversion is possible
case b: B[_] => fOnB(b)
}
If is both legal and safe to call a generic method, such as fOnA[T] with an existential (a matching A[_])
However, it might be difficult to convince the compiler that the parameter you pass to f or the result you get are ok, given the reduced information of the existential. If so, please post the signatures you need.

Scala Implicit Ordering

Is there a way for me to define the same implicit ordering for two different classes?
I tried to do something along the following lines but it doesn't detect the ordering.
abstract class Common
case class A extends Common
case class B extends Common
implicit val KeyOrdering = new Ordering[Common] {
override def compare(x: Common, y: Common): Int = {
x.toString.compareTo(y.toString)
}
}
As noted by #ntn, the inferred type of your list - the least upper bound of its two elements - is Product with Serializable with Common. As scala.Ordering is not contravariant on its type parameter, implicit resolution fails because it does not hold that Ordering[Common] <: Ordering[Product with Serializable with Common].
You can work around this by writing the implicit ordering so that it always has the exact type of the implicit parameter under consideration:
abstract class Common
case class A() extends Common
case class B() extends Common
object Common {
implicit def ordering[A <: Common]: Ordering[A] = new Ordering[A] {
override def compare(x: A, y: A): Int = {
x.toString.compareTo(y.toString)
}
}
}
Or for concision:
object Common {
implicit def ordering[A <: Common]: Ordering[A] = Ordering.by(_.toString)
}
If you remove the case class for A and B (or even only for one of them), then it works.
For List(A(), B()).sorted, it fails to find an Ordering for Product with Serializable with C, as the base class for A and B is Product with C (due to A and B being both case classes).
If you are creating a list with elements of two different base types, I assume you want a list of type List[C], in which you can declare the elements before using them (or get them from some function which returns type C.
val a: C = A()
val b: C = B()
List(a,b).sorted

Why is this an invalid use of Scala's abstract types?

I have this code:
class A extends Testable { type Self <: A }
class B extends A { type Self <: B }
trait Testable {
type Self
def test[T <: Self] = {}
}
object Main {
val h = new A
// this throws an error
h.test[B]
}
And my error is:
error: type arguments [B] do not conform to method test's type parameter bounds [T <: Main.h.Self]
h.test[B]
On this question, it was said that this was due to path dependent types. Can anyone figure out how to have T <: Self, without having the path-dependent types problem?
Any help would be appreciated.
Your code need to be looks like:
// --- fictional scala syntax ---
class A extends Testable { type Self = A }
class B extends A { override type Self = B }
But it is imposible in current version of scala.
I would propose little bit long way (not longer than using path dependent types but another), and it conforms your requirements.
a) Use Type-class pattern for test method;
b) Use implicit parameters for conforms type relations.
Class hierarchy:
trait Testable
class A extends Testable
class B extends A
Conforms trait:
trait Conforms[X, Y]
Testable Type-class:
object TestableTypeClass {
implicit def testMethod[T <: Testable](testable : T) = new {
def test[X](implicit ev : Conforms[X, T]) = {}
}
}
test method type parameter conditions in companion objects:
object A {
// P <: A is your conditon (Self <: A) for class A
implicit def r[P <: A] = new Conforms[P , A] {}
}
object B {
// P <: B is your conditon (Self <: B) for class B
implicit def r[P <: B] = new Conforms[P , B] {}
}
Tests:
import TestableTypeClass._
val a = new A
a.test[A] // - Ok
a.test[B] // - Ok
val b = new B
// b.test[A] // - did not compile
b.test[B] // - Ok
UPDATE:
1) It is possible to collect all implicits in one object, and in this case object with implicits need to import (it is not needed before by rules of implicit scope in companion object):
object ImplicitContainer {
implicit def r1[P <: A] = new Conforms[P , A] {}
implicit def r2[P <: B] = new Conforms[P , B] {}
}
and using:
import TestableTypeClass._
import ImplicitContainer._
val a = new A
a.test[A]
a.test[B]
2,3) trait Conforms defined for 2 type parameter X & Y
X - used for future type constraint (and this constraint come from parametric method)
Y - used for determine the type for which will be define type constraint
implicit parameter choise by Comforms instance type, and idea of this design is playing with combinations X & Y
in Type-class TestableTypeClass type Y captured by implicit conversion from Testable to anonimous class with test method, and type X captured in test method call.
And a main feature is invariance of Conforms trait, this is why implicits is not ambiguous and correctly manage bound rules.
And for better understanding, one more example with more strict rules:
//...
class C extends B
object ImplicitContainer {
implicit def r1[P <: A] = new Conforms[P , A] {}
implicit def r2[P](implicit ev : P =:= B) = new Conforms[P , B] {}
implicit def r3[P <: C] = new Conforms[P , C] {}
}
import TestableTypeClass._
import ImplicitContainer._
val b = new B
//b.test[A] // - did not compile
b.test[B] // - Ok
//b.test[C] // - did not compile
I think what you are trying to achieve is something like this:
//this is of course not a correct Scala code
def test[T <: upperBoundOf[Self]]
But this doesn't make sense. Why? Because you can very easily circumvent such constraint, effectively rendering it pointless:
val h = new B
h.test[A] //nope, A is not a subtype of B
but...
val h: A = new B
h.test[A] //same thing, but this time it's apparently OK
Not only the constraint provides zero additional type safety, I think it also leads to breakage one of the most fundamental rules of OOP - the Liskov Substitution Principle. The snippet above compiles when h is of type A but does not compile when h is of type B even though it's a subtype of A, so everything should be fine according to the LSP.
So, essentially if you just leave your types like this:
class A extends Testable
class B extends A
trait Testable {
def test[T <: A]
}
you have exactly the same level of type safety.