Kevin Meredith
Kevin Meredith

Reputation: 41909

Generic Method Implementing Two Traits

I'm trying to define a method - it accepts an A, which must be a sub-type of 2 traits.

scala> trait Foo
defined trait Foo

scala> trait Bar
defined trait Bar

scala> def f[A <: Foo, Bar](x: A) = x
f: [A <: Foo, Bar](x: A)A

scala> case class Bip extends Foo with Bar

scala> val bip = Bip()
bip: Bip = Bip()

// looks good
scala> f(bip)
res0: Bip = Bip()

// only extends `Foo`
scala> case object Fip extends Foo
defined module Fip

// I expected a compile-time error
scala> f(Fip)
res1: Fip.type = Fip

How can I properly write f such that it only accepts an implementor of Foo and Bar?

Upvotes: 1

Views: 103

Answers (1)

Michael Zajac
Michael Zajac

Reputation: 55569

You can use compound types to do this.

trait Foo
trait Bar
def f(a: Foo with Bar) = ???

scala> val foobar = new Foo with Bar
foobar: Foo with Bar = $anon$1@1b8c25c0

scala> f(foobar) // Happily accepts a class that mixes Foo and Bar
res26: Foo with Bar = $anon$1@1b8c25c0

scala> f(new Foo{})  // Refuses a class that only mixes Foo
<console>:23: error: type mismatch;
 found   : Foo(in object $iw)
 required: Foo(in object $iw) with Bar

The same syntax can be used with a type parameter, though I don't see it as necessary here.

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

scala> f(foobar)  // Accepts a class that mixes Foo and Bar
res29: Foo with Bar = $anon$1@1b8c25c0

scala> f(new Foo{})  // Refuses a class with only Foo, as it breaks the type bounds
<console>:25: error: inferred type arguments [Foo] do not conform to method f's type parameter bounds [A <: Foo with Bar]
<console>:25: error: type mismatch;
 found   : Foo
 required: A

Another way you could write it is:

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

Upvotes: 2

Related Questions