I'm currently discovering scala and I was wondering if I could use traits with a factory.
I tried this :
abstract class Foo { ... } object Foo { def apply() = new Bar private class Bar extends Foo { ... } } Foo() with MyTrait // Not working
I guess it's because with
must be preceded by new
.
So is there any way to do this ?
Thank you
Say you have:
Then:
would be analogous to:
which would imply some kind of prototype-based inheritance, which Scala doesn't have. (As far as I know.)
(I'd guess the error in thinking is intuitively mistaking the = sign for a "substitution sign". I.e. since Foo() means Foo.apply() and which "equals" new Foo, you can substitue Foo() with new Foo. Which obviously you can't.)
Solution with proxies and implicit conversion
This example extends olle's solution to allow the user to specify the mixin trait when calling the
apply()
method (e.g.val xerxes = Avatar[Elf]("Xerxes")
).Prints:
Solution with implicit conversion
Ken suggested that a proxy could help us in this case. What we are trying to do here is to add a trait to the instance after it is created. This "monkey patching" could be useful if someone else wrote the class (and the
apply()
method) and you cannot access the source. In this case you can do is add a proxy/wrapper on top of the instance by implicit conversion (no manual conversion needed):Using the
Foo
example we could do this like this:Outputs:
The reason I do not like this example is:
Baz
doesn't useFoo
in any way. It is hard to see the reason why we would want to attach theusefulMethod()
toFoo
.So I made a new example where the the trait we "monkey patch" into the instance actually uses the instance:
Prints:
In this example the added
Elf
trait use thegetName
method of the instance it extends.Would be grateful if you see any errors, I am not the good at implicits (yet).
No it is too late, the instance is already created when the apply() method returns.
What you can do is using the traits inside the factory method. The code below is from a rather big code example I am writing:
In this code the type (profession and race) of your Avatar is decided in the factory based on the RaceType and CharacterType enumerations. What you have is one factory for all sorts of different types or type combinations.