I'm currently working on a A* implementation in Scala. To accomplish a clean structure I would like to use a nested case class structure which implements a self-bounded trait. However, I experience some issues when implementing this in the Scala IDE. The following code will not compile:
trait A[T <: A[T]]
class B {
case class C(int: Int) extends A[C] // A[this.C] won't work either
def make = C(5)
}
object D {
def foo[T <: A[T]](some: T) = {}
val c = new B().make
foo(c) // this does not compile
}
Is there any way I can make this structure work?
Not sure why you want this, but here's why it won't work as is:
The type of D.c is B#C. It is a path-dependent type where we don't know what instance of B it belongs to. However, C extends A[C], which is the already the same as saying A[this.C] in that context, which is bound to a specific instance of B. foo sees the type parameter T as B#C, which is not the same as b.C for some b.
You have two options to make this compile.
Relax the constraints of A to B#C:
trait A[T <: A[T]]
class B {
case class C(int: Int) extends A[B#C]
def make = C(5)
}
object D {
def foo[T <: A[T]](some: A[T]) = {}
val c = new B().make
foo(c)
}
Or handle the path-dependent type, so that c has type b.C:
trait A[T <: A[T]]
class B {
case class C(int: Int) extends A[C]
def make = C(5)
}
object D {
def foo[T <: A[T]](some: A[T]) = {}
val b = new B
val c: b.C = b.make
foo(c)
}
Related
Let's say I have some trait:
trait A[T] { def foo: T }
A class which extends it:
class B[T](t: T) extends A[T] { def foo = t }
And a subtrait of the parent trait:
trait C[T] extends A[T]
I want to mix C in with B.
val foo = new B("foo") with C[String]
This works fine, but I'd rather not need to specify the type parameter again, since B is already of type A[String]. However, I recognize Scala doesn't support the following:
val foo = new B("foo") with C
My question is where there's some other mechanism in the type system to support not having to specify the type parameters when C is mixed in. What I was thinking of was something as follows:
trait C {
self: A[T] => ...
}
One would think this kind of thing would fix what C could be mixed into. However, it isn't valid Scala. Something like:
trait C {
type T
self: A[T] =>
}
does not work either.
You can do this using an abstract type:
trait A {
type AT
def foo: AT
}
class B[T](t: T) extends A {
type AT = T
def foo = t
}
trait C extends A
val foo = new B("foo") with C
The definition is a bit more verbose, but your requirement of not having to type T again is satisfied.
How about this:
scala> trait C {
| self: A[_] =>
| }
defined trait C
scala> val foo = new B("foo") with C
foo: B[String] with C = $anon$1#f2df380
scala> foo.foo
res16: String = foo
Basicaly this is what I am trying to do.
A trait that has a member and another trait that inherits that member and initialize it.
Then a class that takes a generic type that must be inherited from the first trait and accesses that member
object main extends App{
val z = new c[b]()
z.p()
}
trait a{
val x : String
}
trait b extends a {
val x = 1
}
class c [A <: a] {
self: A =>
def p(): Unit ={
print(x)
}
}
but in the line
val z = new c[b]()
c[b] is underlined and the compiler complains that
"Illegal inheritance, self-type c[b] does not conform to A"
I want to define multiple traits that inherit from a father trait and then define a class that takes one of the fathers child traits and accesses its values
I found the answer, I simply had to extend the object while creating it, like this:
object main extends App{
val z = new c[b] with b
z.p()
}
trait a{
val x : String
}
trait b extends a {
val x = "1"
}
class c[A <: a]{
this: A =>
def p(): Unit ={
print(x)
}
}
if I have an ADT and a type class, is there a way for me to ensure at compile time that there is an instance of the type class for every subtype of the ADT?
Just to give an example - I'd really like this to not compile as there isn't an instance of A for Baz
sealed trait Foo
final case class Bar(s: String) extends Foo
final case class Baz(i: Int) extends Foo
trait A[T <: Foo] {
type O
def f(t: T): O
}
implicit val barA = new A[Bar] {
type O = String
def f(t: Bar): O = t.s
}
This is all my own code, so I'm happy to change the encoding of Foo if required (maybe a shapeless coproduct can help me out here?)
EDIT
Sorry, should have mentioned - I have a function a bit like this I'd like to implement (lets assume my instances are in an object I've imported and they are the only implementations in scope)
def g[T <: Foo](fs: List[T])(implicit a: A[T]): List[a.O] = fs.map(a.f(_))
From the comments below, it looks like I should also have said that the thing that calls g can do so with a List of any subclass of Foo (I have no control over that part other than to change g I guess). Here, I'm trying to ensure that if someone changes Foo later on, then there will be a compiler error letting the user know that they need to implement an appropriate A
You can use F-bounded polymorphism (aka Curiously Recurrent Template Pattern):
sealed abstract class Foo[Self <: Foo](implicit val hasA: A[Self])
final case class Bar(s: String) extends Foo[Bar]
final case class Baz(i: Int) extends Foo[Baz]
abstract class is used instead of trait so the implicit is picked up automatically.
However, for this specific A and g, you may not really need a type class:
sealed trait Foo[O] {
def f(): O
}
final case class Bar(s: String) extends Foo[String] {
def f() = s
}
def g(fs: List[Foo[O]]): List[O] = fs.map(_.f())
trait Foo[T] {
this: ImplementThis[T] =>
}
case class Bar() extends Foo[String] with ImplementThis[String] {
override def f(t: String): String = {
t
}
}
case class Baz() extends Foo[Int] with ImplementThis[Int] {
override def f(t: Int): Int = {
t
}
}
trait ImplementThis[T] {
type O
def f(t: T): O
}
Try something like this. This will enforce implementation of def f(t: T):O for any subclass of Foo that's defined.
def g[T <: Foo](fs: List[T])(implicit a: A[T]): List[a.O] = fs.map(a.f(_))
From this, I assume you want all the child classes of your Foo to have a def f so that they dont fail at runtime. I think my above suggestion will enforce that def f implementation and solve this problem.
I need overriding implicit in object res defing one from trait. The purpose is to define custom implicits in one place (trait B). Trait a is defined in external library. Is it possible?
trait t {
}
object m extends t
object q extends t
trait a {
implicit val o: t = m
}
trait b {
implicit val o: t = q
}
trait c {
def action(implicit v: t): Unit = {}
}
object res extends c with a with b {
//i need smth like override val o = super[b].o
val ololo= action
}
It is not possible to mix-in two unrelated traits that both contain a member with the same identifier. The Scala compiler has no way to resolve which one would take precedence in this scenario. Since types A and B are related, o does not even need to have the same type in both of them. Trait B needs to extend A and override o. There isn't any other way to override a member without using inheritance.
trait T
case object M extends T
case object Q extends T
trait A {
implicit val o: T = M
}
trait B extends A {
override implicit val o: T = Q
}
trait C {
def action(implicit v: T): Unit = println(v)
}
object Res extends C with B {
def call() = action
}
scala> Res.call()
Q
Since you are already mixing A into Res anyway, it is assumed that A is not difficult to extend, since Res must implement any other unmentioned abstract members.
I'm very new to Scala programming, and I really like the degree to which code is composable. I wanted to write some traits that deal with two related objects that are convertible to each other, and build more functionality by continuing to extend that trait so that when I create objects I can specify the related types for my generics. Here is a working toy example of the type of code I'm talking about:
trait FirstConverter[First] {
def toFirst: First
}
trait SecondConverter[Second] {
def toSecond: Second
}
trait TwoWayConverter[First <: SecondConverter[Second], Second <: FirstConverter[First]] {
def firstToSecond(x: First) = x.toSecond
def secondToFirst(x: Second) = x.toFirst
}
trait RoundTripConverter[First <: SecondConverter[Second], Second <: FirstConverter[First]] extends TwoWayConverter[First, Second] {
def firstToFirst(x: First) = secondToFirst(firstToSecond(x))
def secondToSecond(x: Second) = firstToSecond(secondToFirst(x))
}
case class A(s: String) extends SecondConverter[B] {
def toSecond: B = B((s.toInt) + 1)
}
case class B(i: Int) extends FirstConverter[A] {
def toFirst: A = A((i * 2).toString)
}
object ABConverter extends RoundTripConverter[A, B]
object Main {
def main(args: Array[String]): Unit = {
println(ABConverter firstToSecond A("10")) // 11
println(ABConverter secondToFirst B(42)) // 84
println(ABConverter firstToFirst A("1")) // 4
println(ABConverter secondToSecond B(2)) // 5
}
}
While this works, I'm not sure if it's idiomatic Scala. I'm asking if there are any tricks to make the type definitions more concise and if I can somehow define the type restrictions only once and have them used by multiple traits which extend other traits.
Thanks in advance!
One way to improve your design would be to use a type class instead of inheriting from FirstConverter and SecondConverter. That way you could use multiple conversion functions for the same types and convert between classes you don't control yourself.
One way would be to create a type class which can convert an A into a B :
trait Converter[A, B] {
def convert(a: A): B
}
trait TwoWayConverter[A, B] {
def firstToSecond(a: A)(implicit conv: Converter[A, B]): B = conv.convert(a)
def secondToFirst(b: B)(implicit conv: Converter[B, A]): A = conv.convert(b)
}
trait RoundTripConverter[A, B] extends TwoWayConverter[A, B] {
def firstToFirst(a: A)(implicit convAB: Converter[A, B], convBA: Converter[B, A]) =
secondToFirst(firstToSecond(a))
def secondToSecond(b: B)(implicit convAB: Converter[A, B], convBA: Converter[B, A]) =
firstToSecond(secondToFirst(b))
}
We could create type class instances for the following two classes Foo and Bar similar to your A and B
case class Foo(s: String)
case class Bar(i: Int)
implicit val convFooBarFoor = new Converter[Foo, Bar] {
def convert(foo: Foo) = Bar((foo.s toInt) + 1)
}
implicit val convBarFoo = new Converter[Bar, Foo] {
def convert(bar: Bar) = Foo((bar.i * 2) toString)
}
We then could create a FooBarConverter :
object FooBarConverter extends RoundTripConverter[Foo, Bar]
FooBarConverter firstToSecond Foo("10") // Bar(11)
FooBarConverter secondToFirst Bar(42) // Foo(84)
FooBarConverter firstToFirst Foo("1") // Foo(4)
FooBarConverter secondToSecond Bar(2) // Bar(5)
The only problem is because we can not pass parameters to a trait, we can not limit the types to types with a Converter type class instance. So you can create the StringIntConverter below even if no Converter[String, Int] and/or Convert[Int, String] instances exist.
object StringIntConverter extends TwoWayConverter[String, Int]
You cannot call StringIntConverter.firstToSecond("a") because the firstToSecond method needs the implicit evidence of the two mentioned type class instances.