Programming Scala, extract

You need a result type specified in case of recursive function

If function consist from just one statement, curly braces are not mandatory

 

“=” is a delimiter of signature and body of function

 

If method can be called with space instead of dot, “Obj.foo(10)” -> “Obj foo 10”, only of Obj is defined explicitly

 

Array – fixed length mutable container, List – fixed length immutable.

 

ListBuffer – mutable extendable list.

 

Nil – empty list

 

Empty parentheses at empty parameter list can be dropped, “obj.foo()” -> “obj.foo” or “obj foo”, if several parameters “obj foo (param1, param2)”

 

“return” keyword can be propped, last calculated value is returned

 

“Unit” result type is used in case not result type exist, similar to Java’s void, the only difference, it has a single value – ()

 

Singleton object can extend superclass and mix traits. But it is not possible to declare a variable of such type. No parameters are allowed for construction.

 

Companion object has an access to private members to its companion class and vice versa

 

To run scala program

object Main {

def main( args: Array[ String]) = {

//code is here

}

}

 

Or

 

object Main extends App

{

//Code here

}

 

Scala implicitly imports

Java.lang – package

scala – package

Predef – singleton

 

Class-name and file-name at scala are not mandatory equal, but recommended

 

scalac – compiler scans all jars each time when it is used, to speedup it, use daemon “fsc”

 

Basic types:

Integral: Byte, Short, Int, Long, Char

Numeric: Float, Double

Boolean

String (java.lang only this one, rest are from scala)

 

No octal numeric literals, only hex and dec.

For integrals default type is int, long can be created with “l/L” postfixed.

For numerics double is default, float created by “f/F”postfixed.

 

String interpolation s+$

val str1 = “sub”

val str2 = s”str $str1”

val i = 5

val str3 = s”str ${i*6}”

 

printf-type of interpolation f+$

raw interpolation

 

Operators: infix, prefix, postfix

Prefix “unary_-”, allowed only four:+ – ~ !

 

Postfix takes no parameters, no dot or parentheses

 

== is always value equality, reference equality with “eq” and “ne” functions for Java objects mapped to Scala objects only.

 

Operation precedence by first symbol

(special symbols)

* / %

+ –

:

= !

< >

&

^

|

(other letters)

(all assignments)

One exception, if operator ends with “=” and it is not a comparison (like), it is priority equals “=” operator

 

Rich wrappers

Byte -> scala.runtime.RichByte, and others, except String -> scala.collection.immutable.StringOps

 

override keyword prefixes method definition in case of overriding

 

Classes

class ClassName( classParameter: Int)

{

//Primary constructor body

}

 

Class parameters are instance private, fields (with a copy of class parameters) are used if needed more relaxed access level

If class parameter is prepended with val or var it is called parametric field, means it is simple class field, it can be additionally prepended with override, protected or private specificator.

 

Class preconditions – checks invariant

require(<boolean expression>) – it is like an assert, should be placed at primary constructor

 

Auxiliary constructors

def this(<parameters>) = {

this(parameters)

//body

}

 

Auxiliary constructor should invoke another constructor (auxiliary or primary) as a first instruction. So primary constructor called always once at the end.

 

Implicit conversion

implicit keyword prefixes method with one parameter (method’s name is not important) compiler will use it at number of cases, for instance for converting the parameter into class instance

 

if can return a value – as ternary Java operator

while and do-while return Unit

 

Assignment return unit value

 

For

val vr = for(x <- 0 until 4 intermidVar = x/2  if x == 2; y <- 0 until 4) yield x

common form

for(pattern1 <- expr pattern2 = expr if expr)

pattern1 <- expr – generator

pattern2 = expr – definition

if expr – filter

 

throw expression besides throwing, returns value of Nothing type

 

try{

// body

}

catch{

case ex: ExceptionType1 => //do something

case ex: ExceptionType2 => //do something

}

finally

{

//finally actions

}

 

Scala doesnt require to specify or handle checked exceptions

 

try-catch-finally can return a value, its a last computed line of try block or relevant catch block, or return statement of finally (with no return keyword finally returns Unit)

 

Nested scopes with variables will shadow variables from embraced scope with the same name (in Java it is forbidden)

 

Nested functions are allowed, they have an access to parameters of eclosing functions

 

