scala intro

Just some random notes about scala that you would notice as you start learning scala ( this is fairly long post )

scala support first class functions – this means scala treats functions just like variables – you can pass it to another function as an argument

it supports closures – A closure is a function, whose return value depends on the value of one or more variables declared outside this function

it supports currying – which is where a funtion that takes multiple arguements can be written as if it takes one argument and then a chain of calls to bring the same functionality as earlier , this makes it easier to pass the function as a first class function.

it supports pattern matching – case classes

Scala has a strong type inference , so its statically typed but we can leverage the type inference

scala> var radi = 10

radi: Int = 10

scala> var raii = 10.0

raii: Double = 10.0

in the case below , scala inferred the types based on the values . The compiler is smart enough to check the type

scala> var radi:Int = 10.0

                      ^

       error: type mismatch;

        found   : Double(10.0)

        required: Int

use triple quotes “””” for multiline strings. “””

you can use == operator to compare strings

String interpolation is supported , so scala will substitute the variable in the string thats delimited by $. need a ‘s’ at the beginning of the string

s” hello $valword”

the $valword will be replaced by whatever value it has . you can use formula with {} . for printf , precede the string with a ‘f’ and then the format with the % command

scala has a unified type system, java has the value and reference type , primitives like integer etc are passed by value whereas String , collections etc are object and passed by reference.

everything is an object in scala – no primitives , no wrapper types etc – functions are objects too – first class function

Scala solves this conundrum by declaring superclass – two superclass Anyval and AnyRef and then these have another class called Any …see this for better idea –https://docs.scala-lang.org/resources/images/tour/unified-types-diagram.svg

null in java and scala are the same , it can be used as a value for a reference type but not for value type . Null is a trait ie a type and not a value , null is a type of Null. Nothing is also a trait . Nothing can never be instantiated but Nothing extends everything because its a subtype of both AnyVal and AnyRef. Nil is a special value associated with an empty list. Nil is the singleton instance of List[Nothing]. List are singly linked list in scala and Nil is what the last element points to. None is a special value associated with an option , so if the function does return a value sometimes…. great , if not it can return None. Unit is similar to void in java as it is the return type of a function that returns nothing for instance

type operations -> asInstanceOf – similar to cast in java , however its better to use to<Type> e.g toLong – its class specific , and calls the system converter and its better .

you can use boolean method isInstanceOf[class] to check the type . you can use getClass to get the actual class

scala can be compiled or interpreted (remember the repl loop in intellij )

You can directly create a scala object as opposed to a class

A scala object corresponds to a static class in java

So  object o creates a singleton object 0 as the instance of some anonymous class , it can be used to hold static members that are not associated with instances of some class

main is the entry point just like java , but the same can be achieved by extending App which is a trait.

Object o extends T  makes the object 0 an instance of Trait T ;  you can then pass o anywhere , a T is expected.

Traits in Scala are like partially implemented interfaces. It may contain abstract and non-abstract methods. It may be that all methods are abstract, but it should have at least one abstract method. Not only are they similar to Java interfaces, Scala compiles them into those with corresponding implementation classes holding any methods implemented in the traits.

You can say that using Scala trait, we can share interfaces and fields between classes. Within trait, we can declare variables and values. When we do not initialize them, they are abstract. In other cases, the implementing class for the trait internally implements them.

Unlike Java , Traits can be extended by an instance of the class and not just by the class itself. you can extend multiple traits thus giving the impression of multiple inheritance

val is immutable , this keeps the code safe for concurrent distributed applications. Var is mutable , better to use Val instead .

Don’t use the return keyword in scala  ,  the last value is the return value in scala code  , so it automatically picks it up  …using return will allow you to compile the code , but its not advised.

Here is a good blog describing why we should not use return

https://tpolecat.github.io/2014/05/09/return.html

in scala – you either have a statement ( which does not return anything ) or expression ( which does return something ). A lot of stuff in java thats considered statement in java is considered as expression in scala . You can chain multiple expressions in an expression block thats enclosed in curly brackets – {} . The return type is whats the last expression returns within an expression block.

Scala does allow access to variables defined outside of the expression block ,this is what enables closure. You can have nested expression blocks and in cases of a var defined with the same name and runs into conflict the one closest in the scope is picked , this applies to return – the one that’s most inside defines the return type of a nested expression block

if/else is an expression in scala and if there is no else ( pun intended ) then the return value is Nothing , this is why type inference could infer the value to be Any.

match expressions are more common in scala than nested if else or switch-case in java, this is because match expression can match on value , type etc . match with case for each condition gives a way to conditionally initialize a val.

you can use OR ( syntax is the pipe symbol – ” | ” ) or patternGurad thats a if expression inside of a case expression , so you could have the same Case statement repeated with a different if expression .

val typeofDay = dayofWeek match{
    case "Monday" | "Tuesday" => "Working Day"
    case "Saturday"  => "Sabbath"
   }

in java you have default to do the catch everything else, Scala expands upon this option by giving us two options , you can either declare another case stmt with another variable that catches the default value that can be used in the expression or you can use the default wild card operator “_”

case someothervalue => s"This $somethervalue could be sunday or other working day"

or 

case _ => s"This $dayoftheweek could be sunday or other day"

notice i cannot use the $_ to refer to the variable in the expression

a for loop s just like java , it just iterates through the list so its a statement , recollect statements are code that does not return anything, if you add a “yield” statement , then scala considers the for loop to be an expression which then returns a value for each of the iteration

