Contains some code and documentation about how to get started with Scala.
- Java JDK 8
- Scala
brew install scala
All script related code can be found under scripts. There I have written basic examples on conditional and loop statements, using both imperative and functional approaches.
There is also some examples of methods, types, units and parameterisation (equivalent to Java generics).
The more Object Oriented related code can be found under objects. The classes contain documentation, thus better to refer to what is written there as well. They also contain details about compiling and running the code and inspecting the byte-code.
This is all work in progress, so bare with me whilst I work on some more advanced examples.
- Type inference
- Static types
- Community support
- Pattern matching, clean syntax, API, currying, partial functions, operator overloading.
- It’s difficult.
- Backwards compatibility.
- Not that much.
- val: defines a final variable, a constant, cannot be changed after a value is assigned to it.
val a = 100- Type inference will make it an integer
val a:Int = 100- In case we want to specify it. However, not really needed.
- var: defines a variable, can have values reassigned to it. Not very used because it's mutable.
- lazy val
- Delays evaluation of the val to when it’s actually used.
- OpChars (Operation Characters)
- unicode.org/charts/PDF/U0000.pdf
- Unicode Symbol Math
- fileformat.info/info/unicode/category/Sm/list.html
- Unicode Symbol Other
- fileformat.info/info/unicode/category/So/list.html
- Escape reserved keywords (with a backtick)
val `import` = 10
- Byte
val a:Byte = 10
- Short
val a:Short = 130
- Integer (default)
val a = 100000
- Long
val a = 100000
- Float
val a = 100.0F
- Double (default)
val a = 100.0
- Char
val a = ‘k’val a = ‘\u03BB’
- Boolean
val b = true
- All primitives inherit from AnyVal
- AnyVal inherits from Any, which is the mother of everything.
- AnyRef inherits from Any as well, and all objects inherit from AnyRef
1.+(4)-> prints 5-5.abs-> prints 5- It uses implicit wrapping (by rich wrappers).
- Example:
import scala.math.powdef **(x:Int, ex:Int) = pow(x, exp)
- Unit is something you get when there is nothing to give. It’s like “void” in Java.
val g:Unit = ()
- Cool idea of having methods inside methods. The closest thing to it that I would say Java has is anonymous classes, which are not cool anyway.
- This keeps code cleaner and the scope of the inner-method is limited by the outer-method.
- Works just like in Java. Nothing special there.
- This is analogous to Generics in Java. It helps to keep the code more polymorphic and abolish the use of isInstanceOf and asInstanceOf (casting).
- Have a look at the
Person.scalaand thePersonScript.scala. There is a lot of documentation available there.
- From a Java perspective, the Getters and Setters are analogous to Scala's accessors and mutators.
- If one needs Java style Getters and Setters, the scala.beans.BeanProperty annotation can be used on the constructor parameters.
Have a look at the
Computer.scalaclass.
- The class
Person.scalacontains the implementation of a few constructors. Please, read the documentation there. - The primary constructor is expected to have all the information that is needed to create an object of the class. The remaining constructors must always call the primary one, either directly or via another constructor.
- There are no empty constructors in immutable languages in order to avoid excessive copy and memory consumption.
- Constructors are defined just like a method, but they are called
this. To have a multi-lined constructor, just use curly-brackets. - The first line of an ancillary constructor has to be a call to another constructor.
Just like they are used in methods, there is no reason why they shouldn't in constructors. Isn't it lovely?
- All required self-explanatory code can be found in the
Computer.scalaclass. - Using default and named arguments is helpful and decrease the need of having ancillary (secondary) constructors. However, as a personal opinion, a constructor with a lot of parameters is a bit hard to read / use. Instead, I would have a few more constructors.
No mystery here. Just like Java, except for some improvements, Scala has the methods in classes. We have already seen some, bu in the script files we worked with.
- Methods have access to the internal state of objects and hence can modify their state.
- Default and named parameters are also allowed. That helps a lot! Why? Instead of defining methods to change the state, we can use the Memento Pattern and create a copy of an object, keep the state on the member we want and changing those we don't.
For further details please refer to the Computer.scala class.
- Constructors and methods' parameters can be checked for preconditions with
require,assert,assumeorensuring. Each of them behaving slightly different from each other. For instance, arequirethrows anIllegalArgumentExceptionif a condition is not met. When it comes toassertandassume, an AssertionError is thrown. Both are used for static checking, differing only in intent. The prior is a predicate whilst the latter is an axiom. - Some more details about the other two,
requireandensuring, they are used as a mean of design-by-controct specification. - In order to disable the checker, use -Xdisable-assertions, which raises -Xelide-below above elidable.ASSERTION.
- Exceptions in Scala are handled in a similar fashion as they are in Java. The main difference is that the
catchblock uses a matching patters to check which exception has actually been thrown. - Just like in Java, you can also have a
finallyblock. - All exceptions in Scala are Runtime.
To get a glimpse on how it all works, have a look at the Computer.scala class and the ComputerScript.scala. Remember: if you don't explicitly check them, they will look ugly on the console, browser, etc.
- Just like with Java, the keyword
extendsis used to denote inheritance, a is-a relationship. - Again, like in Java, attributer that belong to the superclass are sent to its constructor.
- And guess what, polymorphism also applies.
- But wait! That doesn't have anything to do with Java, that's all about Object Orientation. Ah, we are fine! ;)
- The inheritance example is depicted in the
Models.scalaclass and execution-wise, more details can be found in theModelsScript.scala. Yes, as I said previously, we don't need the file name to be the same as the class name. Moreover, there can be multiple classes per file. I mean, multiple public classes.
Again, there are only a few differences when compared to Java, and that's not only about syntax-sugar. Below some details on how to work with method overriding.
- The keyword
overrideis mandatory. In Java we have an annotation which only indicates that a particular methods overrides another, but it can be omitted. - Of course, like in Java, the signature must be the same. Otherwise, it is not overriding, but overloading - which I will explain later.
A new method, called fullName, was added to the class Person.scala and is being overridden in the Employee class, which lies inside the Models.scala
Have a look at the ModelsScript.scala for further understanding.
- Method overloading does not have a special keyword. It works just like in Java. So, if have method A(param1, param2) and want to overload it to add an extra parameter. To achieve that, just define a method A(param1, param2, param3) and you are good to go.
- There is one small thing about method overloading, though: it does not work if the method being overloaded contains default parameters.
To confirm this problem, have a look at the
Models.scala. There I overloaded the 'update' method, which is declared in thePerson.scalaclass. The overloading method is currently commented out. Please, remove the comment blocks and try compiling the file.
- As the name suggests,
equalsis used to test equality of values between two objects. For example, if we have created 2 instances of the class 'Person' with the same first name, last name and address, checking for value equality should returntrue. - The
equalsmethod is defined in theAnyRefclass, which means that we have to override it. If we simply check for equality, without overriding the method, it will return false, since that the default implementation in theAnyRefclass does not take into account the class members we have defined. - After defining out
equalsmethod, with can call it using the==operator; that's equivalent to the equals, so not really like Java==, which checks for reference equality. - In Scala, to check for reference equality, or if objects reference the same instance, we have to use the operator
eq. Check thePerson.scalaand thePersonScript.scalafile.
- The
hasCodemethod is used to return a hash, a unique as possible identifying number, which is related to a particular object. It's also used as a link by the JVM to help fetching where in the memory a given object is stored. So, it's not the memory address itself. - As with
equals, thehashCodemethod is also defined in theAnyRefclass. In order to use it, we have to add our own implementation to our classes. This is a must have for any domain model class since the method is used in Maps. - The
hashCodeimplementation used here is suggested by Josh Block in his Effective Java 2nd Edition book. Have a look at thePerson.scalaclass to see how it's done.
- The
toStringmethod kicks in when we need a human readable representation of an object. As the other two, it's also defined in theAnyRefclass. It's implementation? Feel free to do whatever you want. Again, have a look at thePerson.scalaclass.
Remark: when using an IDE, the three methods explained above should be easy to generate in an automatic fashion.
And now the time to forget about writing equals, toString and hashCode has come! Yes, just use the keyword case before class in your class declaration. Done!
What else does case bring to the table?
- No need to use the
newkeyword when instantiating classes. - No need to use the
valbefore the constructor parameters. - It creates a
copymethod which can be used to create a new object of an instance (GoF Memento Pattern). - It has automatic pattern matching.
- However, case classes cannot be subclassed. It makes them good to be domain model classes.
If you don't like the toString implementation, for example, just implement your own. Have a look at the Models.scala and look for the Department class.
If you come from Java, C++, C#, etc., you know what abstract classes mean. There are only a few things here that I should mention.
- Use the
abstractkeyword in the class declaration.
Have a look at the Models.scala file and the new abstract class that has been added.
We have already seen Parameterised Types with Scala. So, it is not very different from Java and you have a lot of freedom. I mean, it's the same thing. To know more about how using it with classes, please refer to the following files:
Box.scalaclassCouple.scalaclassBoxScript.scalascriptCoupleScript.scalascript
No extra explanation needed.
Again, nothing really special here if you are already used to Java generics. Have a look at the same files I depicted above for examples on how to use it.
Objects are cool, but how cool are they in Scala? No, I'm not talking about class instances, which are objects, but singleton objects with boilerplate code. So, in Scala 'object' is a keyword used to declare singletons (yep, from the GoF Patterns). Since there is no 'static' in Scala, creating a singleton the way we do in Java would be a bit difficult. So, objects to the rescue!
Besides singletons, objects are good for factory methods, pattern matching logic, default values, main method, etc.
Have a look at the ObjectsScript.scala for more details.
Okay, you might have got it a long ago. But what do we have to do to get a main method? Have a look at the Runner.scala and, for a simpler version, also
look at the RunnerApp.scala.
Those type of objects are still singletons, but it has some specific things and applications are slightly different from what we saw above.
- A Companion Object must have the same name as the class
- A Companion Object have to be in the same file where the class is declared
- Private information is shared between the Class and the Companion Object
- A Companion Object cannot have a main method.
- Since objects are singletons, whatever state it has will be shared amongst the instances of the class it accompanies.
You will find some application of Companion Objects in the SecretAgents.scala and SuperHeroes.scala files.
The apply method brings some special juice to Scala. It helps the programmer to write less and less code. All the boilerplate you are use to will be gone!
- If a method is called
apply, you don't have to call it explicitly - It can be used in both classes and objects.
- Although we haven't seen it, it has already been used in this tutorial: case classes. Yes, they not only declare accessor methods automatically, but they also create a companion object for the class and apply methods to be used as factory methods.
To see how it is possible, please refer to the Cars.scala file.
Infix operators help to clean the code a bit by removing the dot and parenthesis of a method call. It is usually used when the method has just one parameter, but it is not limited to that.
For example, when we do "3 + 4", it is actually calling the method "3.+(4)". So, mathematical operations in Scala use infix operators. Another application of infix operators is chain reaction. For instance, implementing a Chain of Responsibility Pattern would be quite easy with Scala.
To have a look on how fun infix operators are, have a look at the ChainReaction.scala file.
Time to some more Scala magic! I won't write much about it. So, please have a look at the ColonsScript.scala file.
- If a method ends in a colon, you may invoke it in a right associative way.
- It mush be invoked as an infix method.
- This technique is primarily used with Lists and Streams.
Who like "null" values? Nobody, right? Or at least, most of experienced programmers might be in favour of having something other then the vast void of space. For that Optionals come in hand. Java have them, since Java 8. And So has Scala, but way before that.
In Scala they are called Options. An Option can be of Some or None type. As the types suggests, Some contains something, whilst None doesn't contain any.
For some examples, no pun intended, have a look at the Options.scala file.