Tuesday 25 August 2009

Learning Scala when Sleep Deprived

So I've not blogged anything in a while, usual excuse of being busy, the not so usual excuse of becoming a Dad for the second time. So as well as being busy I am somewhat sleep deprived.
I've been doing some stuff with Scala and Lift, and hit a really basic issue that took me a moment (in my current state that equals about an hour) to understand.
I had a couple of classes and was trying to access a field in one class from another ... well I thought it was a field.

package foo

class A( name: String ) { }

class B() {
  val myA = new A("foobar")
  println( myA.name )
}

When I compiled I got this error:

error: value name is not a member of foo.A

Huh? Fields are public by default in Scala, what is going on here. It really had me stumped, my addled brain failed to find any reason for this, and a google search found nothing really useful.

So I changed my code to...

class A( name: String ) {
  def getName = { name }
}

class B() {
  val myA = new A("foobar")
  println( myA.getName )
}

Now I was calling a method which simply returned name, this compiled and ran fine. So why did my original code not work? And why if I first thought that perhaps constructor parameter generated fields were private, but why did I not get an accessibility error?

Then I had a thought, how does the compiler know if 'name' is a val or a var? What if I explicitly state so?

class A( val name: String ) { }

class B() {
  val myA = new A("foobar")
  println( myA.name )
}

This worked. Interestingly using 'var' worked as well - I can only assume that the compiler is getting confused if its not specifying it and so silently doesn't create a field. Even though you can still reference it internally in the class it has no external representation.

Perhaps a case for either a warning or better error granularity?

Or perhaps just a case for me to get more sleep?

1 comment:

kev.lee.wright said...

A contructor param is only exposed as a property if you explicitly state that it should be:

1. make it a val
2. make it a var
3. make the whole thing a case class (which defaults all params to be vals)