Scala & Functional Programming

Based on Martin Odersky's course. Cards will be updated gradually :-)

184 flashcards · Programming Languages · by claudehsu

  1. Primitive types of Scala are as in Java. What's the difference between the two?

    Primitive types in Scala are written in capitalized form.

  2. The evaluation order of a non-primitive expression is ? ? ? One example is def pi = 3.14159 def radius = 10 (2 * pi) * radius // what's the evaluation process of (2 * pi) * radius?

    The leftmost operator Operands, left before right Apply the operator to the operands // evaluation process of (2 * pi) * radius (2 * 3.14159) * radius 6.28318 * radius 6.28318 * 10 62.8318

  3. What's the evaluation order of a function invocation with parameters? ? ?

    Evaluate all function arguments, from left to right Replace function application by the function's right-hand side(function body), and at the same time, replace the formal parameters by the actual arguments

  4. Given def square(x: Int): Int = x*x def sumOfSquares(a: Int, b: Int): Int = square(a) + square(b) What's the evaluation process of sumOfSquares(3, 2+2)? Answer: sumOfSquares(3, 2+2) sumOfSquares(3, 4) square(3) + square(4) 3*3 + square(4) 9 + square(4) 9 + 4*4 9 + 16 25

  5. What are the two evaluation strategies? call-by-value: applicative order call-by-name: normal order

  6. Do AOE and NOE always reduce to the same final result?

    No, two conditions need to be met to ensure AOE and NOE reduce to the same result the expression to be reduced consists of pure functions both evaluations terminate

  7. Given a function as def double(x: Int, y: Int): Int = x * 2 If NOE is used, what's the evaluation process of expression double(2+3, 3*4)? double(2+3, 3*4) (2+3)*2 5*2 10

  8. Figure out one example that AOE and NOE reduce to different results.

    non-pure function case import scala.util.Random def dummyZeroAOE(x: Int) = x - x def dummyZeroNOE(x: => Int) = x- x @main def main = val random = new Random() val rAOE = dummyZeroAOE(random.nextInt(10)) val rNOE = dummyZeroNOE(random.nextInt(10)) println(s"$rAOE, $rNOE") not terminate case def loop: Int = loop // parameterless def firstAOE(fst: Int, scd: Int) = if true then fst else scd def firstNOE(fst: Int, scd: => Int) = if true then fst else scd @main def main = // AOE version causes infini…

  9. What's the advantage of AOE and NOE respectively when reducing function calls with parameters?

    AOE: evaluates every function argument only once NOE: no need to evaluate unused function argument

  10. What's the default evaluation strategy of Scala? How to use the other strategy?

    The default eval strategy is AOE. To use NOE For function parameters: use arrow symbol like def func(x: => Int) For variables: use def keyword instead of val (indeed, def actually means a function definition)

  11. In Java, if ... else ... are statements, what's the corresponding 'entity' in Scala? if... then ... else... What exactly is it? An expression

  12. What is short-circuit evaluation? Does Scala support it?

    Expressions like expr1 && expr2, expr1 || expr2, and etc. don't need to be fulled evaluated. false && expr -> false true || expr -> true: so that true || loop will terminate Scala supports short-circuit eval

  13. Regarding to Block in Scala How to denote a block? What essentially is a block? Does a block have a return value? Is there any syntax sugar for block?

    To denote a block in Scala Use curly braces A block is essentially An expression The return value of a block is The value of the last expression The syntactic sugar is to use 2-space indentation instead of using curly braces after =, then, else and in some other places

  14. What's the lexical scope rule of blocks, especially considering things defined inside and outside of the block?

    Definitions inside the block: only visible in the block, not outside the block Definitions outside the block: visible from within the block, and get shadowed by the same name in the block @main def main = { val dogA = "Liyu" val dogB = "Jenis" val meaninglessRs = { val dogA = "Vicky" println(s"DogA: $dogA\t\t\tDogB: $dogB") } println(s"DogA: $dogA\t\t\tDogB: $dogB") } Note In the inner block, `dogA`="Vicky" shadows the "Liyu" defined in the outer block

  15. Below is the Uclid's method to implement the gcd function, calculating the greatest common divisor. def gcd(a: Int, b: Int): Int = if b == 0 then a else gcd(b, a % b) Is it a tail recursion? If not, change it to tail recursion. What's the benefit of tail recursion?

    Yes, that is tail recursion, bc the recursive call is not contained in another 'bigger' expression. The benefit of tail recursion is that it will not increase the call stack, so stack overflow is unlikely to happen.

  16. Which annotation can be used to indicate tail recursion in Scala? Answer: @tailrec What's the corresponding import? Answer: import scala.annotation.tailrec

  17. If the @tailrec is omiited for a tail recursive function, will the Scala compiler add that annotation for us?

    Yes, the compiler will do that. But explicitly pointing that out can remind us the intention of tail recursion.

  18. Below is the classical implementation of factorial calculation. def factorial(n: Int): Int = if n == 0 then 1 else n * factorial(n-1) Is above implementation tail recursion? If not, improve it to tail recursion.

    No, that's not tail recursion, bc in the else branch, the recursive call is inside another 'bigger' expression. Improve it to tail recursion as def factorial(n: Int): Int = def factCalc(n: Int, accVal: Int): Int = if n == 0 then accVal else factCalc(n-1, n*accVal) factCalc(n, 1)

  19. What is a Higher Order Function?

    A function that takes another function as parameter, or it returns another function as return value.

  20. Define an anonymous function to calculate the square value as below. x: Int => x*x Is that correct?

    No, it is not correct. Without parameters being enclosed by the parentheses, compilation error will happen. So the correct one is (x: Int) => x * x

  21. Anonymous function is aka function literal. One anonymous function to double the number can be defined as below (x: Int) => 2 * x What if we provide the return type like below? (x: Int) : Int => 2 * x

    An error will happen scala> (x: Int): Int => 2 * x -- Error: ---------------------------------------------------------------------- 1 |(x: Int): Int => 2 * x |^^^^^^^^^^^^^ |not a legal formal parameter for a function literal The return type of the anonymous function should not be explicitly denoted. Instead it is inferenced.

  22. Which of the following is correct? scala> def dbl1 = (x: Int) => 2 * x scala> val dbl2 = (x: Int) => 2 * x scala> def dbl3(x: Int) = 2 * x

    All of the three are correct scala> def dbl1 = (x: Int) => 2 * x def dbl1: Int => Int scala> val dbl2 = (x: Int) => 2 * x val dbl2: Int => Int = Lambda/0x000002cb014c0400@4db46344 scala> def dbl3(x: Int) = 2 * x def dbl3(x: Int): Int dbl1 is of type Int => Int and it's by-name evaluation, so no value is actually assigned. dbl2 is also of type Int => Int, but it's by-value evaluation, so actual value is evaluated and assigned dbl3 is a regular function definition. The response string is differen…

  23. In a Higher Order Function, functions can be input parameters. Suppose a mapReduce function has below parameters list map: a function mapping one Int to another Int reduce: a function reducing two Ints to one Int baseValue: the base(init) Int value of map reduce lowerBound and upperBound: the range of the numbers How to define the parameter type of the function? def mapReduce(map: Int => Int) (reduce: (Int, Int) => Int) (baseValue: Int) (lowerBound: Int, upperBound: Int) = ...

  24. We'd like to define a sum function that calculates the summation of a few numbers populated by applying a function to a range of numbers, such as sum of square from 2 to 5, or sum of doubled numbers from 3 to 5. Below are three definitions. def sum(func: Int => Int, lowerBound: Int, upperBound: Int): Int = ... def sum(func: Int => Int): (Int, Int) => Int = ... def sum(func: Int => Int) (lowerBound: Int, upperBound: Int) : Int = ... Which one is correct? What's the difference among them?

    All of the three are correct, but they mean different things 1st: a function defined with three parameters and the return value is of type Int 2nd: a function defined with one parameter and the return value is of type (Int, Int) => Int 3rd: similar to 2nd, but it follows a better syntax to support currying. The return type of 3rd is Int, not like 2nd.

  25. In Scala, in regard to function currying import scala.annotation.tailrec @tailrec def sum(func: Int => Int) (lowerBound: Int, upperBound: Int, baseVal: Int) : Int = if lowerBound > upperBound then baseVal else sum(func) (lowerBound + 1, upperBound, baseVal+func(lowerBound)) Is it possible to do partial application or we have to provide the full parameters lists?

    Both are supported We can provide full arguments list like sum(x => x*x) (2, 5, 0) to get the final summation value Alternatively we can do partial application. def sumOfSquare = sum((x: Int) => x*x); sumOfSquare(2, 5, 0)

  26. Provide implement of map reduce regular resursive version tail resursive version

    def mapReduce(map: Int => Int) (reduce: (Int, Int) => Int) (baseValue: Int) (lowerBound: Int, upperBound: Int) : Int= if lowerBound > upperBound then baseValue else reduce(map(lowerBound), mapReduce(map) (reduce) (baseValue) (lowerBound+1, upperBound)) scala> mapReduce((x) => x*x*x) ((a, b) => a + b) (0) (2, 5) val res7: Int = 224 # If you don't like the baseValue def mapReduce(map: Int=>Int)(reduce: (Int, Int)=>Int)(lowerBound:Int, upperBound:Int):Int={ if lowerBound==upperBound then map(lower…

  27. To represent a rational number, we can use two parts: numerator and denominator. A function to calculate the summation of two rational numbers can be def addRational(numerLeft: Int, denomLeft: Int, numerRight: Int, denomRight: Int) = ... Managing four parameters is a little challenging. How to improve above implementation? Hit: consider data abstraction.

    We can define a class to represent rational number class Rational(numer: Int, denom: Int): def numerator = numer def denominator = denom

  28. A rational number can be represented as numerator / denominator. Below is the implementation of Rational class class Rational(x: Int, y: Int): // don't forget the colon here def numer = x def denom = y How to access the member of an instance? @main def main = val r1 = new Rational(1, 2) // new can be omitted println(s"${r1.numer} / ${r1.denom}")

  29. Here is the implementation of Rational class class Rational(x: Int, y: Int): def numer = x def denom = y Add the toString function override def toString(): String = s"$numer/$denom"

  30. Below is the implementation of Rational class class Rational(x: Int, y:Int): private def gcd(a: Int, b: Int):Int = if b == 0 then a else gcd(b, a%b) private val g = gcd(x, y) def numer = x / g def denom = y / g Fill in the blanks. Note the gcd method and value g are only used inside Rational class.

  31. Given class Rational(x: Int, y:Int): private def gcd(a: Int, b: Int):Int = if b == 0 then a else gcd(b, a%b) We can define numerator and denominator as def numer = x / gcd(x, y) def denom = y / gcd(x,y) or as val numer = x / gcd(x,y) val denom = y / gcd(x,y) No matter which one is used, client programmers don't need to know the details of the implementation. This is called data abstraction.

  32. Inside of a class, how to reference to the 'current' object itself? For example class Rational(x: Int, y:Int): private def gcd(a: Int, b: Int): Int = if b == 0 then a else gcd(b, a % b) def numer = x / gcd(x, y) def denom = y / gcd(x, y) def less(that: Rational): Boolean = this.numer * that.denom < that.numer * this.denom

  33. In the Rational class case, how to ensure to construct objects with the condition that the denominator must be positive numbers. class Rational(x: Int, y: Int): require( y>0, "denominator must be positive") If we provide a negative denominator, which exception will be thrown? Answer: IllegalArgumentException

  34. Regarding to `assert` What's the syntax of using `assert` ? It seems to be similar to `require`. What's the difference between them? Write examples of using `assert` and `require`

    What's the syntax of using `assert` ? assert(condition, message) What's the difference between `assert` and `require`? require: enforce a precondition on the caller side, and it throws IllegalArgumentException to indicate there are issues with the arguments. assert: like a check point in the function, and it throws AssertionError when the condition doesn't meet. An example of `assert` scala> val dog = "Liyu" val dog: String = Liyu scala> assert(dog == "Jenis", s"Dog is supposed to be Jenis, but…

  35. In Scala, a class implicitly introduces a primary constructor. class Rational(x: Int, y: Int): ... To define an auxiliary constructor, we do class Rational(x: Int, y: Int) def this(x: Int) = this(x, 1)

  36. What is the end marker for?

    When code of a class or a control structure gets long, we use end marker to indicate the end of that section. For example, we can use end marker with class if then else extension etc. Some use cases are like below class Rational(x: Int, y:Int): def numer = x def denom = y def addRational(that: Rational) = Rational(this.numer*that.denom+that.numer*this.denom, this.denom*that.denom) end addRational end Rational

  37. Extend the computation mode, which is based on substitution, to instantiation of a class. Think about how C(a1, ..., am) is evaluated.

    The evaluation process of creating an instance is similar to the evaluation process of making a function call. In the C(a1, ..., am) case, we evaluate the arguments before constructing the object, just as evaluating the arguments first when calling the function.

  38. Given below definition class C(x1, ..., xm) {... def f(y1, ..., yn) = b ...} How is the following expression evaluated? C(v1, ..., vm).f(w1, ..., wn)

    There are mainly three substitution one for class parameter v1 to vm --> x1 to xm another for the constructed class instance C(v1, ..., vm) --> this(implicit this) in method body b the third for function parameter of f w1 to wn --> y1 to yn [w1/y1, ..., wn/yn][v1/x1, ..., vm/xm][C(v1, ..., vm)/this]b

  39. Analyze the substitution of below expression Rational(1,2).less(Rational(2,3))

    [1/n, 2/d] [Rational(2,3)/that] [Rational(1,2)/this] body: this.numer * that.denom < that.numer * this.denom = Rational(1,2).numer*Rational(2,3).denom<Rational(2,3).numer*Rational(1,2).denom --> 1 * 3 < 2 * 2 --> true

  40. Technically we can define all the methods in a class, which may lead to a 'huge' class. That seems not very modular. How to improve that? Provide some examples with below class class Rational(x: Int, y:Int): private def gcd(a: Int, b: Int): Int = if b == 0 then a else gcd(b, a % b) def numer = x / gcd(x, y) def denom = y / gcd(x, y) def less(that: Rational): Boolean = this.numer * that.denom < that.numer * this.denom def max(that: Rational): Rational = if this.less(that) then that else this

    We can utilize extension. If some methods do not need to access internals of a class, we can alternatively define them as extension methods. Examples can be min method to return the smaller one of two Rational numbers abs method to return the absolute value of a Rational number. extension (r: Rational) def min(s: Rational) = if r.less(s) then r else s def abs = Rational(r.numer.abs, r.denom.abs) end extension

  41. Is it possible for different people to define their own extensions in different modules, so that they may have their own versions of enhancement on a class?

    Yes. That is possible.

  42. When is an extension visible?

    Extensions of a class are visible if they are listed in the companion object of a class or if they are defined or imported in the current scope Below is an example of defining the extension in the companion object class Rational(numer: Int, denom: Int): private def gcd(a: Int, b: Int):Int = if b==0 then a else gcd(b, a%b) private val divisor = gcd(numer, denom) val numerator = numer/divisor val denominator = denom / divisor override def toString = s"$numerator/$denominator" object Rational{ ext…

  43. Are we allowed to define function/method with name such as + and <?

    Yes. Operators such as + and < are counted as identifiers in Scala, so they can be used as function/method names.

  44. In Scala, there are two types of identifier. What are they?

    Alpahnumeric: starting with a letter, followed by a sequence of letters or numbers. _ underscore character is counted as a letter Symbolic: starting with an operator symbol, folowed by other operator symbols.

  45. How to do below explicit type conversion in Scala? convert a float value 1.1 to int value 1 1.1.toInt convert a string value "1" to int value 1 "1".toInt

  46. Here is a code snippet about `while` loop. object Main extends App { var count = 9 while (count > 0) { println(s"Current count: $count") count -= 1 } println("Exited while loop") } How do you think of the while loop? Is there any drawback or defect using `while`?

    The code is working, but usually using `while` loop is considered as anti-pattern. The strength of FP is it can avoid traditional problems like data inconsistency, resource starvation, etc. in concurrency. Using `while` loop traces the state of a variable here, which may lead to concurrency issues.

  47. Below code snippet is an extension of Rational class extension (r:Rational) def +(s: Rational) = Rational(r.numer*s.denom+s.numer*r.denom, r.denom*s.denom) Can `+` be used with infix notation?

    Yes. `+` can be used as infix notation, since it only takes a single parameter.

  48. Suppose we'd like to define a method called `min` for Rational and we want `min` to support infix notation. Write the implementation.

    extension(r: Rational) infix def min(s: Rational) = Rational(r.numer*s.denom-s.numer*r.denom, r.denom*s.denom) Note: to support infix notation The function must take one single parameter. As alphanumeric function, `infix` modifier is a must

  49. Suppose we have below 'crazy' expression with corresponding symbolic functions defined. a + b ^? c ?^ d less a ==> b | c How do we know which part of the calculation will be processed first, aka the precedence?

    The first letter of the function identifier determines the precedence. Scala has a fixed list of precedence as below (precedence from low to high). Personal I don't think we need to remember that order. Instead we remember the idea and we can refer to the doc later if needed. all letters | ^ & < > = ! : + - * / % all other special characters

  50. Below is an implementation of Rational Numbers. class Rational(val numerator:Int, val denominator:Int): def add(other: Rational):Rational = Rational(numerator*other.denominator+other.numerator*denominator, denominator*other.denominator) extension (r:Rational) def +(other: Rational) = r.add(other) override def toString: String = s"${r.numerator}/${r.denominator}" Is there any defect?

    Yes, there is. In extension, we cannot override methods. To fix the issue, we need to move the overridden method up to class.

  51. Analyze the difference between below cases def fn1(x:Int) = 2 * x def fn2 = (x:Int) => 2 * x var fn3 = (x:Int) => 2 * x val fn4 = (x:Int) => 2 * x All of the four define a 'double' calculation function.

    Short version def fn1(x:Int) = 2 * x normal function definition def fn2 = (x:Int) => 2 * x normal function definition, but the return value is an anonymous function(function literal) fn2 uses parameterless call, so fn2(523) means to call on the function returned by `fn2` can redefine var fn3 = (x:Int) => 2 * x fn3 is a variable, so we can change it to another value fn3's type is implicitly defined as Int => Int val fn4 = (x:Int) => 2 * x fn4 is defined as a function literal defined as value so…

  52. In Scala REPL environment, there are some 'helper' commands that are not treated as Scala source code. What are the commands to perform below two actions? Get help Exit REPL What do below commands do? `:rest` `:load`

    What are the commands to perform below two actions? Get help: `:help` Exit REPL: `:quit` Notice commands can be abbreviated, so `:q` can exit Scala REPL. What do below commands do? `:rest`: reset REPL environment, so that previously defined variables, values, functions and etc are removed. `:load`: load the content of Scala source file into REPL, as if the Scala code is typed and executed in REPL.

  53. Several options are available to build Scala projects. Such as Ant Maven Gradle What's the major tool used in the Scala community for building Scala projects? Answer: sbt

  54. Some basic commands of sbt run: compiles and runs your program on the JVM. exit: gracefully terminates your session. new: creates an sbt project using a Giter8 template. about :provides general information on the sbt version and the project. compile: triggers the compilation of your Scala source code. clean: deletes any file produced during the compilation. reload: re-evaluates the configurations provided in the project. console: starts the REPL within a sbt project; all your code and dependenc…

  55. Suppose we'd like to create a Scala project in path C:\Sandbox\Scala\my-scala-project How can we achieve that with sbt?

    In cmdl, navigate to C:\Sandbox\Scala and then start up sbt. Issue below command to create a project using the Giter8 template. sbt:Scala> new scala/hello-world.g8 Name the project as `My Scala Project` so that the corresponding folder will be named as `my-scala-project`. Once the strucuter is created, sbt will quit automatically and we get back to our shell. Change the build.sbt file for things like Scala build version and project name per our needs.

  56. You may encounter the issue that sbt is very laggy in Windows OS. Sometimes, it even seems not responding to some particular keystrokes. How to resolve the issue?

    That issue can be resolved with jline.terminal, the Java system variable, to be set as `none`. Put it simply, start sbt with below command sbt "-Djline.terminal=none" Note The issue happens not only to sbt, but also to some other terminal based programs. `-D` is used to 'define' the system property, and in this case `jline.terminal`. The `-D` option is used in other systems, for example in Unix, the -D option is often used to define macros in the C preprocessor.

  57. How to temporarily and permanently change the Scala build version for a project?

    For temporarily changing the Scala version, start sbt with `++<ver_num>!`. For example to start REPL using sbt and force the Scala version to be 3.4.1 $ sbt ++3.4.1! console Note above command works well in Linux, but may not work in Windows.[TBR] For permanently changing the Scala version, specify the Scala version in build.sbt file, for example scalaVersion := "3.4.1" You may need to recompile your project after the change.

  58. What's the difference between val var

    val denotes values, and values are immutable. var denotes variables, and variables are mutable.

  59. Given below code snippet scala> var j = 2 var j: Int = 2 scala> j = 3.0 what will happen?

    We will get a Type Mismatch error. There are some tricks var j = 2 makes Scala to infer the type of j is Int, so we cannot simply assign things like strings to j. 3.0 is Double type and Scala cannot automatically change a Double to Int, because losing precision may happen. So we get an error The other way around, assigning an Int value to Double type variable is working.

  60. In Python, we can assign values of different types to a variable sequentially. >>> i = 10 >>> i = 2.0 >>> i = "Python" Is it possible to do the similar thing in Scala?

    Yes, we can declare the type of the variable as `Any` scala> var i:Any = 10 var i: Any = 10 scala> i = 2.0 i: Any = 2.0 scala> i = "Scala" i: Any = Scala The difference is Python is strongly typed programming language with dynamic typing, while Scala is a strictly typed language.

  61. `val` vs. `var`, when to use which?

    Stick to `val` as much as possible. `var` is always your last choice. Immutable brings many benefit when working in the concurrency world.

  62. In Scala, is there the 'traditional turnery operator `<condition> ? <value_for_ture> : <value_for_false>`?

    No, there isn't. However, In Scala, there is a similar structure if <condition> then <value_for_true> else <value_for_false> The philosophy is like Python's structure <value_for_true> if <condition> else <value_for_false> This is more FP style.

  63. Write examples for below 'branch' structures if else if then else

    def foo = if (true) { println("True line statement") }else{ println("False line statement") } def bar = val content = if true then "True Value" else "False Value" print(content) @main def main = foo bar Note we can always get the value of a block as its last expression def foo = val content = if (true){ "True Content!" }else{ "False Content!" } print(content) @main def main = foo We get "True Contents!" printed out.

  64. Write examples for below 'loop' structures for while What do you think of using 'traditional' loops in Scala?

    def foo = for i <- 9 to 1 by -1 do println(i) def bar = var counter = 9 while counter > 0 do println(counter) counter = counter - 1 @main def main = foo bar Using 'traditional' loops is treated as anti-pattern, because the program keeps track of variables, instead of utilizing immutability.

  65. In regard to loop structure like `for` and `while`, we can use either `do ... end <keyword>` or curly braces def foo = for i <- 1 to 5 do println(i) end for // optional end for (i <- 5 to 1 by -1) { println(i) } @main def main = foo Which style is preferred?

    For bodies more than one line, using curly braces is a preferred style. At least for Vim users, the keybinding `%` can work with curly brace well. The `do` style is more suitable for one-line body. For example `for i <- 1 to 5 do println(i)`. Pay attention, `for i <- 1 to 5 {...}` is invalid. Either a pair of parentheses or `do` is needed to separate condition and the body block.

  66. in Scala we can define many different sorts of functions. abstract concrete anonymous higher order pure impure If we define a function using `???` like below def myFunc(a: Int, b:Int) = ??? What does `???` mean?

    The symbol `???` is defined as a placeholder in Scala. It tells the compiler that the implementation is currently missing, but don't cause compilation error and runtime will throw NotImplementedError when the program hits that `???` line. It's very common to throw this sort of not implemented yet exception when we focus on designing the structure of our program.

  67. Below is some code snippet def walkDog(name: String, dog: String) = { name = "Claude" dog = "Liyu" print(s"$name is walking $dog") } Is there any defect in above code snippet?

    Yes, `name` and `dog` are defined as value identifier. They cannot be reassigned with values. Function parameters are actually value identifiers, instead of variables. Note, explicitly defining them as variables will cause compilation error. def walkDog(var name: String, var dog: String) def walkDog(val name: String, val dog: String) Above two function signatures are all invalid. Although `name` and `dog` are actually values, we cannot explicitly define them as either `var` or `val`. The FP sty…

  68. Does Scala support named parameter and default value? If it does, write an example

    Yes, Scala supports named parameter and default value. Below is an example def walkDog(name: String = "Claude", dog: String) = { println(s"$name is walking $dog") } @main def main = { walkDog("Claude", "Liyu") walkDog(dog = "Jenis") walkDog(dog = "Vicky", name = "Claude") } In the third invocation case, we ignore the position order.

  69. Given below code snippet def walkDog(name: String = "Claude", dog: String) = { println(s"$name is walking $dog") } @main def main = { walkDog("Vicky", name = "Claude") } is above code working?

    No, it isn't working. In that case, "Vicky" as argument will feed `name` parameter, and `name="Claude"` also tries to feed `name`. parameter name of method walkDog: (name: String, dog: String): Unit is already instantiated So we will get above error

  70. Given below code snippet def dupString(times: Int = 1, targetStr: String) = targetStr * times @main def main = println(dupString(3, "abc")) Is there any defect?

    Yes, there is. The best practice is to define parameters with default values after those without default values. With the definition in the question, when we want to use the default value of `times`, we'll have to provide the parameter name of `targetStr`, such as `dupString(targetStr="abcde")`. If we try to omit the parameter name of `targetStr`, such as `dupString("abcde")`, we'll get error. In this case, "abcde" will be treated as positional argument to pass to parameter `times`.

  71. Does every function in Scala have the return type? Take a look at below function definition def foo = print("foo function got called!") @main def main = foo It seems foo doesn't return any value.

    Every function in Scala has a return value, and therefore there is the corresponding return type. In this case, the return type of the function is `Unit`. This can be proven with REPL. scala> def foo = print("foo function got called!") def foo: Unit Unit type represents the absence of a meaningful value. In other words, it indicates the function doesn't return a useful data value, and side effects must happen.

  72. Scala is good at inferring data type. Given below code snippet def gcd(a:Int, b:Int) = if b == 0 then a else gcd(b, a%b) Is there any defect?

    Yes, there is an obvious defect. Scala tries it best to infer the data type. However, there are cases that it cannot figure out the data type. Some examples recursive function abstract function In those cases, we need to provide the return type explicitly.

  73. When we encounter the case that we have the choice to either manually provide the return type or let Scala infer the return type Which one should we choose following the best pracice?

    As a rule of thumb, always provide the return type explicitly. The benefit of explicit return type is we additionally tell the compiler to check if the implementation follows the design. It's like a double check.

  74. What's abstract function? Write an example.

    When a function doesn't have a function body, it's an abstract function. Note we can NOT use `abstract` keyword to modify function in Scala. The `abstract` keyword can only be used to modify class Here is an example of abstract function def myFunc(a:Int): Boolean Since there is no function body, Scala cannot infer the return type of the function, so we'll have to explicitly provide the return type.

  75. Below code snippet shows how to use a class in Scala class Robot(name: String) @main def main = val j = Robot(name="Jarvis") print(j.name) Is there any defect?

    Yes, there is defect and the code snippet does NOT work. `name` is a constructor parameter / class parameter, and it's only accessible in the constructor and the body of the class. We cannot visit it via object reference, even in the class(Think about a method of `Robot` accepts another `Robot` instance as parameter). To fix the issue, we can explicitly 'turn' `name` into a field with `val` class Robot(val name: String) Now `name` is expanded to a field.

  76. Given below class definition. class Robot(var name: String) Is there any defect in above class definition?

    Yes, there is defect. Although the code is working, when we can use `val`, we should use `val` instead of `var`.

  77. Given below class definition and invocation class Coordinate(latitude: Double, longitude: Double) new Coordinate(19.91, 5.23) Is there any defect?

    When more than one class of parameters have the same type, we should use named parameters to improve readability. new Coordinate(latitude = 19.91, longitude = 5.23) Now the invocation looks clearer and better. As a rule of thumb, use named parameters every time if it can improve code's readability.

  78. Given below class definition and invocation object Main extends App { val arale = Robot("Arale") arale.greet("Dr. Slump") } class Robot(val name: String = "Unknown"): def greet(name: String) = println(s"Hi $name, my name is $name") Does above code work?

    There is no syntactical error, so the code can run. However, the behavior may not be like the expected one. `$name` defined in the `greet` method signature shadows the `name` field of `Robot` class, we we get below output Hi Dr. Slump, my name is Dr. Slump To fix the issue, use `this` to refer to the object. println(s"Hi $name, my name is ${this.name}") Now `this.name` points to `Arale`

  79. Is the access control on class level, just as Java?

    Like Java, the access control is at class level. Below is an example class Robot(val name: String = "Unknown", age:Int = 0): private val robotAge: Int = age def greet(robot: Robot) = println(s"Hi ${robot.name}, my name is ${this.name}. I know you're ${robot.robotAge} years old!") @main def main = val arale = Robot("Arale", 13) var jarvis = Robot("Jarvis", 16) arale.greet(jarvis) // println(arale.robotAge) // cause error `robotAge` is a private field of class `Robot`. It can be accessed in the c…

  80. Write a class inheritance example

    class Robot(name: String) { def greet = println(s"Hello, I'm $name") } class HumanoidRobot(val name: String, val height: Int) extends Robot(name) @main def main = { val arale: Robot = HumanoidRobot("Arale", 139) arale.greet print(arale.asInstanceOf[HumanoidRobot].name) } Above is an example showing parent-child relationship between `Robot` class and `HumanoidRobot` class. Note `name` in Robot is a class parameter (or call it constructor parameter). It can only be used in the body of the class.…

  81. Write an example of method override.

    class Robot(name:String): def greet = print(s"I'm a robot. My name is $name") class HumanoidRobot(name:String, age:Int) extends Robot(name): override def greet: Unit = println(s"I'm humanoid robot $name") @main def main = val arale = HumanoidRobot(name = "Arale", age = 13) arale.greet Note `override` modifier cannot be omitted, or you will get an error.

  82. Write an example of abstract class with abstract methods.

    abstract class Robot(name:String): def greet:Unit class HumanoidRobot(name:String, age:Int) extends Robot(name): override def greet: Unit = println(s"I'm humanoid robot $name.") Note For abstract method, we MUST provide return type because there is no method body and compiler cannot infer the return type If `HumanoidRobot` contained abstract method, it would be defined as an abstract class

  83. Given below Scala code snippet abstract class Robot(name:String): def greet = print(s"I'm a robot. My name is $name.") The abstract does NOT contain any abstract methods. Instead, it only contains a concrete method. Is it valid definition?

    Yes, it's valid. An abstract class can have non-abstract methods. In this valid edge case, it only contains a concrete method.

  84. Given below Scala code snippet class Robot(name:String): private var core = s"Rat[$name]" def getOtherCore(r: Robot) = s"${r.core}" @main def main = val danceOfMaple = Robot("Dance of Maple") val arale = Robot("Arale") println(arale.getOtherCore(danceOfMaple)) `name` is a constructor parameter `core` is a private field What's the difference between them, especially in regard to accessibility?

    Field accessibility is at class level, so it is perfectly fine to visit `r.core` as long as `r` is the passed in Robot instance. `name` is a constructor parameter. It is accessible only in the constructor and body of the class. That is the reason why we can form the string using its value on the 2nd line. If we try to visit constructor parameter in a method like below def getOtherCore(r: Robot) = s"${r.core} ${r.name}" we will get an compilation error.

  85. In Scala, can we define a class without super class? For example class Robot(name:String) In above code snippet, Robot class doesn't extend any class.

    Syntactically that's correct. However be aware that when there is no explicit super class, `AnyRef`(`Object`) class is the base class of user defined class. class Robot(name:String) @main def main = val arale = Robot("Arale") println(arale.isInstanceOf[Robot]) println(arale.isInstanceOf[Object]) println(arale.isInstanceOf[AnyRef]) Executing above code snippet, we will get three `true`.

  86. What's the difference between below two types? Any Object

    Any: supertype of all types in Scala AnyRef(Object): base type of user defined type and other reference type. It corresponds to reference type in Java.

  87. Given below Scala code snippet abstract class Base: def foo = 1 def bar: Int class Sub extends Base: override def foo = 2 def bar = 3 Can the code be compiled successfully?

    Yes, it can. You may feel that `override` modifier is missing one the `bar` method. However, `bar` is an abstract defined in superclass, so `override` is not mandatory in the subclass when implementing the mthod.

  88. Design a data structure for sets of integer numbers. Below two methods are required incl(<elem>): to include/add the <elem> to the set contains(<elem>): to indicate whether <elem> is contained in the set hint: Define an abstract class as a 'protocol' to reveal two methods, and implement the abstract class with binary tree The class hierarchy can be like IntSet EmptySet derived from IntSet NonEmptySet derived from IntSet

    abstract class IntSet: def incl(elem:Int):IntSet def contains(elem:Int):Boolean class EmptySet extends IntSet: def incl(elem: Int): IntSet = NonEmptySet(elem, EmptySet(), EmptySet()) def contains(elem: Int): Boolean = false class NonEmptySet(elem:Int, left:IntSet, right:IntSet) extends IntSet: def incl(elem: Int): IntSet = if elem < this.elem then NonEmptySet(this.elem, left.incl(elem), right) else if elem > this.elem then NonEmptySet(this.elem, left, right.incl(elem)) else this def contains(el…

  89. In Scala, how to implement singleton pattern? For example, when implementing 'sets of integer' using binary tree, for the empty node type, we have below code snippet abstract class IntSet: def incl(elem:Int):IntSet def contains(elem:Int):Boolean class EmptySet extends IntSet: def incl(elem: Int): IntSet = NonEmptySet(elem, EmptySet(), EmptySet()) def contains(elem: Int): Boolean = false Ideally, we don't need to crate many empty node instances. One instance should be sufficient. How to implemen…

    object EmptySet extends IntSet: def incl(elem: Int): IntSet = NonEmptySet(elem, EmptySet, EmptySet) def contains(elem: Int): Boolean = false Note we use `object` to indicate that is a singleton object. Don't get confused with `Object` type(capital case) Since we don't create multiple instances of a singleton object, when using the singleton object, we use the form `<object_name>`, not `<class_name>()`. In short, no parenthesis to create instances.

  90. Write a simple program according to below criteria Create an singleton object definition Try get 'two different' instances of the singleton object Validate the equality and identity of the 'two' instances and prove they are actually the same one

    object Arale{ var name:String = "Arale" } @main def main = val arale1 = Arale val arale2 = Arale println(arale1 eq arale2) println(arale1 == arale2) arale1.name = "[Robot]Arale" println(arale2.name) Note Object may not have parameters, so `object Arale(var name: String)` is invalid `eq` is used to test the identity(reference equality) `==` is for testing equality we changed the name via `arale1` and that can be viewed by `arale2`. It's obviously that `arale1` and `arale2` are actually one objec…

  91. Is it possible to define a class and an object with the same name? For example `class EmptySet` `object EmptySet` Will there be any naming conflict?

    No. Singleton objects are indeed values. In Scala, values and types have different namespaces, so there will be no naming conflict. If a class and an object with the same name are defined in the same source file, we call them companions.

  92. What are common use cases of `object`?

    When singleton pattern is desired When something similar to static in Java is needed. class Robot() object Robot: def echo(s:String) = s"[Echo]$s" @main def main = print(Robot.echo("This is a test!")) Notice on the last line, the form `Robot.echo(...)` looks like a static method call in Java.

  93. Is it possible to define a method other than `main` as the entry point?` In addition, think about what if the entry point needs to accpet some arguments.

    Yes, that's possible and we need to use `@main` annotation. @main def test = print("This main doesn't have 'main' as name") In above code snippet, we name the entries point of the program as `test`. When executing in shell like `scala Robot.scala`, `test` will be executed. We can also use `@main` on a method of an object like below object Robot: @main def test() = println("Use @main annotation on a method of class") Although the entrance is named as `test`, not `main`, we use `@main` annotation…

  94. Is is possible to define two entries in a Scala source file?

    Yes, that's possible. object EntryA: @main def foo = print("EntryA foo") object EntryB: def main(x: Array[String]) = print("EntryB main") Now, there are multiple entries in the same Scala source file, so we cannot simply run the program like `scala <source_file>` . Instead, we need to compile the program first. PS C:\Sandbox\ScalaWithMO> scalac Robot.scala PS C:\Sandbox\ScalaWithMO> ls EntryA$.class EntryA.class EntryA.tasty EntryB$.class EntryB.class EntryB.tasty foo.class foo.tasty lab.scala…

  95. Does Scala use the early method binding strategy or the late binding strategy?

    Scala uses a late binding strategy, or call it dynamic binding. class Robot(name:String): def greet = println(s"Hello this is Robot[$name]") class HumanoidRobot(name:String) extends Robot(name): override def greet: Unit = println(s"Hi, this is humanoid robot[$name]") @main def main = val j:Robot = Robot("Jarvis") val a:Robot = HumanoidRobot("Arale") j.greet a.greet Note `a` is declared as `Robot`, but due to polymorphism, we provide an instance of `HumanoidRobot` to `a`. Later when invoking `a.…

  96. How to denote the starting point of a Scala program? One possible approach is use `@main` annotation as below @main def main = { println("Start program...") // ... println("Exit program") } Besides above `@main` approach, is there any other way to denote the entry point? Hint Use a special trait The 'regular' main method, which doesn't use any annotation or trait

    Use `App` trait object MyApp extends App { println("Start program...") // ... println("Exit program") } Note The statements are in the `App` body itself, instead of in a method of `App` object. This is special to `App` trait. Other traits don't support this, and statements should be placed in the method of object. Another approach is to use `Main` singleton object + main object Main : def main(args: Array[String]) = println("Start program....") println(args(0)) // the first element of the array…

  97. What's the different between using `@main` and extending `App` trait?

    Both of them are for indicating the entry point of the Scala program. @main: new in Scala 3. The recommended way in Scala 3. extends App: supported in both Scala 2 and 3. If compatibility is needed, use this one.

  98. Classes and objects are organized in packages. How to place a class or object inside a package? For example, say we have a `Hello` object and w'd like to place it in a package called `net.greeting`. package net.greeting object Hello{ //... }

  99. Given below Scala code in `Hello.scala` source file. package net.greeting object Hello extends App { print("Hello from net.greeting package!") } We can execute above program with the command `scala Hello.scala`. Alternatively, we can compile the code with below command PS> scalac Hello.scala Then we can execute the program with below command PS> scala net.greeting.Hello

    Note when classes / objects are placed in a package, their qualified names include the package

  100. Do we need to construct the folder structure according to the package name? For example given below Scala code in a file called `Hello.scala` package net.greeting object Hello extends App { print("Hello from net.greeting package!") } Do we need to place the `Hello.scala` file under the folder structure `/net/greeting`?

    That's the best practice, but we don't need to strictly follow it. Furthermore, the source file name doesn't have to be `Hello.scala`. Although that's the best practice, the file name can be another name if we want.