There is admittedly some truth to the statement that “Scala is hard”, but the learning curve is well worth the investment. Some of the more complex features of the language (Tuples, Functions, Macros, to name a few) ultimately make it easier for the developer to write better code and increase performance by programming in Scala. Frankly, we are programmers, and if we’re not smart enough to learn a language that has some complexity, then we’re in the wrong business.
Scala is a type-safe JVM language that incorporates both object oriented and functional programming into an extremely concise, logical, and extraordinarily powerful language. Some may be surprised to know that Scala is not quite as new as they thought, having first been introduced in 2003. However, it is particularly within the past few years that Scala has begun to develop a significant following. Which begs the question of “Why Scala?”.
This article examines the advantages of Scala, especially versus Java (since Scala is written to run in the JVM). Scala is not the only attempt to create a “better Java”. Alternatives such as Kotlin and Ceylon have also gone down that path, but they made the fundamental decision to remain very close in syntax to the Java language itself, so as to minimize the learning curve. This may seem like a great idea, but it is ultimately somewhat self-defeating in that it forces you to stay within a number of those very same Java paradigms that were the reason for wanting to create a “better Java” in the first place.
In contrast, Scala was created specifically with the goal of being a better language, shedding those aspects of Java which it considered restrictive, overly tedious, or frustrating for the developer. As a result, there are indeed code distinctions and paradigm shifts that can make early learning of Scala programming a bit more difficult, but the result is a much cleaner and well organized language that is ultimately easier to use and increases productivity.
While the simplicity of the Java language has been part of its success, ironically, it has also contributed to its complexity. Sure, you can write nearly anything in Java, but the lines of code required to do so can be daunting. Programming in Scala, on the other hand, has a slightly more complex structure. But if you can write a slightly more complex single line of code that replaces 20 “simpler” lines of Java, which one is really more complex?
The truth is that Java is often just way too verbose. In Scala, the compiler is incredibly smart, so this avoids the developer needing to specify explicitly those things that the compiler can infer. Compare, for example, this simple “Hello World!” program in Java vs. Scala:
Hello World in Java:
public class HelloJava { public static void main(String[] args) { System.out.println("Hello World!"); } }
Hello World in Scala:
object HelloScala { def main(args: Array[String]): Unit = { println("Hello World!") } }
While there’s not a huge distinction between the two languages here, Scala is less verbose even in this simple example.
For a more practical example, let’s take a look at creating a simple list of Strings:
Java:
List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3");
Scala:
val list = List("1", "2", "3")
Certainly there are some tricks in Java to shorten the code a bit, but not in standard usage.
Now consider a case where we have a list of strings that are numbers, but we want to convert that list to a list of integers:
Java:
List<Integer> ints = new ArrayList<Integer>(); for (String s : list) { ints.add(Integer.parseInt(s)); }
Scala:
val ints = list.map(s => s.toInt)
Thanks to Scala’s functional properties, this conversion becomes extremely simple.
Let’s take things a step further and compare standard bean / plain old Java object (POJO) creation in Java and Scala.
First, the Java version:
public class User { private String name; private List<Order> orders;public User() { orders = new ArrayList<Order>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Order> getOrders() { return orders; } public void setOrders(List<Order> orders) { this.orders = orders; }
}
public class Order {
private int id;
private List<Product> products;public Order() { products = new ArrayList<Product>(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public List<Product> getProducts() { return products; } public void setProducts(List<Product> products) { this.products = products; }
}
public class Product {
private int id;
private String category;public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; }
}
Phew. Lotta code.
Now the Scala version:
class User {
var name: String = _
var orders: List[Order] = Nil
}class Order {
var id: Int = _
var products: List[Product] = Nil
}class Product {
var id: Int = _
var category: String = _
}
Which language did we say was more complicated?!
If you’ve made it this far, and are a Java programmer, you may at this point be thinking that I’m making an unfair comparison of code. After all, there’s nothing stopping me from making public variables in Java and then getting rid of the getters and setters.
However, if you think back to the reasoning behind getters and setters in Java, it is specifically for future-proofing. That is, if you later need to add some logic to either the getting or setting of variables you would have to re-write those public variables to use methods instead (which is why the use of getters and setters to begin with is encouraged in Java). However, in Scala programming this isn’t the case. Because of the language design, the abstraction remains intact without needing getters and setters. Consider, for example, this modified User
class in Scala that throws a NullPointerException
if you try to set the name to null:
class User {
private var _name: String = _
var orders: List[Order] = Nil
def name = name
def name=(name: String) = {
if (name == null) {
throw new NullPointerException(“User.name cannot be null!”)
}
_name = name
}
And you can still set the name like this:
user.name = “John Doe”
Note that this entirely removes the need to pre-configure method accessors.
Moreover, since Scala prefers immutability, I can write this in Scala even more concisely with case classes:
case class User(name: String, orders: List[Order])
case class Order(id: Int, products: List[Product])
case class Product(id: Int, category: String)
Pretty crazy how much less code I have to write.
Now consider a scenario with the above classes where I want to add a nifty little method in the User
class that returns a list of all Products
that the User
has ordered:
In the verbose world of Java:
public List<Product> getProducts() {
List<Product> products = new ArrayList<Product>();
for (Order order : orders) {
products.addAll(order.getProducts());
}
return products;
}
Fortunately, java.util.List
has an addAll
method, or getProducts()
would have been an even longer in Java.
In Scala, on the other hand, all we need is:
def products = orders.flatMap(o => o.products)
You can see just how much smaller the Scala language implementation is. Yes, it may seem more complex to the Scala newbie, but once you actually fully understand the concepts behind it, the Scala code will look far more simplistic than the Java code.
Let’s get even a bit more complicated here. What if we want to only get the Products
within a specific Category
?
In this case we aren’t able to take advantage of the addAll
method in java.util.List
, so things get uglier in Java:
public List<Product> getProductsByCategory(String category) {
List<Product> products = new ArrayList<Product>();
for (Order order : orders) {
for (Product product : order.getProducts()) {
if (category.equals(product.getCategory())) {
products.add(product);
}
}
}
return products;
}
In Scala, however, the code remains fairly straightforward. We simply use flatMap
to combine the products lists from each Order
flattened in a single list, then we filter to only include the ones that match the category:
def productsByCategory(category: String) = orders.flatMap(o => o.products).filter(p => p.category == category)
There has certainly been no shortage of new languages over the past few years, but whereas nearly all the others that have recently emerged are dynamic, Scala is statically-typed.
As a professional developer – though I know and use many dynamic languages – it is my opinion that compile-time checks are incredibly important to write solid code. In a dynamic language, you can never be sure that your code is sufficiently bug-free and robust until you actually run it in a wide range of scenarios. This can lead to potentially serious defects in code that never get realized until the code is in production.
Hopefully, this article stacks up Java vs. Scala enough to give you a preliminary sense of the power and capabilities of Scala and whets your appetite for learning the language. Not only is it a great language that can make programming less tedious and more enjoyable, but it’s also being used by some of the largest companies in the world (LinkedIn, Twitter, FourSquare, The Guardian, to name just a few).
The popularity and usage of Scala is rapidly on the rise, as evidenced by the ever-increasing number of open positions for Scala developers. If you haven’t already done so, now would be a good time to begin riding the wave and stop asking “Why learn Scala?”
Thanks For Visiting, Keep Visiting. If you liked this post, share it with all of your programming buddies!
Further reading
☞ A Scala tutorial for Java developers
☞ The Scala Chronicles: The Beginning.
Originally published on toptal.com
#java #scala #devops