Thursday, November 30, 2017

Type Classes in Scala



Type classes are useful in providing an interface implementation types without the types implementing the interface themselves i.e. the interface implementation is independent of the type source code.

Hence, type classes can be used to extend the functionality of even those classes for which the source code is not available.

Examples:
Numeric[T] and Ordering[T] are examples of type classes in the Scala library.

Numeric[T] provides a unified interface for all numeric types in Scala even though the numeric types do not share a common super type.

Ordering[T] provides an interface for implementing ordering strategy/logic for sorting a type.

Note
Type classes are not first order citizens in Scala. They are instead implemented via a combination of the following:
  1. traits - for defining the interface
  2. implicit objects - for defining the concrete implementation of the defined trait
  3. parameterised curried method with an implicit parameter list - for restricting the type variable T to the types that have implementations of the defined trait
 Example:

Below is an example of a trait 'MyStringLike' that has a method 'len' which returns the length of a type A value.

The companion object implements MyStringLike[A] for type = Int


trait MyStringLike[A] {
 def len(x : A): Int
}

object MyStringLike {
  implicit object MyStringLikeInt extends MyStringLike[Int] {
    def len(x: Int) = x.toString.length
  }
}


The following are 2 different implementations of the length method which makes use of type class 'MyStringLike' to return the length of some type A for which an implementation of MyStringLike[A] exists.



import MyStringLike._

def mylen[T](x: T)(implicit v: MyStringLike[T]) = v.len(x)
mylen: [T](x: T)(implicit v: MyStringLike[T])Int

def mylen2[T : MyStringLike](x: T) = implicitly[MyStringLike[T]].len(x)
mylen2: [T](x: T)(implicit evidence$1: MyStringLike[T])Int


The 2nd variant where the implicit parameter list is absent is referred to as the context bound notation. Here the type variable T is restricted those types for which MyStringLike[T] implementation exists.


References

[1] https://www.cakesolutions.net/teamblogs/demystifying-implicits-and-typeclasses-in-scala
[2] http://blog.muhuk.com/2013/09/29/unified_support_for_numbers_in_scala.html#.Wh988rT1VR1
[3] http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html

Wednesday, November 29, 2017

Type constructors, Higher Kinded Types etc.



Type Constructors

Type constructors can be thought of as functions that take a type as an argument instead of a value.

Example:

List[+A] is a type constructor

Here, A is a type variable