for(item <- iteminlist){
        item match {
             case "Mango" =>println("Fruit")
             case  everythingelse => println("it could be a fruit orsomething else")
}

// the above stmt doesnot return anything it just prints - the stmt below // returns a list

val new list = for(item <- iteminlist) yield 
{
item match {
case "Mango" => "Fruit"
case everythingelse => "it could be a fruit or something else"
}

this will return a list 
List(Fruit, ....)

in for loop you can use to for the index and it includes the last number in the range or until and it does not include the last number in the range.

while and do while statements are not preferred in scala , its a statement not an expr , the incremental variable has to be a var so it can b incremented and it doesnt fit the functional programming paradigm.

functions are first class citizens which means its an object in itself so it can be passed to other methods , function , store it in a val , return a function etc …all these things you cannot do with a method. methods are declared inside a class . Here is how you would declare the two

class test { 
      def m1(x:Int) = x+3 
      val f1 = (x:Int) => x+3
 }

methods have a “def” and then the name and then an = sign and optionally curly brackets for the expression block.

you can easily convert scala method to function …there are two ways one is by specifying the method signature and the other by wildcard “_” appended to the method ..this is called as eta and scala compiler understands and converts the method to function.

 we can convert method m2 to function f2 as follows 

def m2(x:Int):Int = { x+ 3}
m2: (x: Int)Int
scala> val f1 = (x:Int)=> {x + 3.0}:Double
f1: Int => Double = $$Lambda$840/0x0000000801068840@26bb92e2
scala> val f2:(Int) => Int = m2
f2: Int => Int = $$Lambda$842/0x000000080106a040@77a2688d

you see both function f1 and f2 are of the type Lambda , prior version of scala would make it of type function1 or functionn where n = 1..23  

the other more common way is the eta expansion 

scala> val f3 = m2 _
f3: Int => Int = $$Lambda$843/0x000000080106a840@9499643

note the right side is the name of the method -m2 , space character and then " _"  wild card character 

with named method parameters , the method can be invoked out of order , since we are referring to parameters by name , see below

scala> def m3(num:Int, dem:Int):Float = {num/dem}
m3: (num: Int, dem: Int)Float
scala> m3(2,3)
res15: Float = 0.0
scala> m3(3,2)
res16: Float = 1.0
scala> m3(dem=2,num=3)
res17: Float = 1.0
scala>
in this case i am passing out of order , but scala knows because of named parameter ,  this works only with methods not with function

you can define a default value for a parameter in the method , so you dont have to pass the parameter. Java does not support default parameter and you have to use function overloading in java to get that same feature

parametric polymorphism is same as generics in java with Type parameter. Type parameters are passed in square brackets [] unlike method parameters which are sent in round brackets ()

type parameters only work with methods and not functions ..so if you convert such methods to functions with the eta expansion , it loses the type and converts everything to Any object so we have essentially lost type safety. The key here is to

scala> def printpairTypes[K,V](k:K,v:V) = {
     | val keytype = k.getClass
     | val valtype = v.getClass
     | println(s"$k, $v are of types $keytype $valtype")
     | }
printpairTypes: [K, V](k: K, v: V)Unit

scala> printpairTypes(10,"ten")
10, ten are of types class java.lang.Integer class java.lang.String

val printfn = printpairTypes _
printfn: (Any, Any) => Unit = $$Lambda$1020/0x000000080111d840@70e75151

converting to function automatically converts to ( Any , Any ) and we have lost type safety, if instead we define the types explicitly , it picks it up

scala> val printfn1 = printpairTypes[Int, String] _
printfn1: (Int, String) => Unit = $$Lambda$1028/0x0000000801128840@426ba1d5

varargs or variable arguments can be passed to a method ( not supported in functions ) by specifying * next to the type ..see example below


scala> def concatStrings(strings:String*) = {
     | var concatanetedstr = ""
     | for (s <- strings) concatanetedstr = concatanetedstr + "" + s
     | concatanetedstr
     | }
concatStrings: (strings: String*)String


scala> concatStrings("Hello" , "World" , "From" , "Ella")
res23: String = HelloWorldFromElla

( i am trying a new wordpress plugin for syntax highlighter midway through the post , so the code section can be a bit more readable …whats life without constant change )

concatStrings("Hello" , "World" )
res24: String = HelloWorld

so the same method is invoked with different number of parameters or variable arguement or vararg

procedures are named reusable statements , functions are named reusable expressions and since statements dont return anything , procedure returns unit which is equivalent to void in java

we can define methods with or without parantheses …its allowed and makes it look like fields

nested functions are allowed , we can return a tuple of values from the outer function

Higher order function can take a function as an argument or return a function. you can pass parameters and the function that needs to be invoked as another parameter to another function in this case a higher order function . similarly if the last statement in a function is an anonymous function then that become the return value so you return a function. This helps with currying. i have described a lot in the last two statements. This needs a separate post by itself.

here is a sample higher order function

def math(x:Double,y:Double,fn:(Double,Double)=>Double):Double = {fn(x,y)}
math: (x: Double, y: Double, fn: (Double, Double) => Double)Double

scala> val result  = math(10,20,(a,b)=>a + b)
result: Double = 30.0

// in the case above we are passing the function ( or rather the function definition ) // to the math function as is the case below 


scala> val f2 = (a:Double,b:Double) => a + b
f2: (Double, Double) => Double = $$Lambda$907/0x00000008010a0840@6f4adaab

scala> val result  = math(10,20,f2)
result: Double = 30.0

// in this case math is a higher order function since it accepts a function f2 as a parameter

partially applied function is way to fix or bound one or many parameters of an existing function ,this promotes code reuse . in Java we would use overloading to achieve the same functionality .

you can group similar parameters into parameter groups , so you can have functions that take in multiple parameter groups fn()() …this idea of writing a function with multiple parameter groups is called Currying

you can specify any of the parameter groups and you get partially applied functions ..

closure = nested function + all of the variables local to the outer scope ( Referencing environment )