4

I have a set of model objects and a set of wrapper objects to give them extra functionality.

I'd like to be able to convert collections of model objects to wrapper objects concisely, using the same shorthand that allows you to write List("x", "y", "z").foreach(println), like this:

class Model
class ModelWrapper(val m: Model)
object ModelWrapper { def apply(model: Model) = new ModelWrapper(model) }

val m1 = new Model; val m2 = new Model; val m3 = new Model

List(m1, m2, m3).map(ModelWrapper)

So that ModelWrapper, passed as an argument, is converted to ModelWrapper(_), a call on the companion object.

However, when I try this, I get a type mismatch error like this:

<console>:14: error: type mismatch;
 found   : ModelWrapper.type (with underlying type object ModelWrapper)
 required: Model => ?
                  List(m1, m2, m3).map(ModelWrapper)

However, if I make ModelWrapper a case class, and remove the companion object, it works. I don't want to make it a case class as the behaviour it's adding does not fit well with the overall way in which case classes work. Two wrapper classes with the same model class as a parameter are not necessarily equal, for example.

What I'd like to know is, what is the difference between the case class and companion object in this case? Can I get what I want without using a case class?

Russell
  • 12,261
  • 4
  • 52
  • 75

2 Answers2

10

Your companion object must be a function:

object ModelWrapper extends Function1[Model, ModelWrapper] { def apply(model: Model) = new ModelWrapper(model) }

Or may be you'll prefer this abbreviation:

object ModelWrapper extends (Model => ModelWrapper) { def apply(model: Model) = new ModelWrapper(model) }
Sergey Passichenko
  • 6,920
  • 1
  • 28
  • 29
  • The funny things is that, according to the scala specification, the built-in companion object does not implements the Function trait. Maybe there's another explanation. – Nicolas Mar 13 '12 at 15:50
  • 1
    This works so marking it as accepted, thanks. But I would be interested in knowing what causes the difference. Complete guess, but I wonder if the built-in companion object does something like providing an implicit conversion to a `Function`? – Russell Mar 13 '12 at 17:24
  • I found this behavior some days ago and it was strange for me too. – Sergey Passichenko Mar 14 '12 at 00:37
4

For some reason, these works:

  List(m1, m2, m3).map(ModelWrapper(_))
  List(m1, m2, m3).map(ModelWrapper.apply)

It seems for case classes, since the companion object is created by the compiler and not you, it knows you are referring to ModelWrapper.apply. When there is a companion, it thinks you are referring to the companion.

huynhjl
  • 41,520
  • 14
  • 105
  • 158