If you’ve been following my previous installments into Learning Scala, you might recall that I was ploughing ahead well into chapter 4 of Programming in Scala the last time we met. I’ve made it passed that point, and I’ve already reached into chapter 7. I did get a little bogged down from real life obligations and such, so I’d like to take a break from it and jot down some of my thoughts.
What I’ve covered thus far
It would be something of a lie to say I haven’t read about a lot of things. Some of them I know (classes and objects, Java data types), and many of them I don’t. Up to this point, the book has discussed classes; objects; singleton objects; basic types; more about operators-as-methods; a few blurbs about how Scala handles infix, prefix, and postfix notations; symbols, which is how Scala defines true
and false
; “functional objects” (I have an example from the text for this bit–more later); differences from Java and how Scala handles constructors; something called “pre-conditions” which are awesome; identifiers, which is a fancy term for referencing things in the Java library that contain reserved words in Scala; and finally, control structures. I still have a few things left in chapter 7 to cover–including exception handling–but I think much of what remains is similar enough to other languages that I can put off a discussion over those topics until day four.
Some minor hitches
I’ve encountered more than a few hitches. They haven’t been bad, but they’ve been enough to stop me briefly until I could figure out what I was doing wrong. So far, there is one particularly bad stumbling block that has caught me off guard more than once. I should have known better because I’ve read about it in at least four chapters. Yet, I’m still running headlong into the issue. I think I can avoid it in the future by writing it out; at the very least, this will help me remember. Here’s what it is:
1
2
3
4
5
| class Example {
def doSomething (a: String): String = {
a += "something"
}
} |
class Example {
def doSomething (a: String): String = {
a += "something"
}
}
Looks good, doesn’t it? Not so fast. Compiling this generates an error “reassignment to val
“. Ooops! That’s right, function arguments are val
s, and val
s cannot be reassigned to once they are created. At this point, I knew that the last expression that yields a value qualifies as a return statement (you don’t need explicit returns in Scala), but evidently, I had neglected the small fact that a += "something"
is an attempt to concatenate a string with the contents of a
and inject the resulting string back into the val
. Big mistake. What I meant to write should have turned out like this:
1
2
3
4
5
| class Example {
def doSomething (a: String): String = {
a + "something"
}
} |
class Example {
def doSomething (a: String): String = {
a + "something"
}
}
By writing a + "something"
instead, no reassignment is occurring with a
. Rather, a
is being concatenated with the string "something"
and since it’s the last expression in the function, the resulting value is returned. doSomething
now performs as expected:
scala> var c = new Example()
c: Example = Example@1629e96
scala> c doSomething "what should I do? "
res0: String = what should I do? something
The other problems I’ve run into are largely related to the change in IDEs I had to make (more later–sorry to keep you waiting!). I’ve been doing the usual stupid beginner mistakes of adding parenthesis where they shouldn’t be (mostly by accident) and omitting them where they ought to be (another accident). I’m not exactly certain why I do this; I suspect it has something to do with the minor rewiring of adjusting to a new syntax. But, I’d rather attribute it to the change in IDEs. This is the same thing that plagued me for about a week or so when I was first learning C#. I expect these minor bumps will be gone by next Monday.
More on methods
I know I talked a little bit about methods-as-operators last time. It’s really cool, and you’ve gotten to see another example (above) in the doSomething
method. Since Scala treats methods that return a value and accept exactly one value themselves as an operator, you could therefore write our little class Example
call above as either c.doSomething("what should I do? ")
or, as I wrote instead, c doSomething "what should I do? "
. With Scala’s handling of single-argument methods as operators, it is possible to override all of the basic operators +, -, /, and *. You can even make your own, if you like. The only exception is with the dollar sign ($). Scala uses dollar signs to mangle calls before passing them on to the JVM, so introducing the symbols into your own code will probably cause problems.
However…
Overriding the basic arithmetic operators is all well and good. However, if you try to do the same thing with the arguments swapped, you’ll wind up with an error. Here’s our Example
class again:
scala> "what should I do? " doSomething c
:7: error: value doSomething is not a member of java.lang.String
"what should I do? " doSomething c
Uh oh!
Well, maybe not. doSomething
is defined only in our Example
class. Since String
has no idea what doSomething
means, the compiler complains and spits out this particular error. There is a solution using implicit def
to create an implicit function call within the current scope that resolves this issue. If we were to refactor our Example
class’ doSomething
method (or simply write an override for it), we could add this into the interpreter and it’d work exactly as expected:
implicit def stringToExample (s: String) = new Example(s) |
implicit def stringToExample (s: String) = new Example(s)
I haven’t yet completed a version of the class that does this correctly. I do have a version that will compile but the results are unexpected.
A change of pace…
I mentioned at least once (or was that twice?) that I had to change my IDE. I haven’t explained why, so if you’re curious, let me do that here. First, there’s something important you should know.
The Eclipse Scala plugin does not work
I take that back. It worked exactly once. Then I waited about a week, updated Eclipse, and now it’s broken. 2.7.5 doesn’t work, the nightly builds of 2.8.0 don’t work, and neither does the version I downloaded some time back. Whatever happened broke it. I even downloaded Eclipse via Pulse (which is pretty nice, BTW–I’ll link to it in this week’s LotW), tried the plugin that came with it (which was dated), and that didn’t work.
So, in case you missed it: The Eclipse Scala plugin does not work. They’re working on it, and I’m sure the Scala folks will have a working version up again within a couple of weeks. I take that back: It works. It’s just that it reads Scala sources as Java, even with JDT weaving enabled. I played with it for at least four hours over this weekend, but I’m not going to waste any more time until I have something I can just drop in, click a couple buttons, and have working. I’m not familiar with Eclipse’s internals nor is it something I’m particularly interested at this time (that may change), so I’d much rather have an IDE that just works with Scala.
Netbeans, on the other hand, has a working plugin for Scala. Some things are a little flaky but syntax highlighting works as do some mouse-over/error messages. Javadoc-style comment completion, multiline completion, and proper tabbing of braces when closing methods and classes don’t work. Thankfully, those are simply incidentals that can be dealt with.
It’s just a shame I’ve grown so spoiled with typing /** [ENTER]
and having the enter comment block written for me… Oh well.
Just remember: If you’re learning Scala sometime during the latter half of 2009, you might want to save yourself the trouble and download Netbeans if you don’t already use it. Eclipse is my favorite IDE but it just doesn’t work. (Don’t get me ranting on their plugin infrastructure…)
A word about objects
Scala, unlike Java, PHP, C++, C#, and a few other OOP-style languages doesn’t have exactly the same notion of static methods. In Java, where you might write something like:
public class Calculator
{
public static int doCalculation (int x, int y)
{
return x + y;
}
} |
public class Calculator
{
public static int doCalculation (int x, int y)
{
return x + y;
}
}
And then call this method with: Calculator.doCalculation(4,2)
. Don’t try doing the same thing with Scala. In other words…
class Calculator {
def doCalculation (x: Int, y: Int) = { x + y }
}
// Call this from the interpreter and you'll receive:
scala> Calculator.doCalculation(4,2)
<console>:7: error: value doCalculation is not a member of object Calculator
Calculator.doCalculation(4,2) |
class Calculator {
def doCalculation (x: Int, y: Int) = { x + y }
}
// Call this from the interpreter and you'll receive:
scala> Calculator.doCalculation(4,2)
<console>:7: error: value doCalculation is not a member of object Calculator
Calculator.doCalculation(4,2)
Instead, you have to use something called singleton objects. If I’m remember the text correctly, singleton objects are instantiated (created) the first time they’re called. They’re also named after the class whose static-like methods they implement. For example, if we instead wrote our class (above) like this, splitting it apart into a class and a singleton object:
class Calculator {
}
object Calculator {
def doCalculation (x: Int, y: Int) = { x + y }
} |
class Calculator {
}
object Calculator {
def doCalculation (x: Int, y: Int) = { x + y }
}
And we run the interpreter:
scala> Calculator.doCalculation(4,2)
res8: Int = 6
…we’d receive exactly what we expected.
Now, I’m going to come right out and say this. I’ll probably be labeled a Scala fanboy, too, and that’s fine by me. I actually like this design requirement. Static methods can clutter a class quickly. This is especially true for classes that contain both static and non-static members. If you’ve dealt with thousand-line classes that have a mix of factory methods (static of course) and non-static methods that do useful work within the context of the class, you know what I mean. I imagine that factory methods work in Scala as they do in other languages, but I what I can’t imagine is the well-needed relief this will bring to the world to force static members into a singleton.
To be fair, it’s possible to do something similar to this in C# by using partial classes. In fact, partial classes is one of the things I really love about C#. If you have a class that happens to be especially big, separating it into multiple source files is easy using the partial
keyword. The Visual Studio designer makes liberal use of partial classes, so if you’re hard-pressed for an example, you shouldn’t have to look too far.
Constructing constructors
Scala handles constructors a little differently than does Java. First, all constructor overloads must call the parent constructor or another constructor that does. In other words, this will work:
class Calculator (i: Int, j: Int) {
val x = i
val y = j
def this (i: Int) = { this(i, 0) }
def this () = { this(0,0) }
} |
class Calculator (i: Int, j: Int) {
val x = i
val y = j
def this (i: Int) = { this(i, 0) }
def this () = { this(0,0) }
}
This won’t:
class Calculator (i: Int, j: Int) {
val x = i
val y = j
def this () = { this() }
} |
class Calculator (i: Int, j: Int) {
val x = i
val y = j
def this () = { this() }
}
However, using the first example, calling Calculator
without any arguments results in an implicit assignment (since we created an empty constructor by passing 0 to all of our arguments):
scala> val c = new Calculator()
c: Calculator = Calculator@12a7c1e
scala> c.x
res11: Int = 0
I’m not so sure I can quite see what the best practice is for this particular facet of classes, but I expect it will come clear in the later chapters. Chapters 21-28 have been repeatedly referenced during the course of my reading, and I should think that they’ll clarify some of the things that are on my mind. Specifically, I’m curious about:
- What is the best practice, then, for creating classes with multiple constructors?
- What about classes that might have to deal with different data types, such as
Int
and Float
?
- Initialization is necessary, isn’t it? How are we supposed to use classes if we’re encouraged to use
val
s where possible but cannot reassign to them? Is this one of the cases where using a var
is appropriate?
Pre-conditions kick some serious posterior
Here’s something that Java developers would kill for: Have you ever wanted a way to write–with one line of code–an insurance policy to verify that the arguments passed into your constructor are valid? In Scala, you can. Take this for example:
class Precondition (x: Int) {
require(x > 0)
val number = x
} |
class Precondition (x: Int) {
require(x > 0)
val number = x
}
Now, load this class up in the interpreter and try the following. Watch carefully and see what happens if I pass in a value where x
is less than or equal to 0:
scala> val c = new Precondition(1)
c: Precondition = Precondition@1e04a35
scala> val c = new Precondition(0)
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:107)
at Precondition.(:7)
at .(:7)
at .()
at RequestResult$.(:3)
at RequestResult$.()
at RequestResult$result()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeM...
That’s pretty nice, isn’t it? One line of code can verify that the constructor has been treated correctly by client code. Yes, this is possible in Java using “only one line” of code–or is it? Let’s have a look… I’ll even include line numbers just to be a jerk.
1
2
3
4
5
6
7
8
9
10
11
| public class Precondition
{
private int x;
public void Precondition (int x)
{
if (x > 0)
this.x = x;
else
throw Exception();
}
} |
public class Precondition
{
private int x;
public void Precondition (int x)
{
if (x > 0)
this.x = x;
else
throw Exception();
}
}
Hmm, that’s four lines of code to do roughly the same thing. It’s also bad practice to have all that in the constructor. Let’s do this the Right Way.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public class Precondition
{
private int x;
public void Precondition (int x)
{
this.setX(x);
}
public void setX (int x)
{
if (x > 0)
this.x = x;
else
throw Exception();
}
} |
public class Precondition
{
private int x;
public void Precondition (int x)
{
this.setX(x);
}
public void setX (int x)
{
if (x > 0)
this.x = x;
else
throw Exception();
}
}
There, one line of code! Can’t you see it? You can’t?! I’m talking about the constructor, only. No, really! Oh, that mutator method? Yeah… I had to add that to game the rules of this particular challenge. Fine, you want one line of code, do you?
1
2
3
4
5
6
7
8
| public class Precondition
{
private int x;
public void Precondition (int x)
{
if (x > 0) this.x = x; else throw Exception();
}
} |
public class Precondition
{
private int x;
public void Precondition (int x)
{
if (x > 0) this.x = x; else throw Exception();
}
}
There. One line. Unreadable? Yeah, it is. So what.
“So what,” they might say. Frankly, I prefer readability over the ability to write fewer lines of code especially when those lines of code are compressed. You simply can’t beat the require
statement.
Conclusion
I’ve covered a lot of ground here. At least, it seems like a lot. All told, these chapters took about 4 hours of off-and-on reading for me to complete. That includes time for interruptions and breaks. Scala isn’t hard. It is a paradigm shift, and I’m still not sure how well I’m following along with the functional part of the language. I suppose we’ll see how well I do in the coming weeks as I add further installments into my journal: Learning Scala.
See you next time. Oh, and I promise I’ll have a LotW up tomorrow. Don’t expect it ’til the evening, but I think you should have plenty to read until then.
Cheerio and all that rot.