Note#1608 View (from Page#40 "Programming")
Created 2011-Mar-16. Updated 2018-Mar-17.

What I like about Scala

or How I Learned to Stop Worrying and Love the JVM environment

(google doc version - with colors in code examples)

A non boring-Java (and more):

At work I'm using Scala for all my new developments. It's a joy to use! A fast, concise and elegant general-purpose multi-paradigm programming language (object oriented, function oriented) providing seamless integration with Java, designed to scale from scripts to large complex applications.

image

  • Seamless integration with Java = low-risk adoption
  • multi-paradigm: object oriented and functional = expressive
  • less code = more readable = more productive
  • Multicore friendly = future proof

Used by LinkedIn, Twitter, Foursquare, UBS, EDF etc...

The scala language was created by Martin Odersky who also wrote the Java reference compiler and co-authored the Java generics. His implementation of the Scala compiler produces java bytecode that performs as good as comparable Java code.

As high level and concise as Ruby or Groovy but way faster and IDE friendly.

Trying to merge "the best" of object-oriented and functional languages; "the best" of agile (dynamic typing + lightweight syntax) and safe (static typing) / performant languages.

What I like in Scala - Highlights

Type inference

Scala has a non-annoying, non-verbose advanced static type system with type inference. Static enough to help safe refactoring and self documentation but without cluthering your code:

val txt = "bla" // "bla" is a String literal: so txt is a String...
val r   = new java.io.StringReader( txt )

// obviously in method definition, types should be declared:
def bar( msg:String ) = println( msg )
def foo( a:Int, b:Int ):Int = a + 4 * b
    // n.b. if the return type could be inferred from the last evaluated
    // expr. it can be omitted: def foo( a:Int, b:Int ) = a + 4 * b // ok
