Eli-Golin
10/26/2016 - 12:08 PM

Scala Coding Conventions

Scala Coding Conventions

Code conventions are for three reasons:
 1. Code discovery.
 2. Uniformity.
 3. Error prevention.


Braces Opennings
* Prefer opening braces in the same line.
An example of erroneous code:

class FooHolder
{
  def foo()
  {
    println("foo was called")
  }
}

The class FooHolder has one Unit returning method - foo.
But what actually is happening is that "def foo()" is interpretated as an cabstract method
and, 
{
  pringln("foo was called")
}
as a code block which is executed part of the constructor.

Ofcourse we could solve it by explicitely putting = sign after every concrete 
method definition.

Another reason to prefer block braces openning on the same line is that by following 
it your're able to copy pase your code into the repl.
Example:
if(true)
{
  println("true!")
}
else
{
  println("false!")
}

This code will execute in REPL right after the first block.

Dangling operators and Parenthetical expression.
Dangling operator is an operator (such as +/-) that's the last non white charachter
in a line of code

object Test {
  val x = 5
  def foo = "HAI"
  + x
  + "ZOMG"
  + "\n"
}

This code won't compile because the comiler infewrring the end of line before it should

With dangling operators:

object Test {
  val x = 5
  def foo = "HAI" + 
  x + 
  "ZOMG" + 
  "\n"
}

Everything compiles fine.
An alternative is wrapping hte expression in parentheses:

object Test {
  val x = 5
  def foo = ("HAI"
  + x
  + "ZOMG"
  + "\n")
}

Do not rename named parameters in the child class.
That is .. if a parent class defines a method with named parameters and the 
child overrides it, it should use the same names as it's parent class.
Problematic example:

class Parent {
  def foo(bar:Int = 1, baz:Int = 2) = bar + baz
}

class Child extends Parent {
  def foo(baz:Int = 3, bar:Int = 4) = super.foo(baz,bar)
}

val x = new Child
x.foo(bar = 1) //4
val y:Parent = new Child
y.foo(bar = 1) //5

This is happenning since named parameters in Scala use static type 
to determine ordering. 
So from Scala perspective in case of y.foo(bar = 1), bar is the first argument 
to foo method (from it's static type) and the second argument is the default 
parameter of the foo method from child.

* Names are static, values are runtime.

Always use 'override' keyword when overrding methods (even abstract)
Reasons:

1.
trait UserService {
  def login(credentials:Credfentials):UserSession
  def logout(session:UserSession):Unit
  def isLoggedIn(session:UserSession): Boolean
  def changePassword(new_cerdentials:Credentials, old_credentials:Credentials):Boolean
}

When compiling the beneath class we would receive a compilation error.
But the compilation error is due to not implementin the 'changePassword' in the concrete class. 
class UserServiceImpl extends UserService {
  def login (credentials: Credentials): UserSession = new UserSession
  def logout (session:UserSession):Unit = session.logout()
  def isLoggedIn(session:UserSession):Boolean = true
  def changePassword(session:UserSession, credentials:Credentials):Boolean = true
}

Let's make the implementation to a trait:
trait UserServiceImpl extends UserService {
  def login (credentials: Credentials): UserSession = new UserSession
  def logout (session:UserSession):Unit = session.logout()
  def isLoggedIn(session:UserSession):Boolean = true
  def changePassword(session:UserSession, credentials:Credentials):Boolean = true
}

Now we don't have any compilation errors at all, but we did not implement one of hte methods!

2. Multiple Inheritence ()

trait Animal {
  def talk:String
}

trait Cat extends Animal {
  override def talk:String = "Meow"
}

trait Dog extends Animal {
  override def foo talk:String = "Woof"
}

val kittyDoggy = new Dog with Cat
kittyDoggy.talk //"Meow"

val kittyDoggy = new Cat with Dog
kittyDoggy.talk //"Woof"

Scala linearization rules define that the left most trait wins!
What will happen if we remove the 'override' keyword?!
A compilation error  - the compiler is preventing us from combining two different concrete 
methods that aren't explicitly annotated with 'override'.
This means that if I want to prevent mixing overrides of behaviour from concrete classes
I should not write 'override'.