“The computer was born to solve problems that did not exist before.”
Thursday, May 12, 2022
Inheritance
Inheritance
Inheritance is an important pillar of OOP(Object Oriented Programming). It is the mechanism in Scala by which one class is allowed to inherit the features(fields and methods) of another class.
Important terminology:
Super Class: The class whose features are inherited is known as superclass(or a base class or a parent class).
Sub Class: The class that inherits the other class is known as a subclass(or a derived class, extended class, or child class). The subclass can add its own fields and methods in addition to the superclass fields and methods.
Reusability: Inheritance supports the concept of “reusability”, i.e. when we want to create a new class and there is already a class that includes some of the code that we want, we can derive our new class from the existing class. By doing this, we are reusing the fields and methods of the existing class.
The keyword used for inheritance is extends.
Syntax:
classparent_class_nameextendschild_class_name{ // Methods and fields }
Type of inheritance
Below are the different types of inheritance which are supported by Scala.
Single Inheritance:In single inheritance, derived class inherits the features of one base class. In the image below, class A serves as a base class for the derived class B.
Multilevel Inheritance: In Multilevel Inheritance, a derived class will be inheriting a base class and as well as the derived class also act as the base class to another class. In the below image, class A serves as a base class for the derived class B, which in turn serves as a base class for the derived class C.
Hierarchical Inheritance: In Hierarchical Inheritance, one class serves as a superclass (base class) for more than one subclass. In the below image, class A serves as a base class for the derived classes B, C, and D.
Multiple Inheritance: In Multiple inheritance, one class can have more than one superclass and inherit features from all parent classes. Scala does not support multiple inheritance with classes, but it can be achieved by traits.
Hybrid Inheritance: It is a mix of two or more of the above types of inheritance. Since Scala doesn’t support multiple inheritance with classes, hybrid inheritance is also not possible with classes. In Scala, we can achieve hybrid inheritance only through traits.
Scala has both functions and methods and we use the terms method and function interchangeably with a minor difference. A Scala method is a part of a class that has a name, a signature, optionally some annotations, and some bytecode whereas a function in Scala is a complete object which can be assigned to a variable. In other words, a function, which is defined as a member of some object, is called a method.
Function Declarations
A Scala function declaration has the following form −
deffunctionName ([list of parameters]) : [returntype]
Methods are implicitly declared abstract if you don’t use the equals sign and the method body.
Function Definitions
A Scala function definition has the following form −
Syntax
deffunctionName ([list of parameters]) : [returntype] = { function body return [expr] }
Here, the return type could be any valid Scala data type and the list of parameters will be a list of variables separated by a comma and the list of parameters and return type are optional.
Calling Functions
Scala provides several syntactic variations for invoking methods. Following is the standard way to call a method −
functionName( list of parameters )
If a function is being called using an instance of the object, then we would use dot notation similar to Java as follows −
[instance.]functionName( list of parameters )
Closures
Scala Closures are functions which uses one or more free variables and the return value of this function is dependent of these variable. The free variables are defined outside of the Closure Function and are not included as a parameter of this function. So the difference between a closure function and a normal function is the free variable. A free variable is any kind of variable which is not defined within the function and not passed as the parameter of the function. A free variable is not bound to a function with a valid value. The function does not contain any values for the free variable.
Scala has only a handful of built-in control structures. The only control structures are if, while, for, try, match, and function calls. The reason Scala has so few is that it has included function literals since its inception. Instead of accumulating one higher-level control structure after another in the base syntax, Scala accumulates them in libraries.
1. If expressions
Scala's if works just like in many other languages. It tests a condition and then executes one of two code branches depending on whether the condition holds true. Here is a common example, written in an imperative style:
var filename = "default.txt" if (!args.isEmpty) filename = args(0)
This code declares a variable, filename, and initializes it to a default value. It then uses and if expression to check whether any arguments were supplied to the program. If so, it changes the variable to hold the value specified in the argument list. If no arguments were supplied, it leaves the variable set to the default value.
2. While loops
Scala's while loop behaves as in other languages. It has a condition and a body, and the body is executed over and over as long as the condition holds true.
example:
defgcdLoop(x: Long, y: Long): Long = { var a = x var b = y while (a != 0) { val temp = a a = b % a b = temp } b }
Scala also has a do-while loop. This works like the while loop except that it tests the condition after the loop body instead of before.
Below shows a Scala script that uses a do-while to echo lines read from the standard input until an empty line is entered:
var line = "" do { line = readLine() println("Read: "+ line) } while (line != "")
3. For expressions
Scala's for expression is a Swiss army knife of iteration. It lets you combine a few simple ingredients in different ways to express a wide variety of iterations. Simple uses enable common tasks such as iterating through a sequence of integers. More advanced expressions can iterate over multiple collections of different kinds, can filter out elements based on arbitrary conditions, and can produce new collections.
Iteration through collections
The simplest thing you can do is to iterate through all the elements of a collection.
For example, below shows some code that prints out all files in the current directory. The I/O is performed using the Java API. First, we create a java.io.File on the current directory, ".", and call its listFiles method. This method returns an array of File objects, one per directory and file contained in the current directory. We store the resulting array in the filesHere variable.
val filesHere = (new java.io.File(".")).listFiles for (file <- filesHere) println(file)
Filtering
Sometimes you do not want to iterate through a collection in its entirety. You want to filter it down to some subset. You can do this with a for expression by adding a filter: an if clause inside the for's parentheses.
For example, the code shown below lists only those files in the current directory whose names end with ".scala":
val filesHere = (new java.io.File(".")).listFiles
for (file <- filesHere if file.getName.endsWith(".scala")) println(file)
Nested iteration
If you add multiple <- clauses, you will get nested "loops." For example, the for expression shown below has two nested loops. The outer loop iterates through filesHere, and the inner loop iterates through fileLines(file) for any file that ends with .scala.
defgrep(pattern: String) = for ( file <- filesHere if file.getName.endsWith(".scala"); line <- fileLines(file) if line.trim.matches(pattern) ) println(file +": "+ line.trim)
grep(".*gcd.*")
Mid-stream variable bindings
Note that the previous code repeats the expression line.trim. This is a non-trivial computation, so you might want to only compute it once. You can do this by binding the result to a new variable using an equals sign (=). The bound variable is introduced and used just like a val, only with the val keyword left out.
Below shows an example.
defgrep(pattern: String) = for { file <- filesHere if file.getName.endsWith(".scala") line <- fileLines(file) trimmed = line.trim if trimmed.matches(pattern) } println(file +": "+ trimmed)
grep(".*gcd.*")
Producing a new collection
While all of the examples so far have operated on the iterated values and then forgotten them, you can also generate a value to remember for each iteration. To do so, you prefix the body of the for expression by the keyword yield. For example, here is a function that identifies the .scala files and stores them in an array:
defscalaFiles = for { file <- filesHere if file.getName.ends with(".scala") } yield file
Each time the body of the for expression executes it produces one value, in this case simply file. When the for expression completes, the result will include all of the yielded values contained in a single collection. The type of the resulting collection is based on the kind of collections processed in the iteration clauses. In this case, the result is an Array[File], because filesHere is an array and the type of the yielded expression is File.
4. Exception handling with try expressions
Scala's exceptions behave just like in many other languages. Instead of returning a value in the normal way, a method can terminate by throwing an exception. The method's caller can either catch and handle that exception, or it can itself simply terminate, in which case the exception propagates to the caller's caller. The exception propagates in this way, unwinding the call stack until a method handles it or there are no more methods left.
Throwing exceptions
Throwing an exception looks the same as in Java. You create an exception object and then you throw it with the throw keyword:
thrownewIllegalArgumentException
Catching exceptions
You catch exceptions using the syntax shown below. The syntax for catch clauses was chosen for its consistency with an important part of Scala: pattern matching. Pattern matching, a powerful feature.
try { val f = newFileReader("input.txt") // Use and close file } catch { case ex: FileNotFoundException => // Handle missing file case ex: IOException => // Handle other I/O error }
The finally clause
You can wrap an expression with a finally clause if you want to cause some code to execute no matter how the expression terminates. For example, you might want to be sure an open file gets closed even if a method exits by throwing an exception. Below shown an example.
import java.io.FileReader
val file = newFileReader("input.txt") try { // Use the file } finally { file.close() // Be sure to close the file }
Yielding a value
As with most other Scala control structures, try-catch-finally results in a value. For example, below shows how you can try to parse a URL but use a default value if the URL is badly formed. The result is that of the try clause if no exception is thrown, or the relevant catch clause if an exception is thrown and caught. If an exception is thrown but not caught, the expression has no result at all. The value computed in the finally clause, if there is one, is dropped. Usually, finally clauses do some kind of clean up such as closing a file; they should not normally change the value computed in the main body or a catch clause of the try.
Scala's match expression lets you select from several alternatives, just like switch statements in other languages. In general, a match expression lets you select using arbitrary patterns. For now, just consider using match to select among several alternatives.
As an example, the script below reads a food name from the argument list and prints a companion to that food. This match expression examines firstArg, which has been set to the first argument out of the argument list. If it is the string "salt", it prints "pepper", while if it is the string "chips", it prints "salsa", and so on. The default case is specified with an underscore (_), a wildcard symbol frequently used in Scala as a placeholder for a completely unknown value.
val firstArg = if (args.length > 0) args(0) else"" firstArg match { case"salt" => println("pepper") case"chips" => println("salsa") case"eggs" => println("bacon") case _ => println("huh?") }
32 bit signed value. Range -2147483648 to 2147483647
4
Long
64 bit signed value. -9223372036854775808 to 9223372036854775807
5
Float
32 bit IEEE 754 single-precision float
6
Double
64 bit IEEE 754 double-precision float
7
Char
16 bit unsigned Unicode character. Range from U+0000 to U+FFFF
8
String
A sequence of Chars
9
Boolean
Either the literal true or the literal false
10
Unit
Corresponds to no value
11
Null
null or empty reference
12
Nothing
The subtype of every other type; includes no values
13
Any
The supertype of any type; any object is of type Any
14
AnyRef
The supertype of any reference type
Operators:
An operator is a symbol that tells the compiler to perform specific mathematical or logical manipulations. Scala is rich in built-in operators and provides the following types of operators −
Arithmetic Operators
Relational Operators
Logical Operators
Bitwise Operators
Assignment Operators
→ Arithmetic Operators
The following arithmetic operators are supported by the Scala language.
Operator
Description
+
Adds two operands
-
Subtracts second operand from the first
*
Multiplies both operands
/
Divides numerator by de-numerator
%
Modulus operator finds the remainder after division of one number by another
→ Relational Operators
The following relational operators are supported by the Scala language
Operator
Description
==
Checks if the values of two operands are equal or not, if yes then the condition becomes true.
!=
Checks if the values of two operands are equal or not, if values are not equal then the condition becomes true.
>
Checks if the value of the left operand is greater than the value of the right operand, if yes then the condition becomes true.
<
Checks if the value of the left operand is less than the value of the right operand, if yes then the condition becomes true.
>=
Checks if the value of the left operand is greater than or equal to the value of the right operand, if yes then the condition becomes true.
<=
Checks if the value of the left operand is less than or equal to the value of the right operand, if yes then the condition becomes true.
→ Logical Operators
The following logical operators are supported by the Scala language.
Operator
Description
&&
It is called Logical AND operator. If both the operands are non zero then the condition becomes true.
||
It is called Logical OR Operator. If any of the two operands is non zero then the condition becomes true.
!
It is called Logical NOT Operator. Use to reverses the logical state of its operand. If a condition is true then the Logical NOT operator will make it false.
→ Bitwise Operators
Bitwise operator works on bits and performs bit by bit operation. The truth tables for &, |, and ^ are as follows −
p
q
p & q
p | q
p ^ q
0
0
0
0
0
0
1
0
1
1
1
1
1
1
0
1
0
0
1
1
Operator
Description
&
Binary AND Operator copies a bit to the result if it exists in both operands.
|
Binary OR Operator copies a bit if it exists in either operand.
^
Binary XOR Operator copies the bit if it is set in one operand but not both.
~
Binary Ones Complement Operator is unary and has the effect of 'flipping' bits.
<<
Binary Left Shift Operator. The bit positions of the value of the left operand are moved left by the number of bits specified by the right operand.
>>
Binary Right Shift Operator. The bit positions of the left operand value are moved right by the number of bits specified by the right operand.
>>>
Shift right zero-fill operator. The left operands value is moved right by the number of bits specified by the right operand and shifted values are filled up with zeros.
Assignment Operators
There are the following assignment operators supported by Scala language −
Operator
Description
=
Simple assignment operator, Assigns values from right side operands to left side operand
+=
Add AND assignment operator, It adds the right operand to the left operand and assigns the result to the left operand
-=
Subtract AND assignment operator, It subtracts right operand from the left operand and assigns the result to left operand
*=
Multiply AND assignment operator, It multiplies right operand with the left operand and assigns the result to the left operand
/=
Divide AND assignment operator, It divides left operand with the right operand and assigns the result to left operand
%=
Modulus AND assignment operator, It takes modulus using two operands and assign the result to the left operand