Lambda

(parameter list) => {body to execute}

 

Placeholder _ – foreach _ parameter can appear at function body only once

 

Partially applied functions – bound variables

 

“funcName _” – produces function object with all parameters bound, actually it generates a class with “apply” method that takes all parameters of original function. In some cases (when function type is expected) it is possible just leave a name with no placeholder

 

val fooOneParamString = fooTwoParamIntAndString(1, _: String)

 

Is free variable from closure is changed after closure is created, closure sees these changes, opposite is true also, if closure changes free variable, it will be observed outside.

 

Free variables of closure live at heap (not at stack) so  can be accessed all the time closure exists

 

Variable arguments list

foo(i: Int *)

inside it can be iterated as it would be an array

To pass an array at such function it should be appended with “: _*” sequence.

foo(arr: _*)

 

Named arguments

foo(argName = argValue), can be at any order

 

Default function parameters

foo(i: Int = 10)

 

Tail recursion optimisation – is applied by compiler by default

 

Currying

foo(x: Int)(y: Int) – called foo(1)(2), if only one parameter provided – new function is returned, but placeholder should be postfixed, like foo(1)_

 

Curly braces can be used instead of round for any method, that accepts only one argument

 

By-name parameters allows to drop empty parameter list of function type, that is passed as a parameter to other function

 

foo( boo: ()=> Int ) -> foo( boo: => Int )

So it can be called

foo(()=>2+3) -> foo(2+3)

“2+3” – will be (or not) executed within foo body (it allows optionally to avoid side effects of 2+3 calculation), but in case of “foo(i: Int)” 2+3 will be executed before foo call.

 

Abstract classes

 

abstract class cl

{

def foo(i: Int): Boolean

}

 

Abstract class can have both abstract and concrete methods, abstract methods just doesnt have a body

 

Parameterless methods are used by conventions when they do not change state of a class, dont have side effects and do not depend on mutable state, to provide uniform access principle, to give client ability to access properties or fields at the same way

def foo : Int = 5

 

Empty-paren methods – for other cases, when state is changed

def foo : Int = //change state here

 

extends keyword – like at Java inherits one class from another

 

scala.AnyRef like java’s java.lang.Object

 

Fields and method can be overridden, as well as parameterless method can override and be overriden by field with the same name

 

Method and field at the same class could not have the same name, so they at the same namespace.

Java’s namespaces: fields, methods, types, packages

Scala’s namespaces: types (classes and traits),  values (methods, fields, packages, singletons)

 

Calling parent constructor

class Child extends Parent(/*arguments for parent class*/){/*body*/}

 

override specificator is mandatory when some concrete method is overridden, if it is an abstract method, override can be skept

 

final for methods and classes like at Java – no overrides are allowed

 

++ operation concatenates two arrays

 

scala.Any – common ancestor for any scala object, with methods:

final def = =( that: Any): Boolean

final def !=( that: Any): Boolean

def equals( that: Any): Boolean

def ##: Int

def hashCode: Int

def toString: String

 

There are two subtypes: AnyVal (for value types) and AnyRef (for rest reference types)

 

Value classes could not be created via new, since they are final and abstract

 

Value numeric types can be implicitly converted to bigger type, like Short -> Int

 

Null bottom type is subclass of any reference value, null its value, could not be assigned to value type

 

Nothing bottom type is subtype of any scala type, no value exists for it, because it is used in case of abnormal method termination, like exception

 

To create own value type, a few condition should be met

  1. Class should have only one class parameter (or val parametric field)
  2. it should contain only def-s inside
  3. Inheritance from value class is forbidden
  4. equals and hashCode should not be overridden

 

Trait can be extended by class (extends or with)

 

Traits like classes with two exceptions:

  1. Traits dont have class parameters
  2. super call in case of trait is bound dynamically (for class it is bound statically)

 

Stackable modifications

 

If you have an abstract class (abs) with method foo and concrete (con) class implementing it, you can create a trait

 

trait tr extends abs{

abstract override def foo(i : Int ) = { super.foo( 2 + i) }

}

 

and next to create a new class or instance

 

сlass new_con extends con with tr

 

val inst = new con with tr

 

The new class new_con will use method foo first goes into trait’s foo and in its turn it goes into foo of class con

 

