small medium large xlarge

Back to: All Forums  PragPub
Generic-user-small
07 Sep 2011, 17:12
Tom Murray (1 post)

Hi,

I think the Scala Traits article is a bit misleading in saying that the application of traits to instances is comparable to open classes in dynamic languages (and comparably dangerous).

Open classes, as in Ruby, allow the programmer to modify existing classes, including standard library classes, so that, for example, one could modify Math::cos() or even Math::PI, with unpredictable results for other code that relied on them.

Scala, on the other hand, allows the programmer to compose a class and traits for a single instance, with the critical difference that this does not modify any existing classes, but rather creates an anonymous class for that instance.

Here is an example of the dangers of open classes in Ruby:

irb(main):001:0> def sin_pi_over_2()
irb(main):002:1>   return Math::sin(Math::PI / 2)
irb(main):003:1> end
=> nil
irb(main):004:0> sin_pi_over_2
=> 1.0
irb(main):005:0> Math::PI = -Math::PI  # <evil laughter> PI is negative now!
(irb):5: warning: already initialized constant PI
=> -3.14159265358979
irb(main):006:0> sin_pi_over_2
=> -1.0

Oops!

And here we see that mixing in traits in Scala has no similar modification of the base class:

scala> class Car {
     |   val location = "land"
     |   def drive(): Unit = println("I'm driving!")
     | }
defined class Car

scala> val myCar = new Car()
myCar: Car = Car@16e3aaf

scala> myCar.location
res0: java.lang.String = land

scala> trait FlyingObject {
     |   val location = "air"
     |   def fly(): Unit = println("I'm flying!")
     | }
defined trait FlyingObject

scala> val myFlyingCar = new Car() with FlyingObject { override val location = "land/air" }
myFlyingCar: Car with FlyingObject = $anon$1@13f79f7

scala> myFlyingCar.location
res1: java.lang.String = land/air

scala> myCar.location  // no change here!
res2: java.lang.String = land

As we can see, myFlyingCar is the unique instance of an anonymous class – there is no way to modify Car after it is defined.

This is just different syntax for the common idiom of using anonymous classes to define interface methods in Java, so there’s no reason to caution Java programmers about its safety, as the article does. The only difference is that with traits, some of the methods may already be defined, so we might not have to (tediously) implement them all for the anonymous instance.

Which can only be a good thing.

tm

Headshot_pragsmall
08 Sep 2011, 23:13
Brian Tarbox (41 posts)

You make a fair point and that I agree that traits are not the same as open classes but I do think they have similarities.   You are also right that at a certain level instances created with traits are really just anonymous classes.  However the difference between java and Scala anonymous classes lies in the possibility of reuse.  If you create an anonymous java class by overriding the instantiation as in Foo myFoo = new Foo() { stuff };  you can not reuse the “stuff”.  In Scala the “stuff” is a trait and so you can reuse it, and since you bothered to create the trait you might reuse it.  Thats all I was getting at in that part of the article.

You must be logged in to comment