This is the third in a series of posts that walks through the experience of what it was like to go from being a veteran .NET developer with no awareness of the world beyond the borders of the CLR to exploring the mysteries of the Scala/Akka/Spray stack on the JVM.
Scala and the Runtime
The simplest way to describe Scala is that it’s a programming language that combines both object-oriented and functional programming principles into a single package that executes on the Java Virtual Machine. However, that definition doesn’t really do it justice. Scala is complex and very strongly opinionated when it comes to getting things done. And to a person used to C# and CLR it’s just strange.
The first thing to notice is the differences in how the Scala relates to Java and JVM. Architecturally, the relationship between Scala, Java, and the JVM is very similar to F#, C#, and the CLR. At compilation time, F# and C# code files are compiled into MSIL assemblies that are executed by the runtime using the JIT complier. Scala, Java, and the JVM follow the same general pattern in that Scala and Java code files are compiled into Java bytecode that is executed by the JVM. That’s where the similarities end though and the differences are actually really interesting.
When a solution requires that a portion of the code is written in F# and another portion is written in C# then the solution is split into projects that isolate the language-specific code files into separate assemblies that are ultimately callable via using directives. So, an F# function can’t be added to a C# code file natively. It must be in it’s own assembly. In a lot of ways this makes good architectural sense. For example, if I’m developing an ASP.NET MVC web application, I can define the application structure in C# with all my models, views, and controllers in the same assembly. Then, I can define the business logic that handles all the data processing in F# in a completely separate assembly thereby keeping my tiers clean and the system loosely coupled. This is a nice and neat way of layering applications that .NET developers have taken for granted for years.
With Scala and Java, however, this isn’t the case. Scala was built on top of Java and the JVM, so the relationship is more similar to C/C++ in that Scala could be said to be an superset of Java like C++ is a superset (and elaboration) of C. So, if I was going to visualize the relationships between F# and C# and Scala and Java, I’d say that F# and C# are horizontally related in that they’re both equally .NET compliant and Scala and Java are vertically related (figure 1).
The upshot of this distinction is that where .NET compliant languages need to be compiled into separate assemblies, Scala code files can host both Scala and Java syntax natively without any extra ceremony. The key to what makes this work is that one of the primary design goals of Scala was to offload as much work as possible to the compiler. In the case of mixing Java with Scala, the compiler is intelligent enough to distinguish between the two and handle them appropriately. In many ways, this makes Scala a much more flexible language in that if a developer needs a class or piece of functionality that Scala doesn’t provide by default but is available in Java then he can simply use the Java syntax and carry on unimpeded.