if there are several traits mixed in, they are called from right to left

 

Linearization of inheritance hierarchy

Start from leftest class of trait that extend the class is defined, and move right, preserving at linear set of classes/traits only unique items, and finish the line with the class you are defined.

 

Two ways to include something into package

  1. place package <name1>.<name2>…. as a first instruction at file
  2. envelop code into block (blocks can be nested) package <name1>.<name2>{/*everything is here*/}

 

_root_ – top level package

 

import statement is used like at Java (_ instead of *) with addition:

  1. It can appear everywhere, not only at beginning of source file
  2. it can refer values (singleton or regular), not only packages of classes
  3. It is possible to import just a half of deep of nested packages, and reference a type with a rest of package names, in other words to import packages, not only final package items like types
  4. It is possible to hide or rename some imported items
  5. import packageName.{TypeName, …} – import only specified types
  6. import packageName.{TypeName=>NewTypeName,…} replace a name, like alias
  7. import packageName.{TypeName=>_ , _} import all except TypeName

 

private – like at Java

protected – more restrictive, it is accessed only from ancestors

public – there is no public specificator, all is treated as a public, except it is not marked as private or protected

 

Protection scope

private[scope] and protected[scope] – scope is a package, class or singleton name

private[this] – instance private

 

package object – one per package

 

package object Name{

//everything is here, it is package level

}

 

assert – assert(Boolean) or assert(Boolean, Explanation) throws AssertionError

assertions are enabled/disabled via JVM parameters -ea/-ed

 

Types operations

  1. v.isInstanceOf[Type] – checks a type
  2. v.asInstanceOf[Type] – casts to type

 

Scala uses runtime type erasure like a Java, except arrays, arrays saves a type for runtime

 

case classes

  1. Factory method with a name of the class  is added
  2. Class arguments are implicitly vals
  3. toString, equals, hashCode are automatically generated
  4. copy method is added, it allows to create a copy of object with options new value for any parameter/parameters

 

case class Item(i : Int, s : String, l : Long)

val res = Item(3, “wer”, 5) match {

case Item(_, v, 5) => v

}

 

match like switch, but with no breaks and it returns a value

val res = itemToCheck match {

сase value => expression

case _ => defaultExpression

}

 

Three kinds of patterns:

  1. v (any variable name) – bound variable, can be used at right side from =>, if it start with capital letter, scala check for constant value with such name, if not found or the first letter is not capital, it is considered as bound variable. If you need to have lower case variable not be considered as a bound variable, you can enclose it into back ticks (like `v`) or prepend with object identifier (like this.v or obj.v)
  2. 5 (any constant value) – value to match
  3. _ – any value, just to ignore a value

 

match differs from Java’s switch in:

  1. match is an expression, it returns a value
  2. there is no fall through
  3. If no case expression matched, exception MatchError is thrown

 

Constructor match pattern makes deep comparisons, means case TypeA(1, TypeB(3)), if you need a variable of TypeB in case of match, @ letter can be used, like case TypeA(1, v @ TypeB(3))

Sequence match patterns (for example for List, Arrays) like case List(, 2,_) – matches list with three elements with second matched 2. to ignore a length _* can be used as last element.

Tuple match pattern – case (x,y) => – matches any two element tuple

Typed match pattern – case m : Map[_,_] => it check also a real type of element, but type parameters of Map could not be checked, due to type erasure.

 

Pattern guard star with if and represents boolean expression, pattern matches if expression return true

 

If patterns overlap, compiler will complain

 

Sealed super-class cannot have other descendants than defined at the same file. If such classes are used at pattern matching, compiler will check that match covers all possible cases. It refers to class types, not to its parameters. Sealed class checks only match expressions mentioned all subclasses inherited from sealed one.

 

Two possible solution to avoid annoying warning: add “catch-all” match pattern or add an annotation like:

def describe( e: Expr): String = (e: @unchecked) match {

case Number(_) = > “a number”

case Var(_) = > “a variable”

}

 

Option type for optional value, can have two values, Some(x) or None.

 

More patterns

For tuples (length should match too)

val myTuple = (123, “abc”)

val (number, string) = myTuple

 

For lists (length should match too, if length is unknown, its better to use ::, like val n1 :: n2 :: _ = myList)

