Best way to declare a typeclass having a superclass

58 views
Skip to first unread message

Julien Richard-Foy

unread,
May 17, 2013, 11:24:26 AM5/17/13
to scala...@googlegroups.com
I Haskell you can declare a typeclass Bar having a “superclass” Foo as follows:

class Foo a => Bar a


What is the best way to model this kind of relationship in Scala?

We could use inheritance (as it is done in scalaz, IIRC):

trait Foo[A]
trait Bar[A] extends Foo[A]

But to implement Bar you also would have to implement Foo’s members…

Instead we’d like to reuse any available Foo implementation, maybe something like:

class Bar[A : Foo]

But then Foo wouldn’t be a superclass of Bar, the following wouldn’t compile:

def f[A : Bar](a: A) = g(a)
def g[A : Foo](a: A) = a

I tried by defining an implicit conversion from Bar to Foo in Bar’s companion object but that doesn’t work either. Even if we explicitly import the conversion.

Any other idea?

Alec Zorab

unread,
May 17, 2013, 11:52:22 AM5/17/13
to Julien Richard-Foy, scala-user
trait Foo[A]

trait Bar[A] {
  this: Foo[A] =>
  
}

Does the trick, through you can't do runtime mixins without some fairly horrible hacks.


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Vlad Patryshev

unread,
May 17, 2013, 12:57:10 PM5/17/13
to Julien Richard-Foy, scala-user
If you are interested in just specifying that your type should be a subtype of another type, then what Alec suggested should be what you need.

If you use type class pattern, something like this might work:

trait Functor[F[_]

<:java.util.List[_]

] {

 def map[X,Y](f: X => Y): F[X] => F[Y]

}

implicit object JAL_a_Functor extends Functor[ArrayList] {

 def map[X,Y](f: X => Y) = (xs: ArrayList[X]) => {/*...*/}

}

implicit def fops[F[_]<:java.util.List[_]: Functor, A](fa: F[A]) = new {

 val functor = implicitly[Functor[F]]

 final def map[B](f:A=>B):F[B] = functor.map(f)(fa)

}  


etc

Thanks,
-Vlad


--

Lars Hupel

unread,
May 18, 2013, 6:34:45 AM5/18/13
to scala...@googlegroups.com
> I tried by defining an implicit conversion from Bar to Foo in Bar�s
> companion object but that doesn�t work either. Even if we explicitly import
> the conversion.

The problem is the implicit *conversion*. Try this (note that the
parameter of the implicit is itself implicit):

trait Foo[A]
object Foo {
implicit def fromBar[A](implicit bar: Bar[A]) = bar.foo
}

trait Bar[A] {
def foo: Foo[A]
}

// usage

def f[A : Bar](a: A) = g(a)
def g[A : Foo](a: A) = a

Putting `fromBar` into `Bar`s companion object won't work, because when
calling `g`, the compiler doesn't look inside that object (by default).
Importing would work, though.

> We could use inheritance (as it is done in scalaz, IIRC):
>
> trait Foo[A]
> trait Bar[A] extends Foo[A]
>
> But to implement Bar you also would have to implement Foo�s members�

Do you control `Foo` and `Bar` in your own code? If so, I strongly
suggest going with the inheritance approach. It makes your life much easier.

If you really have the situation that you can't modify a `Foo` instance,
you can still have `Bar` extending `Foo`, and do something like this:

object Bar {
trait FromFoo[A] {
def foo: Foo[A]

// implement proxy methods to `foo`
def frobnicate = foo.frobnicate
// ...
}
}

and then you can write:

implicit object IntIsBar extends FromFoo[Int] {

// only implement `Bar` methods

}

yves

unread,
May 18, 2013, 7:52:54 AM5/18/13
to scala...@googlegroups.com
Not sure I understand the question.

Depending on the context, I might use the previous answers,or also use abstract types :

type Foo
type Bar <: Foo

You can even go as far as writing

type Bar <% Foo

which mean that there is a way to implicitely convert Bar to Foo ; it may be by standard inheritance,or by an implicit method.

At this stage,you've just said there will at some time exist a class Bar and a class Foo,and that Bar will extend (or be convertible to) Foo.

How you will later fill up that requirement is undefined at that point (can be classic inheritance, trait mixin, implicit conversion...)

Then, there is no best way. There is no such hierarchy of good or bad ways.
There are several ways to achieve the same thing, which then lead to different ways of coding and using your classes.
You have to make the decision by estimating which solution suits better your situation.

Yves

Julien Richard-Foy

unread,
May 19, 2013, 9:50:01 AM5/19/13
to scala...@googlegroups.com
Thanks for your answers!
Reply all
Reply to author
Forward
0 new messages