Wednesday, September 9, 2009

Using objects to access trait functionality

Today's topic is based on an article by Bill Venners. http://www.artima.com/scalazine/articles/selfless_trait_pattern.html. I recommend reading that article as it goes into much more detail. I also recommend taking a look at the earlier topic that covers companion objects.

The normal way to use a trait is to mix it in to an object. However there can be a problem mixing two traits containing methods with equal signatures. If the two traits are not designed to work together then you will get a compile error. Otherwise one method will override the other. Either way you cannot access both methods. There is an additional way to access the functionality of a trait. You can create an object (not instance) that extends the trait and import the methods when you need them.

If the trait is stateless then the object can be shared if not then make sure that sharing the object is carefully handled.

Examples:
  1. scala> trait T1 {
  2.      | def talk = "hi"
  3.      | }
  4. defined trait T1
  5. scala> trait T2 {
  6.      | def talk = "hello"
  7.      | }
  8. defined trait T2
  9. // Cannot extend C with T1 and T2 because they are not designed to work together
  10. scala> class C extends T1 with T2
  11. :6: error: error overriding method talk in trait T1 of type => java.lang.String;
  12.  method talk in trait T2 of type => java.lang.String needs override modifier
  13.        class C extends T1 with T2
  14.              ^
  15. scala> class C extends T1
  16. defined class C
  17. // objects can have state so becareful how you share them
  18. scala> object Obj1 extends T1
  19. defined module Obj1
  20. scala> object Obj2 extends T2
  21. defined module Obj2
  22. // You can give aliases to the imported methods and use them in the class
  23. scala> class C {
  24.      | import Obj1.{talk => hi}
  25.      | import Obj2.{talk => hello}
  26.      | def sayHi = hi
  27.      | def sayHello = hello
  28.      | }
  29. defined class C
  30. scala> val c = new C
  31. c: C = C@54d8fd1a
  32. scala> c.sayHi
  33. res0: java.lang.String = hi
  34. scala> c.sayHello
  35. res1: java.lang.String = hello
  36. scala> class C extends T1 {
  37.      | import Obj2.{talk => hello}
  38.      | def helloTalk = hello
  39.      | }
  40. defined class C
  41. scala> val c2 = new C
  42. c2: C = C@2ee634bf
  43. scala> c2.talk
  44. res2: java.lang.String = hi
  45. scala> c2.helloTalk
  46. res5: java.lang.String = hello

No comments:

Post a Comment