Objects & Traits in Scala
But when it comes to Scala, there is a higher priority placed on expression, conciseness... Primitives require special handling, whereas objects all use the same syntax and are easier to read.
In this post, we will be discussing how objects work in Scala vs Java. I will be approaching this topic as someone who already has a perspective on objects in Java, and will expand on that knowledge to distinguish between the two languages and even showcase their parallels.
No Primitives
Singleton Objects
Extractor Objects
Traits
No Primitives
In Scala, there are no primitive data types. You know, like int, byte, short, long, float, double, boolean, and char. The only data types that a Scala compiler recognizes are objects. So instead of int, you have Int, instead of char— Char, and so on. In this way, Scala is more object-oriented than Java while it is usually only thought to be more functional. Interesting, right?
Now, don't get me wrong, there are primitives at some point. When the compiler compiles Scala down to Java bytecode, those data types become primitives. But what you write in the language is always going to be an object.
So, why does Scala not use primitive data types in the language? It is all about the conceptual simplicity of the code. Java primitives provide faster performance, it's true. But when it comes to Scala, there is a higher priority placed on expression, conciseness, consistency, and scalability rather than easy optimization. Primitives require special handling, whereas objects all use the same syntax and are easier to read.
You can click here to see the type hierarchy for Scala's unified type system.
Singleton Objects
and as opposed to what?
A singleton object is a class with only one instance, meaning you can't say new
and create a new instance of it. It's the object you create when you use the object
keyword as the entry point for your program execution, then serving as the place for all the so-called static methods of the class though there are no "static" methods in Scala.
Since a class is the template of an object (See definition for classes in Java), an instance or object is automatically created when you create a "new" class. This would be an example of an object that is not a singleton.
Case objects are also singleton objects because they are stateless, non-renewable case class instances. Case objects are usually kept as a group or "domain" inside of the companion object. A companion object is the singleton with the shared name of the class.
Here is an example of a singleton/companion object that also has a domain of case objects:
object Counter{ // companion object
case object Increment
case object Decrement
case object Print
}
Class Counter extends Actor{
override receive: Recieve{
case Increment=> int += 1
case Decrement=> int -= 1
case Print=> println(int.toString())
}
}
As you can see above, Class Counter has a companion object Counter with a domain of case objects Increment, Decrement, and Print.
Extractor Objects
In order to explain what this kind of object is, you first have to know what about the apply() method vs unapply().
apply() is a function that applies an object to arguments. This is what you are actually calling whenever you call an object. Many objects are created with an apply method which makes them callable. I will talk more about apply() in the future.
An extractor object is an object with an unapply() function. Unlike apply() which creates an object with its arguments, unapply() extracts the arguments from the object. This is also useful for pattern matching.
Example:
Here, the unapply method is taking c of type Citizen which returns an Option with a String c.name, and a Long c.ssn. When Citizen.unapply(citizen) is called, the result is Some((John,214748364))
.
This is not an example where unapply is actually used for pattern matching. That will be explained in another post.
Traits
In Java, we use an interface to hold method signatures for other classes to implement. The Scala similar is a trait.
Unlike interfaces which are implemented using the keyword implements
, traits are extended. And if you want more than one trait in your class, then you mix them in by using the keyword with
. These traits are also called mixins.
All you need to understand is that traits:
- have instance fields while interfaces do not.
- cannot be instantiated like interfaces because they lack arguments and parameters.
- can have both abstract and non-abstract methods.
- can be extended, therefore providing inheritance.
Traits in Scala are not as confounding as they would be in languages like PHP and RUST since there are no interfaces in Scala, and traits in Scala are actually comparable to interfaces. Scala traits are simply the same as interfaces, except they may hold variables that aren't constant.
Example:
In the example above, class Chef extends two traits, Cook and OrderTracker. Cook has abstract methods while OrderTracker has concrete methods. In the class, we add definition to the abstract methods.
In the object MyChef, we assign a val c
to Chef that we can use to call each method. When c.fry() is called, the result will be I do not fry chicken.
And for the other methods, we have created a val order
and then used it in an boolean expression. Depending on what ther order is, we will either call c.boil or c.steam.
Because order is "yellow rice", the result is:
Order is not ready.
Steaming vegetables...
Order is ready!
In Scala, there are no primitive data types because everything is an object. The most commonly used object is a singleton object. It is created using the keyword object
and serves as the starting point of the program. Singleton objects that have the same name as a class are called companion objects. The companion object is where you would put your domain of case objects and classes.
While Singleton objects are created using the apply() method, Extractor objects are objects that have an unapply() method. unapply() extracts the arguments from the object and gives back the result. Extractor objects are the beginning of pattern matching in Scala.
In Scala, traits are like interfaces that keep the methods and fields for other classes to inherit or mix in. Traits cannot be instantiated, but they can be extended.
And that's the gist of objects and traits in scala!