64

In scala, we cannot extend object:

object X 
object Y extends X

gives an error error: not found: type X

In my case someone has defined some functionality in an object and I need to extend it (basically add another method). What would be the easiest way to extend this object?

Jus12
  • 17,824
  • 28
  • 99
  • 157

7 Answers7

95

As so often the correct answer depends on the actual business requirement. Extending from an object would in some sense defy the purpose of that object since it wouldn't be a singleton any longer.

What might be a solution is to extract the behavior into an abstract trait. And create objects extending that trait like so:

trait T{
    // some behavior goes here
}

object X extends T

object Y extends T {
    // additional stuff here
}
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • 2
    That is what I ended up doing. It actually makes sense to not be able to extend an object due to the singleton requirement. – Jus12 Oct 03 '11 at 06:30
  • 1
    The problem with this is that X and Y have no subclassing relationship, which was the reason to subclass in the first place. – John Cowan Nov 15 '18 at 17:28
42

If you want use methods and values from another object you can use import.

object X{
  def x = 5
}

object Y{
  import X._
  val y = x
}
YoK
  • 1,606
  • 17
  • 23
14

You can't actually extend an object, because that would create two of it, and an object by definition exists only once (edit: well, that's not quite true, because the object definition can be in a class or method).

For your purposes, try this:

object X {
}

object Y {
    def a = 5
}

implicit def xToY(x: X.type) = Y

println(X.a)

It doesn't actually extend, but it does allow you to call new methods on it than were originally defined.

Owen
  • 38,836
  • 14
  • 95
  • 125
  • 11
    IMO, this is evil, never use implicit conversions like this or you are asking for troubles. – Mirco Dotta Oct 02 '11 at 07:29
  • First sentence is meaningless. – user207421 Oct 02 '11 at 08:12
  • 1
    @Mirco: Can you give an explanation for this? – Debilski Oct 02 '11 at 11:46
  • I would also like to know why this is evil. – Jus12 Oct 03 '11 at 06:29
  • 1
    @Debilski @Jus12 I think the problem is that when reading someone's code and seeing `X.a` it makes it harder to find out what `X.a` is referring to, because you need to know what implicits are in scope. At least that's what frustrates me about this. But I thought I'd suggest it anyway. – Owen Oct 03 '11 at 18:19
  • In general, implicit conversions should be used with care. As @Owen pointed out, they do make your code harder to read. Often it's hard to know what implicit is being applied at a given location (remember that rules for implicit resolution are quite involved, and it might be far from easy to guess which one is being applied by only looking at the source. Though, things will definitely get better once IDEs support implicit highlighting). But in this case, the main reason is simply that X should really not be seen as Y, you really want to know which one you are manipulating. – Mirco Dotta Oct 04 '11 at 06:11
  • For the question that the OP is asking, the implicit should be from Y to X, as the goal was to have Y extend X, not to force a pre-existing object X to have additional functionality. Implicitly modifying an existing object would be much riskier than creating a new one that always inherits certain functionality via automatic conversions, provided those automatic conversions must always be imported together with the new object, so one doesn't have to consider whether the automatic conversion is in scope. – Theodore Murdock Jun 16 '14 at 23:35
  • There would be one big difference between that design and OO-inheritance, though...self-calls by X would still be to X, and not to overriding methods in Y. – Theodore Murdock Jun 16 '14 at 23:40
  • This is a smart and perfect answer to the question. Point! As for the "evil" and /or "never", never say "never", if not evil parrot. I found a nice use case for testing extensions to library code (you test it this way, and when ok you move the code to the lib). Thanks! – Volty De Qua Jan 29 '20 at 17:34
5

Note that starting in Scala 3, you can alternatively use composition (instead of inheritance) via export clauses which allow defining aliases for selected members of an object:

object X { def f = 5 }

object Y {
  export X._
  def g = 42
  def h = f * g
}

Y.f // 5
Y.g // 42
Y.h // 210

Note that you can also restrict which members you want to export:

object X { def f = 5; def g = 6 }
object Y { export X.f }
Y.f // 5
Y.g
^^^
value g is not a member of Y
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
5

The only way to share code between two objects is by having one or more common superclass/trait.

Mirco Dotta
  • 1,300
  • 8
  • 13
  • 2
    No, that change allows an object member of a superclass to be overriden by an object member in a subclass. `class A { object a }; class B extends A { override object a }; ((new B): A).a // access B.a` – retronym Oct 02 '11 at 08:24
2

You can convert parent into class + companion object, and then have child extend class E.g.

in Parent.scala

class Parent {}

object Parent extends Parent {}

And then in Child.scala

object Child extends Parent {}

Yes, it's more a hack than a solution.

Stevo Slavić
  • 2,298
  • 2
  • 24
  • 32
0

This is a Scala 3 of Owen's answer: You can extend a companion object using extensions.

object X:
  def a = 5
end X

// Somewhere else, another file where X is visible
extension (x: X.type)
  def b = 42
end extension

// Somewhere else, another file where 
// both X and the extension are visible
@main def main =
  println(X.a)
  println(X.b)