Higher Kinded Types (HKT's)

A set of types of the same kind are referred to as HKTs.
For example, there can be several types of lists. Hence, list can be considered a HKT.

There is also an order associated with the HKT.

In fact, List is considered as a higher kinded type of the 1st order.


scala:k List
List's kind is F[+A]

scala:k -v List
List's kind is F[+A]
* -(+)-> *


This is a type constructor: a 1st-order-kinded type.


Functors

Functor is a map function that, given 

  • a function 'f: A => B' and 
  • a value wrapped in a context 'F[A]'

can unwrap the value inside F[A], apply the function f to the value to generate value of type B and wrap the same inside context F to generate F[B]

scalatrait Functor[F[_]] {
       def map[A,B](fa: F[A])(f: A => B): F[B]
     }
defined trait Functor

scala:k -v Functor
Functor's kind is X[F[A]]
(* -> *) -> *

This is a type constructor that takes type constructor(s): a higher-kinded type.


Functor is a higher kinded type of the 2nd order as it's type constructor takes type constructor as argument.


Monads

Monad is a transformation function that given f: A => F[B] and F[A], applies the function f to the value in F[A] and wraps the result in the context F i.e. F[F[B]] which is then further flattened get F[B].


scalatrait Monad[F[_]] {
       def flatMap[A,B](fa: F[A])(f: A => F[B]): F[B]
     }
defined trait Monad

scala:k -v Monad
Monad's kind is X[F[A]]
(* -> *) -> *

This is a type constructor that takes type constructor(s): a higher-kinded type.


Applicatives

Applicative is a transformation construct that given a function wrapped inside a context F[A => B] and value wrapped inside a context F[A], unwraps both the function & value, applies the function to the value to generate a type B value and wraps it inside the context F to generate F[B]


scalatrait Applicative[F[_]] {
       def apply[A,B](fa: F[A])(fab: F[A => B]): F[B]
     }
defined trait Applicative

scala:k -v Applicative
Applicative's kind is X[F[A]]
(* -> *) -> *


This is a type constructor that takes type constructor(s): a higher-kinded type.

References

[1] https://thedet.wordpress.com/2012/04/28/functors-monads-applicatives-can-be-so-simple/
[2] https://thedet.wordpress.com/2012/05/04/functors-monads-applicatives-different-implementations/

Friday, November 24, 2017

For comprehensions - Syntactic sugar for flatMap & map


Given the following definitions...


def getX = Option(List(3))

def getY = Option(List(5))


The below 2 computations are the same:


getX.flatMap(x => getY.map(y => x ++ y))



val z = for {
       x <- getX
       y <- getY

     } yield x ++ y


Value of z:



z: Option[List[Int]] = Some(List(3, 5))


Friday, September 01, 2017

Uniform Access Principle in Scala

The Uniform Access Principle basically states that the notation used to access the object's member should be the same independent of whether the member is a field or a method. Thus the developer can remain ignorant of the actual implementation.

The Scala compiler automatically adds the getter/setter methods for constructor arguments depending on the type qualifier.  

class Person(var name: String)

For the above class, the Scala compiler generates the following Java class which can be obtained after disassembling the Person.scala. You can clearly see that getter & setter methods have been added automatically 

$ javap -p Person.class 
Compiled from "Person.scala"
public class Person {
  private java.lang.String name;
  public java.lang.String name();
  public void name_$eq(java.lang.String);
  public Person(java.lang.String);
}

Note the special syntax for the setter which is suffixed with "_$eq". This allows the setter to be invoked when an assignment style syntax is employed:
  • If type = var, both getter/setter methods are added
  • if type = val, only getter is added
  • if no type is specified, neither getter/setter methods are added

val person1 = new Person("Alice")

println(person1.name) // The getter is invoked here implicitly here

person1.name = "Bob"  // The setter is invoked implicitly here

As is evident, the notation employed to access name field does NOT indicate whether the field is being accessed directly or the getter/setter method is being invoked. This is the Uniform Access Principle in action.

Pipeline operations - Scala v/s Java

In both Java & Scala, the pipeline operations are functional and do not modify the original collection.

In the below examples in the case of Java, the pipeline operations are working on streams which are evaluated lazily. 

Intermediate operations like map/filter do not actually execute immediately but just create a new stream which when traversed give the mapped/filtered output of the source stream.

Terminal operations like reduce/forEach cause the stream to be traversed to produce a result or side-effect.

In the below examples for Scala, the pipeline operations are operating on plain collections and hence execute eagerly unlike in the case of Java. However, in Scala, there are ways to run pipeline operations on streams.

(1) Foreach

Java

List<String> fruits = Arrays.asList("pear", "apple", "strawberry", "mango", "banana", "orange")
fruits.forEach(System.out::println)

Scala

val fruits = List("pear", "apple", "strawberry", "mango", "banana", "orange")
fruits.foreach(println)


(2) Map

Java

List<String> ufruits = fruits.stream().map(s -> s.toUpperCase()).collect(Collectors.toList())

or

List<String> ufruits = fruits.stream().map(String::toUpperCase).collect(Collectors.toList())

Scala

val ufruits = fruits.map(_.toUpperCase)


(3) Reduce

Java

Optional<String> allfruits = fruits.stream().reduce((s1,s2) -> s1 + "-" + s2)

Scala

val ufruits = fruits.reduce(_ + "-" + _)


(4) Filter

Java

List<String> selected = fruits.stream().filter(s -> s.startsWith("a")).collect(Collectors.toList())


Scala

val ufruits = fruits.filter(_.startsWith("a"))

Thursday, August 24, 2017

Functions in Scala

In addition to being functional, Scala is also object-oriented. Hence a function is also an object and can be used wherever a value can be used.

scala> val isEven = (n: Int) => n % 2 == 0
isEven: Int => Boolean = $$Lambda$1002/925024581@4cbc2e3b

scala> isEven(1)
res0: Boolean = false

scala> isEven(2)
res1: Boolean = true

Behind the scenes, each call to isEven(<n>) is being converted to isEven.apply(<n>)

Actually, the isEven function is of type trait Function1[-T, +R] where T = Int and R = Boolean.

Every function in Scala maps to one of the FunctionN traits where N = 0 to 22. Yes, there are only 23 of them which implies that the number of function arguments cannot exceed 22.

Now, why do we need these FunctionN trait definitions in first place?

As Scala allows functions to be defined outside of classes/objects and as Scala is statically typed and is OO implying that functions are objects as well, it becomes essential that functions have to a type. Hence the need for these FunctionN traits.

Also note that the FunctionN types are contravariant w.r.t arguments (T1, T2 etc.) and covariant w.r.t return types (R). This is ensure flexibility so as to conform to the subtyping rule that subtypes should be permissive in what they accept and restrictive in what they produce. For more about this, refer to this nice reddit post by balefrost.







Wednesday, August 16, 2017

Covariance & Contravariance in Java

Covariance

If the generic type's subtype relationship is the same as the type parameter T, then the generic type is covariant w.r.t type parameter T.

A is a subtype of B => Generic<A> is a subtype of Generic<B>

In order to define a generic type as covariant, the extends keyword is used which defines the upper bound.

Example:

public class Animal {}
public class Mammal extends Animal {}
public class Cat extends Mammal {}
public class Dog extends Mammal {}


List<Animal> animals = ...
List<Mammal> mammals = ...
List<Cat> cats = ...
List<Dog> dogs = ...

public void someFunc(List<? extends Mammal> mammals)
                                |
                                V
               Here 'extends' defines the upper-bound as Mammal

Covariants are producers 

New items cannot be added to covariants after their construction.
public void someFunc(List<? extends Mammal> mammals) {
    mammals.add(new Cat());  ==> Does not compile
    mammals.add(new Mammal()); ==> Does not compile
}
   
However, one can access the items from covariant types, like so...

public void someFunc(List<? extends Mammal> mammals) {
    Mammal m = mammals.get(0); ==> Compiles
}

Also, someFunc() can only accept List<Mammal> or it's subtypes. 

someFunc(cats); ==> Compiles
someFunc(mammals); ==> Compiles
someFunc(animals); => Does NOT compile


Contravariance

If the generic type's subtype relationship is the opposite of type parameter T, then the generic type is contravariant w.r.t type parameter T.

A is a subtype of B => Generic<B> is a subtype of Generic<A>

In order to define a generic type as contravariant, the super keyword is used which defines the lower bound.

Example:

public void someFunc(List<? super Mammal> animals)
                                |
                                V
               Here 'super' defines the lower-bound as Mammal

Contravariants are consumers 

New items can be added to contravariants after their construction.
public void someFunc(List<? super Mammal> animals) {
    animals.add(new Cat());  ==> Compiles 
                             ==> Adding a Cat compiles as the 
                                 lower bound does NOT apply to the 
                                 constituent type <?> but only to                                    the generic type List<?>
    animals.add(new Mammal()); ==> Compiles
}

However, one cannot access the items from contravariant types, like so...

public void someFunc(List<? super Mammal> animals) {
    Animal a = animals.get(0); ==> Does not compile
}

Also, someFunc() can only accept List<Mammal> or it's super types. 

someFunc(cats); => Does NOT compile
someFunc(dogs); => Does NOT compile
someFunc(mammals); ==> Compiles
someFunc(animals); ==> Compiles
someFunc(objects); ==> Compiles

Wednesday, April 12, 2017

Useful git aliases

alias ga='git add'
alias gp='git push'
alias gl='git log'
alias gs='git status'
alias gss='git status -s'
alias gd='git diff'
alias gdc='git diff --cached'
alias gcm='git commit -m'
alias gcam='git commit -am'
alias gb='git branch'
alias gco='git checkout'
alias gra='git remote add'
alias grr='git remote rm'
alias gpu='git pull'
alias gcl='git clone'
alias gundo='git clean -f; git checkout .'