3

In Java I would write

void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }

What do I write in Scala?

def foo(someObjects : Set[AnyRef[SomeClass])

But this doesn't work

Paul McKenzie
  • 19,646
  • 25
  • 76
  • 120

3 Answers3

6

I rarely find myself writing code like this any more. The reason is that, in your example

void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }
//                ^^^^^^^^^^
//                use-site variance annotation

The variance annotation denotes you can only access the collection, not update it. It's highly probable that you could re-write the method as follows

void foo(final Collection<? extends SomeClass> someObjects) { /* ... */ }

That is, if you can only access elements in the set, it's unlikely that you need it to be a Set. In scala, this means using Iterable or Traversable - but these types in Scala are covariant in their type parameter (they are declared Iterable[+A] - the + is a declaration-site variance annotation). Hence there is no need for a use-site variance annotation:

def foo(itr: Iterable[SomeClass])

Then you can pass a Set[SomeClassImpl] freely into this method:

scala> trait T; class S extends T
defined trait T
defined class S

scala> def foo(itr: Iterable[T]) = println(itr.isEmpty)
foo: (itr: Iterable[T])Unit

scala> Set(new S)
res1: scala.collection.immutable.Set[S] = Set(S@e1ed5b)

scala> foo(res1)
false

The reason that scala's Set[A] is not covariant in A is that it implements A => Boolean (i.e. Function1), which is contravariant in its input. Hence Set[A] must be invariant in A. Some chump has asked this before.

In fact, it's much more common that I now use Set as an implementation detail of a predicate function. So, for example:

def bar(p: SomeClass => Boolean)

In this event; you could use:

scala> bar(res1.toSet[T])
Community
  • 1
  • 1
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
5

The literal translation for

void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }

is

def foo(someObjects: Set[_ <: SomeClass]) { /* ... */ }

or

def foo(someObjects: Set[_ <: SomeClass]): Unit = { /* ... */ }

If you are overriding some method in a Java class, prepend override to def. If you are not, please consider doing things in a different manner, as explained by the other answers.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
3

You can define the dependency by using a type bound:

def foo[A <: SomeClass]( someObjects: Set[A] ): Unit = ...

Here A <: SomeClass means that A extends SomeClass, and you can use B >: SomeClass to express than B should be a super class of SomeClass.

paradigmatic
  • 40,153
  • 18
  • 88
  • 147