val myList = List(123, 456)

val List(number1, number2) = myList

 

For exact classes

val exp = new BinOp(“*”, Number( 5), Number( 1))

val BinOp( op, left, right) = exp

 

Cases sequence is a partial function (logically it is like a set of functions), it is function literal

val lambdaVal: Option[ Int] = > Int = {

case Some( x)  => x

case None = > 0

}

 

Each case is considered as function entry point, with parameters specified after case and body after =>.

 

def function = {

case Data( byte) = > sum + = byte

case GetChecksum( requester) = > val checksum = ~( sum & 0xFF) + 1 requester ! checksum

}

 

But it is just partially applied functions, if it is called with parameters with no matching expression – exception is thrown

 

There is special type for partially applied functions:

instead

val second: List[ Int] = > Int = { case x :: y :: _ = > y }

use

val second: PartialFunction[ List[ Int], Int] = { case x :: y :: _ = > y }

 

Compiler will not warn you that function is not defined for all possible parameters.

PartialFunction has a method “isDefinedAt” it is possible to check at runtime whether partial function is applied for particular parameter.

 

Patterns matching at for expression

for (( country, city) <- capitals)

println(” The capital of ” + country + ” is ” + city)

 

if a pattern doesn’t match a value assigned, it is just ignored

 

List type is covariant: if P – type of parent, C – type of child at inheritance hierarchy, than List[P] is a supertype of List[C].

 

Lists are linked lists, so length operation is quite expensive – O(n)

head and tail – O(1)

init and last – O(n)

length – O(n)

reverse

drop, take, splitAt

apply, indices

flatten

zip, unzip

toString mkString

iterator, toArray, copyToArray

map, flatMap, foreach

filter, partition, find, takeWhile, dropWhile, span

forall, exists

folding /: :\ – O(n) of left sequence

sortWith

List.apply

List.range

List.fill

List.tabulate

List.concat

 

obj.apply(x) method on object is used when just obj(x) is called.

 

ListBuffer is mutable object, better append operation (+=) or prepend (:+=)

ArrayBuffer – mutable Array

 

Set and Map implementations

scala.collection.immutable.EmptySet

scala.collection.immutable.Set1

scala.collection.immutable.Set4

scala.collection.immutable.HashSet

 

scala.collection.immutable.EmptyMap

scala.collection.immutable.Map1

scala.collection.immutable.Map4

scala.collection.immutable.HashMap

 

SortedMap and SortedSet – traits, implemented by TreeSet and TreeMap (Red-Black Tree) – only immutable

 

GettersSetters

 

class Time { var hour = 12 var minute = 0 }

 

actually looks like

 

class Time {

private[ this] var h = 12

private[ this] var m = 0

def hour: Int = h

def hour_ =( x: Int) = { h = x }

def minute: Int = m

def minute_ =( x: Int) = { m = x }

}

 

Field itself at expanded class is always private[this], but getters/setters has a visibility of field at original class

 

Fields of non-abstract classes should be initialized, as methods, if there is no meaningful initializer, _ (default value) can be used.

 

Private constructor

class Queue[ T] private ( private val leading: List[ T], private val trailing: List[ T] )

 

Covariant, Nonvariant (default), Contrvariant generic types

 

Arrays are covariant at Java, but type runtime checks that object has suitable types

 

Type bounds

Lower bound def enqueue[ U >: T]() – means U is supertype of T

Upper bound def enqueue[ U <: T]() – means U is subtype of T

 

trait AbstractTrait {

type T             //abstract type

def foo( x: T): T

val field1: T

var field2: T

}

 

class Impl extends AbstractTrait {

type T = Int

def foo( x: Int ) = x + x

val field1 = 1

var field2= field1

}

 

def can be overridden with val but  not vice vers

trait tr{

val i : Int

}

val t = new tr {

val i: Int = 1

}

 

if a field is initialized with an expression, in case of abstract val – expression is evaluated after constructor, in opposite to class parameters (new cl(param1)) which is evaluated before constructor

 

abstract var is represented only with abstract getter and setter, no field itself, it comes at implementation only

 

Pre-initialized fields – allows to initialize fields of child class before parent class constructor is called (in case these fields are used at parent constructor it is important) – just to put them within curly brackets between new and type name. It is not possible to refer itselfs with this, this would mean a wrapping class, not the constructed one.

 

