Learning Scala: Abstractions, Types, and Expressions

This is Scala!")Output:Hello, World!This is Scala!Type Casting: Type casting is a way to convert a variable from one data type to another data type.

In Scala, value types can be cast in the following way.

Example:scala> val a:Int = 100a: Int = 100scala> val B:Float = aB: Float = 100.

0scala> val c:Char = 'a'c: Char = ascala> val d:Int = cd: Int = 97Data Abstraction in the LanguageData abstraction aims to provide a simplified representation or result of a more complex system.

The ultimate goal being that you can focus on the data without having to worry about the behavior that brought it to you.

This data abstraction can have many different layers.

We will explore some of the ways Scala implements this paradigm as part of the language itself, as well as an example of how to build a system that provides data abstraction.

Type InterfaceA common feature in functional programming languages is Type Interface.

This is a form of automatic detection where you do not have to explicitly declare the data type for your variables.

While simple and very obvious if you have experience across different languages, for newcomers it will be helpful to note that:val u:Int = 4315val v:String = "Languages and Paradigms"andval x = 4315val y = "Languages and Paradigms"both produce the same result.

The compiler will infer the types, Int and String respectively, based on their usage within the code.

Though it is common to see type declaration if it will help in code readability.

There are also notable examples exempt from this type of detection such as function parameters and the return type of recursive functions.

//This function requires declaration for the parameter xdef postViews(x: Int):String = "This post has %d views".

format(x)Implementing your own abstractionNote: The example presented here is not unique to Scala and can be translated to most other object oriented languages to suit your needs.

It illustrates how you can use abstraction to present your target audience with the most relevant information.

Suppose that you are working on a math project and you want to provide support for operations on rational numbers.

You would need to define a set of functions (add, subtract, divide, multiply, etc) and provide variables representing your numerators and denominators respectively.

So we start by creating a class that will, in the end, suit the needs of our operations while encapsulating away some of the most intricate parts of it.

class Rational(x: Int, y: Int) { def numerator :Int = x def denominator :Int = y}You could then create objects that have a numerator and denominator member and then manipulate those members for your operations.

But there is a perfect opportunity to abstract away another layer.

All the operations themselves can be written as methods of the classclass Rational(x: Int, y:Int) { def numerator :Int = x def denominator :Int = y def add(r: Rational) = new Rational(numerator * r.

denominator + r.

numerator * denominator, denominator * r.

denominator) def multiply(r: Rational) = // .

def divide(r: Rational) = // .

}Now, for the results of these operations to be useful we would expect that we are given the simplified version of the rational number which means we are going to need to calculate the Greatest Common Divisor.

Take a look at the following examples:class Rational(x: Int, y:Int) { private def gcd(a: Int, b: Int) : Int = if (b == 0) a else gcd(b, a % b) private val g = gcd(x, y) def numerator :Int = x def denominator :Int = y // .

}The computation and resulting number are kept isolated within each object of the class itself and nothing else has access to it.

Use the variable for gcd when constructing the numerator and denominator.

class Rational(x: Int, y:Int) { private def gcd(a: Int, b: Int) : Int = if (b == 0) a else gcd(b, a % b) def numerator :Int = x / gcd(x, y) def denominator :Int = y / gcd(x, y) // .

}This variation uses the calculation directly when creating the numerator and denominator.

If there will be no need to use the gcd anywhere else you can keep this implementation.

class Rational(x: Int, y:Int) { private def gcd(a: Int, b: Int) : Int = if (b == 0) a else gcd(b, a % b) val numerator :Int = x / gcd(x, y) val denominator :Int = y / gcd(x, y) // .

}Finally declaring the numerator and denominator as val will ensure they are only computed once.

The end result here is that no matter the implementation you choose, your rational number will be presented in its simplified form.

You have abstracted away the inner workings of constructing a rational number and provided just the desired resulting data to your user.

ExpressionsExpressions are an important tool in programming as they allow the developer to create arithmetic using operations and identifiers in a specific order to serve a unique purpose.

Scala like many other languages includes various techniques for constructing expressions including assignment, conditions, functions, operator precedence, and much more.

Operator PrecedenceOperator precedence in Scala are based on the first character, which is to say these are infix operators.

The order of precedence is listed below in increasing order of precedence.

So, we can say that * will be evaluated before + (similar to mathematics) by the order of precedence.

There is one exception to this table, which are assignment operators.

The assignment operator (=) has the lowest precedence and is evaluated last.

The associativity of an operator is determined by its last character where ‘:’ is right associative while all others are left associative.

AssignmentsLike with other languages, simple and argument expressions are assigned to a variable depending on the definition.

Additionally in Scala, an expression can be assigned to a function which is interpreted as an invocation of the core language ‘update’ function.

There are however, various expressions that can be assigned not common in popular languages.

This creates programming techniques focused around expressions known as Expression Oriented Programming.

Expression Oriented ProgrammingScala is a unique language for its design on Expression Oriented Programming where every (or nearly every) construction is an expression and thus yields a value.

So, where you’d often use a statement, you may use as an expression to create cleaner, more readable code.

Similar to the conditional operator in many languages, Scala’s if statement returns a value so you can change:var max = Int.

MinValueif(a > b) max = aelse max = bintoval max = if(a > b) a else bIn a switch case scenario, Scala’s match expressions also return a value so you can change:max match { case 10 => t = "Ten" case _ => t = "Not Ten"}into the following:var t = max match { case 10 => "Ten" case _ => "Not Ten"}Notice the match expression is assigned to variable t.

(Side note: The underscore is Scala’s version of default).

Even try catch statements are expressions which return a value so you can create:val result = try { "1".

toInt} catch { case _ => 0}There are many more various statements which return values not common to other languages and can be utilized for quick, concise programming.

To find more examples and structure for using statements as expressions, check out Scala Expressions.

Loop ExpressionsFor loop expressions in Scala operate much differently than many other languages, where for loops may contain generators, filters, and definitions which can yield a result.

Here is a simple example:val numbers = List(5,12,7,23,16,3,9,0)val evens = for { currentNum <- numbers if(currentNum % 2 == 0)} yield currentNumWhere the result of the for loop assigned to ‘evens’ is a List of even numbers from ‘numbers’.

‘currentNum <- numbers’ is a generator where we can create a pattern out of an expression, that pattern is then tested with the filter ‘if(currentNum % 2 == 0)’ to yield a new list.

FunctionsFunctions can be used as an expression to be assigned or operated upon as well.

Value functions are defined in at least two forms with the biggest distinction being whether you want the return type to be specified (explicit) or let the compiler infer it (implicit).

val max:(Int, Int) => Int=(a,b) => { if(a > b) a else b } //Explicitval max = (a : Int, b : Int) => { if(a > b) a else b } //ImplicitBoth forms assign value max with an anonymous function definition expression giving the result specified by the function and other expressions involved.

This allows you to create complex arithmetic with functions unique to specified values as to avoid unnecessary usage elsewhere and maintain clear, concise code.

Authors:Tyler Remmie @TylerRemmieDan Martinez @DanielMartinezAbdul Asif @AbdulAsifColby KuhnelHuy Nguyen @HuyNguyen.

. More details

Leave a Reply