(6) Scala Basics
About
:octocat: GitHub: All of the example code: repo (link)
:page_facing_up: blog link: https://purrgramming.life/cs/programming/fp/ :star:
What is OOP
Object-oriented programming can be defined as a programming model based upon the concept of objects. Objects contain data in the form of attributes and code in methods. It can be defined as a programming paradigm based on the concept of “objects”, which may contain data in the form of fields, often known as attributes, and code, in the form of procedures, often known as methods. For example, a person is an object with certain properties such as height, gender, age, etc. It also has certain methods such as moving, talking, etc.
OOP SOLID Rules
The SOLID
ideas are
- The Single-responsibility principle: "There should never be more than one reason for a class to change." In other words, every class should have only one responsibility.
- The Open–closed principle: "Software entities … should be open for extension, but closed for modification." i.e .creating software entities whose behaviour can be changed without the need to edit and recompile the code itself
- The Liskov substitution principle: "Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. i.e., a superclass object should be replaced with a subclass without breaking the software’s functionality.
- The Interface segregation principle: "Many client-specific interfaces are better than one general-purpose interface."
- The Dependency inversion principle: "Depend upon abstractions, concretions." i.e., high-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend on details. Details should depend upon abstractions
Benefits
- OOP models complex things as reproducible, simple structures
- Reusable, OOP objects can be used across programs
- Allows for class-specific behaviour through polymorphism
- Easier to debug, classes often contain all applicable information to them
-
Secure, protects information through encapsulation
image source: https://miro.medium.com/max/60/0*BzukazqM9J3wcK4J.png?q=20
Four Principles of OOP:
The four pillars of object-oriented programming are:
- Inheritance: child classes inherit data and behaviours from the parent class
- Encapsulation: containing information in an object, exposing only selected information
- Abstraction: only exposing high-level public methods for accessing an object
- Polymorphism: many methods can do the same task
Image source: https://geetikakaushik2020.medium.com/what-is-object-oriented-programming-7f14c5147ee5
Data Abstraction and Encapsulation
Data Abstraction
Data abstraction reduces a particular body of data to a simplified representation of the whole. Abstraction, in general, is the process of taking away or removing characteristics from something to reduce them to a set of essential characteristics.
There are multiple ways to achieve the functions/methods we implement. But clients observe exactly the same behaviour in each case. This ability to choose different data implementations without affecting clients is called data abstraction.
Encapsulation
In object-oriented programming (OOP), encapsulation refers to bundling data with the methods that operate on that data or the restricting of direct access to some of an object’s components.
Encapsulation is used to hide the values or state of a structured data object inside a class, preventing direct access to them by clients in a way that could expose hidden implementation details or violate state invariance maintained by the methods.
Data Abstraction vs. Encapsulation
Abstraction | Encapsulation |
---|---|
It solves an issue at the design level. | Encapsulation solves a problem at an implementation level. |
Hides the unnecessary detail but shows the essential information. | Hides the code and data so that the data can be protected/hidden. |
Focuses on the external lookout. | Focuses on internal working. |
Let’s focus on what an object does instead of how it does it. | Let’s focus on how an object does something. |
Use abstract classes and interfaces. | Use modifiers like private/protected etc. |
Preconditions and Assertions
Preconditions
Our Rational class requires that the denominator is not 0
. We can enforce this by calling the require
function.
class Rational(x: Int, y: Int):
require(y > 0, ”denominator cannot be 0”)
require
is a predefined function. It takes a condition and an optional message string.
If the condition passed to require is false
, an IllegalArgumentException is thrown with the given message string.
val illegal = Rational(4, 0) // Fails
// IllegalArgumentException: denom cannot be 0
Assertions
Besides require, there is also assert.
Assert also takes a condition and an optional message string as parameters. E.g.
val x = 5
assert(x >= 0)
assert(x < 0) // java.lang.AssertionError: assertion failed
Assertions vs. Preconditions
Exceptions
Like require
, a failing assert will also throw an exception, but it’s a different one:
AssertionError
for assert
, IllegalArgumentException
for
require
.
Motivations
This reflects a difference in intent
- require is used to enforce a precondition on the caller of a function.
- assert is used to check the code of the function itself.
Programs
Standalone Object
We can execute all Scala code from the REPL or the worksheet.
It is also possible to create standalone applications in Scala.
Each such application contains an object with the main method. For instance, here is the “Hello World!” program in Scala.
object HelloWorld {
def main(args: Array[String]): Unit = println("hello world !")
}
Once this program is compiled, you can start it from the command line with
> scala Hello
Or we can directly run it in the IDE.
hello world !
Process finished with exit code 0
@main Function
A stand-alone application is alternatively a function that’s annotated with @main
and that can take command line arguments as parameters:
@main def birthday() =
println(s"Happy birthday!")
Once this function is compiled, you can start it from the command line with
> scala birthday
Or we can directly run it in the IDE.
Happy birthday!
Process finished with exit code 0
Handling Exceptions
Scala’s exception handling is similar to Java’s.
The expression
throw Exc
Aborts evaluation with the exception Exc
.
The type of this expression is Nothing
.
Exceptions and Strings
For function
def f: String = throw Exception()
The compiler accepts this code because ‘throw Exception()’ extends ‘String’