def filterEntry( f: Entry => Boolean ):List[ Entry ] = { ...
    // filterEntry takes function f - that should receive an Entry and
    // returns a Boolean - as an input param and returns a list of Entry

/* for parameters in passed function, type is also generally inferred
   ("target typing"): 4, 5, 6 are integer literals, so List( 4, 5, 6 ) is
   a factory generating an integer list, so reduceLeft ("accumulator"
   method) takes a function that will receive integers: x and tot can
   only be integer: no need to specify their type: */
List( 4, 5, 6 ).reduceLeft( ( tot, x ) => tot + x ) // = 15


Implicit type conversions

To extend libraries retroactively, without actually changing them (safer/cleaner than Ruby open classes). You define a new class which contains the desired method and define an implicit conversion from the target class to your new class:

// "adding" a =~ regexp match method to String:
// (java String#matches method works only on the whole string!
// and java String#contains doesn't use regexp)

class MyStr( str: String ) {
    def =~( re: String ): Boolean = {
         if ( re.r.findFirstMatchIn( str ) != None ) true else false
    }
}
implicit def String2MyStr( str: String ): MyStr = new MyStr( str )

/* every time the compiler found a String with an undefined method,
e.g. here =~ : it will look for the implicit method in the current scope that
has matching in/out types = takes a String and returns an object implementing
=~(). It will then ~inline the conversion method... */

"ABC66DE" =~ "\\\\d+" // will return true
// p.s. dots and parenthesis can be omitted (in some situations):
// is shorter than "ABC66DE".=~( "\\\\d+" ) and than
// new MyStr( "ABC66DE" ).=~( "\\\\d+" )


Function-as-first-class-values

In addition to being object oriented, Scala is function oriented: Functions can be passed as parameters to other functions/methods; functions/methods can return functions (n.b. cleaner than ruby where regular code blocks are not real objects / "values" = not real first-class citizens).

Higher-order function, Closures, Currying etc...

// Even simple collection processing functional methods can come in handy!

// Cleaning a string:
"ONCE 235354 upon A time".
    split( "\\\\s+" ).
    filterNot( _.matches( "\\\\d+" ) ).
    map( w => w( 0 ).toUpper + w.substring( 1 ).toLowerCase ).
    mkString( " " )
// will give "Once Upon A Time"

// partitioning:
val ages = List( 34, 56, 12, 44, 6, 65 )
val ( youngs, olds ) = ages partition ( _ < 26 )
// youngs: List[Int] = List(12, 6)
// olds: List[Int] = List(34, 56, 44, 65).
// closure, currying, partially applied function ...

import scala.util.matching._

class RegStr( str: String = "" ) {
    def xall( re: String )( f: List[String] => String ) = {
        // regex#replaceAllIn method wants a matcher function eating
        // Match objects: Embed passed f fonction eating
        // List( matched, subgroups* ) inside function of Match matcher_f,
        // that will be a proxy to use f with replaceAllIn
        val matcher_f = ( m: Regex.Match ) => f( m.matched :: m.subgroups )
        re.r.replaceAllIn( str, matcher_f )
    } // xall: a functional String replaceAll
}
implicit def string2Regstr( str: String ): RegStr = new RegStr( str )

"the quick brown fox".xall( """\\b(\\w)(\\w+)\\s*""" ) {
    hit => hit(1).toUpperCase + "."
} // gives: "T.Q.B.F."   // looks like language ctrl structure (... DSL)

// assigns a partially applied function (also a closure) to a value:
val tqbf = "the quick brown fox".xall( """\\b(\\w)(\\w+)\\s*""" )_

tqbf { ms => ms(1).toUpperCase + ms(2) } // "TheQuickBrownFox"
tqbf { ms => ms(1) + ms(2).toUpperCase } // "tHEqUICKbROWNfOX"
tqbf( _(1) ) // "tqbf"


Refinement types / Structural typing

In addition to the "classical" (class/trait) typing, you can "emulate" duck typing with Scala safer, more explicit structural typing feature:

// If it walks like a duck and quacks like a duck, we could call it a duck.
class Duck {
    def walk  = println( "flip flop" )
    def quack = println( "Quaaack!" )
}
class Person {
    def walk  = println( "Klop klop" )
    def quack = println( "imitating Quaaack!" )
}
// Handy to glue unrelated "external" classes by their abilities
def doTheDuck( duck: AnyRef{ def walk; def quack } ) = {
    // usually a param type is a Class/Interface, but could be method(s)
    // ("abilities"); here the type is AnyRef implementing walk and quack!
    duck.walk
    duck.quack
}
// def walkLikeDuck[ T <: AnyRef{ def walk; def quack } ]( duck: T ) = { ...

doTheDuck( new Duck ) // flip flop, Quaaack!
doTheDuck( new Person ) // Klop klop, imitating Quaaack!


Advanced pattern matching

Case classes - Allows to match (with "deep match" support and variable binding) on any sort of data, not only against integer types and enums like in Java switch/case-s - and Extractors:

// case classes:
case class B( a:String, b:String ) // just add a case modifier to the normal class definition
case class A( x:String, z:B )
val a = new A( "foo", new B( "*", "*" ) )

val ok = a match {
    case A( "foo", B( e, "+" ) )           => { println( e ); 1 }
    case A( "foo", b @ B( x, y ) ) if x==y => { println( b.toString ); 2 }
    case _ => 0
} // 2
    // tests if a is an A object constructed with "foo" and an object B
    // itself built with any value (put in variable e) and "+" or 2
    // identical values (2nd case)... Works via extractors (see below)
    // n.b. match/case-s return a value!

// pattern matching with extractors:
// n.b. like an object deconstructor / data extractor:

val A( str, b ) = a // equivalent to val( str, b) = A.unapply( a ).get
    // extracts data from a into str and b:
    // str = "foo" // extracts 1st field (x) of a:A object into str:String val
    //             // = instantiate and initialize str:String val to "foo"
    // b   = B( "*", "*" ) // extracts 2nd field (z) of a:A object into b:B val
    //                     // = instantiate and initialize b:B val to "foo"
val A( "foo", b ) = a
    // extracts 2nd field (z) of a:A object into b:B val, but only if 1st field
    // (x) of a:A object equals "foo" (if it doesn't match: will raise
    // scala.MatchError)
// n.b. this extractor works via the unapply method on the class A companion
//      object A (= like a static method). For "case" classes this method
//      (and companion) is ~auto generated, but extractors can be customized
//      (by defining unapply, unapplySeq static or/and instance! methods)
//      to do something different than just extracting object parameters,
//      see below regexp
// n.b. extractors can be used outside case classes (and be polymorphic)...

// with regexps: (sub groups extraction!)
val email_re = """^([\\w\\d\\-\\_\\.]+)(\\+\\d+)?@([\\w\\d\\-\\.]+)$""".r

val email_re( name, _, domain ) = "edouard.decastro@isb-sib.ch"
    // Regex extractor extracts matched groups into strings that can be
    // assigned together: define and initialize val name:String to
    // edouard.decastro and domain:String to isb-sib.ch

// a custom extractor:
// extracting multiple matches (full match and captured groups in a list of Strings)
// from a regex on a String :
// (instead of just captured groups on a String full match (default Regex extractor))
import scala.util.matching._
class RegMore( re:String ) {
    def unapplySeq( str:String ):Option[ List[ List[String] ] ]  = {
        Some( re.r.findAllIn( str ).matchData.toList
                      .map { m => m.matched :: m.subgroups } )
    }
}

val rem = new RegMore( """\\w(\\d+)""" )

val rem( a, b, _* ) = "foo54, bar18, baz, qux0"
// a: List[String] = List( "o54", "54")
// b: List[String] = List( "r18", "18")

// n.b. couldn't use implicit conversion (to "extend" Regex into RegMore) here...


etc...

Interactive console
Tuples (mixed type "collections" ... handy to return multiple values)
Default & named arguments
Traits ((partially) implemented interfaces)
Collections (rich, mutable + immutable versions)
Parser Combinators (built in domain specific "language" for executable grammars)
Abstract fields, and types
Option type
XML literals
Actors

Has a great web framework: Lift