class Concrete( n: String) extends {
val field = n
}
with TraitWithN {
//rest of concrete class
}

 

if a lazy modifier is prepended to val – the field will be evaluated at place it is used at first time

 

Refinement types – ????

 

Enumerations are implemented as scala.Enumeration type

object Direction extends Enumeration { val Left, Right= Value }

Value – internal class of Enumeration, optionally can accept a string parameter

 

Implicit conversions

Rules:

  1. implicit keyword should prepend implicit conversion item (function or class)
  2. implicit conversion item name (function or class) should be accessible with no qualifiers (path) as one word, there is only one exception – companion object can contain implicit conversion item and it is also observed by compiler
  3. Only one implicit conversion is applied
  4. If code works with no expression, no expression is applied

 

Name of implicit conversion is important in two cases:

  1. If conversion is called explicitly, for debug purposes
  2. If two conversions are available at some scope and you need to import only one

 

When implicit conversion are applied:

  1. when some type is expected, but other is provided, implicit def int2string( x: Int): String = x.toString
  2. converting receiver, when some method called on object that doesn’t have it, implicit conversion can convert it into other object that have it. There are implicit methods and implicit classes for this purpose. Class has a constructor that accept a initial type, and contains a method that is expected.
  3. When parameters are expected, that nearest variable with corresponding type is used

 

Scala collection hierarchy

Traversable

Iterable

Seq

IndexedSeq

Vector

ResizableArray

GenericArray

LinearSeq

MutableList

List

Stream

Buffer

ListBuffer

ArrayBuffer

Set

SortedSet

TreeSet

HashSet (mutable)

LinkedHashSet

HashSet (immutable)

BitSet

EmptySet, Set1, Set2, Set3, Set4

Map

SortedMap

TreeMap

HashMap (mutable)

LinkedHashMap (mutable)

HashMap (immutable)

EmptyMap, Map1, Map2, Map3, Map4

 

Constructing a stream

val str = 1 #:: 2 #:: 3 #:: Stream.empty

 

Vector have a constant access time to any its part (slower than head access to list, but still constant – lists are quick only for accessing beginning)

Vector is represented by tree, with 32 nodes

Vectors are immutable

 

Stack, Queue, BitSet – immutable

 

ArrayBuffer, ListBuffer, StringBuilder, LinkedList, DoubleLinkedList, MutableList (has pointer to begin and to end), Queue, Array, Stack, ArrayStack, HashMap, WeakHashMap (references from this map to contained objects are not tracked by GC), ConcurrentMap, BitSet, String – are mutable

 

Equality of containers – three categories: sequence, map, set. Containers from different category are always inequal. From the same – equal if contains the same elements (for sequence order should be the same). Mutability doesn’t matter.

 

View represents some collections lazily (view method) or strictly (force method)

 

BufferedIterator – look ahead

 

Convert collections between scala and java – import collection.mutable._ – implicit conversions there

 

Extractor – is an object with unapply method, it is opposite to appy. unapply take an object and returns its parts as Some(tuple of parts), or None. It can be zero or one variable, since there is no one element tuple, just option of value is returned in case of single element.

It is possible to pass a value of other type, not the one is defined as a single parameter of unapply method, but, the value should be castable to expected parameter type.

If a number return parameters of unapply method is not defined, means a sequence can be returned, such method should be called unapplySeq and return Option[Seq[T]]

 

Regular expressions are build over scala.util.matching.Regex type in form:

  • regex findFirstIn str
  • regex findAllIn str
  • regex findPrefixOf str

 

Annotations

  • @deprecated
  • @volatile
  • @serializable, @transient
  • @scala.reflect.BeanProperty
  • @tailrec
  • @unchecked
  • @native
  • @throws – emulating java’s throws exception list

 

XML

XML literal – just open a tag and write valid XML – it will be considered as scala.xml.Elem type.

Other types: Node, Text, NodeSeq

 

To serialize some object into XML, class should contain toXML method, for deserialization – fromXML, accepting scala.xml.Node and returning instance of the class itself.

 

Node object can be used at pattern matching, _* – means any sequence of nodes.

 

Advertisements

About DmitryKrinitsyn
Software developer and muay thai adept

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: