--- a/handouts/pep-ho.tex Sat Mar 11 23:24:15 2023 +0000
+++ b/handouts/pep-ho.tex Sat Sep 23 23:49:44 2023 +0100
@@ -124,7 +124,7 @@
\begin{document}
-\fnote{\copyright{} Christian Urban, King's College London, 2017, 2018, 2019, 2020, 2021, 2022}
+\fnote{\copyright{} Christian Urban, King's College London, 2017, 2018, 2019, 2020, 2021, 2022, 2023}
%\begin{tcolorbox}[breakable,size=fbox,boxrule=1pt,pad at break*=1mm,colback=cellbackground,colframe=cellborder]
% abd
@@ -136,6 +136,10 @@
\underline{a}cademic \underline{la}nguage''}\smallskip\\
\mbox{}\hfill\textit{ --- a joke(?) found on Twitter}\bigskip
+\mbox{}\hfill\textit{``Life is too short for \texttt{malloc}.''}\smallskip\\
+\mbox{}\hfill\textit{ --- said Neal Ford at Oscon'13}\;\hr{https://www.youtube.com/watch?v=7aYS9PcAITQ}\bigskip\\
+
+
\subsection*{Introduction}
\noindent
@@ -150,7 +154,7 @@
``Scala is the better Java''.\footnote{from
\url{https://www.slideshare.net/maximnovak/joy-of-scala}}
-A number of companies---the Guardian, Twitter, Coursera, FourSquare,
+A number of companies---the Guardian, Dualingo, Coursera, FourSquare,
Netflix, LinkedIn, ITV to name a few---either use Scala exclusively in
production code, or at least to some substantial degree. Scala seems
also useful in job-interviews (especially in data science) according to
@@ -168,18 +172,22 @@
\end{quote}
\noindent\alert
-Just make sure you are downloading the ``battle tested'' version of
-Scala \textbf{2.13} This is the one I am going to use in the lectures and
-in the coursework. The newer Scala 3.1 \& 3.2 still have some
-features not fully implemented.\bigskip
+Just make sure you are using the version 3(!) of Scala. This is
+the version I am going to use in the lectures and in the coursework. This
+can be any version of Scala 3.X where $X=\{1,2,3\}$. Also the minor
+number does not matter. Note that this will be the first year I am
+using this version -- so some hiccups are bound to happen. Apologies
+in advance!\bigskip
\noindent
-If you are interested, there are also experimental backends of Scala
-for producing code under Android (\url{http://scala-android.org}); for
-generating JavaScript code (\url{https://www.scala-js.org}); and there
-is work under way to have a native Scala compiler generating X86-code
-(\url{http://www.scala-native.org}). Though be warned these backends
-are still rather beta or even alpha.
+If you are interested, there are also experimental backend of Scala
+for generating JavaScript code (\url{https://www.scala-js.org}), and
+there is work under way to have a native Scala compiler generating
+X86-code (\url{http://www.scala-native.org}). There are also some
+tricks you can play with Scala programms running as native
+GraalVM~\hr{https://scala-cli.virtuslab.org/docs/cookbooks/native-images/}
+images. Though be warned these backends are still rather beta or even
+alpha.
\subsection*{VS Code and Scala}
@@ -200,7 +208,7 @@
\noindent
and should already come pre-installed in the Department (together with
the Scala compiler). Being a project that just started in 2015, VS Code is
-relatively new and thus far from perfect. However it includes a
+relatively new and therefore far from perfect. However it includes a
\textit{Marketplace} from which a multitude of extensions can be
downloaded that make editing and running Scala code a little easier (see
Figure~\ref{vscode} for my setup).
@@ -221,11 +229,12 @@
\end{boxedminipage}
\end{figure}
- Actually \alert last year I switched to VS Codium, which is VS Code minus
-all the telemetry that is normally sent to Microsoft. Apart from the
- telemetry, it works pretty much the same as the original but is driven
-by a dedicated community, rather than a big company. You can download
-VS Codium from
+Actually \alert last year I switched to VS Codium, which is VS Code
+minus all the telemetry that is normally sent to Microsoft. Apart from
+the telemetry (and Copilot, which you are not supposed to use anyway),
+it works pretty much the same way as the original but is driven by a
+dedicated community, rather than a big company. You can download VS
+Codium from
\begin{quote}
\url{https://vscodium.com}
@@ -263,7 +272,7 @@
I do \textbf{not} recommend the usage of either Eclipse or IntelliJ for PEP: these IDEs
seem to make your life harder, rather than easier, for the small
programs that we will write in this module. They are really meant to be used
-when you have a million-lines codebase than with our small
+when you have a million-lines codebase instead of our small
``toy-programs''\ldots{}for example why on earth am I required to create a
completely new project with several subdirectories when I just want to
try out 20-lines of Scala code? Your mileage may vary though.~\texttt{;o)}
@@ -287,16 +296,16 @@
%to inflict Scala upon you.
Very likely writing programs in a functional programming language is
-quite different from what you are used to in your study so far. It
+quite different from what you are used to in your study so far. It
might even be totally alien to you. The reason is that functional
programming seems to go against the core principles of
-\textit{imperative programming} (which is what you do in Java and C/C++
-for example). The main idea of imperative programming is that you have
-some form of \emph{state} in your program and you continuously change
-this state by issuing some commands---for example for updating a field
-in an array or for adding one to a variable and so on. The classic
-example for this style of programming is a \texttt{for}-loop in C/C++.
-Consider the snippet:
+\textit{imperative programming} (which is what you do in Java and
+C/C++ for example). The main idea of imperative programming is that
+you have some form of \emph{state} in your program and you
+continuously change this state by issuing some commands---for example
+for updating a field in an array or for adding one to a variable
+stored in memory and so on. The classic example for this style of
+programming is a \texttt{for}-loop in C/C++. Consider the snippet:
\begin{lstlisting}[language=C,numbers=none]
for (int i = 10; i < 20; i++) {
@@ -304,16 +313,16 @@
}
\end{lstlisting}
-\noindent Here the integer variable \texttt{i} embodies the state, which
-is first set to \texttt{10} and then increased by one in each
-loop-iteration until it reaches \texttt{20} at which point the loop
-exits. When this code is compiled and actually runs, there will be some
-dedicated space reserved for \texttt{i} in memory. This space of
-typically 32 bits contains \texttt{i}'s current value\ldots\texttt{10}
-at the beginning, and then the content will be overwritten with
-new content in every iteration. The main point here is that this kind of
-updating, or overwriting, of memory is 25.806\ldots or \textbf{THE ROOT OF
-ALL EVIL}!!
+\noindent Here the integer variable \texttt{i} embodies part of the
+state of the program, which is first set to \texttt{10} and then
+increased by one in each loop-iteration until it reaches \texttt{20}
+at which point the loop exits. When this code is compiled and actually
+runs, there will be some dedicated space reserved for \texttt{i} in
+memory. This space of typically 32 bits contains \texttt{i}'s current
+value\ldots\texttt{10} at the beginning, and then the content will be
+overwritten with new content in every iteration. The main point here
+is that this kind of updating, or overwriting, of memory is
+25.806\ldots or \textbf{THE ROOT OF ALL EVIL}!!
\begin{center}
\includegraphics[scale=0.25]{../pics/root-of-all-evil.png}
@@ -336,7 +345,7 @@
CPUs in order to make them more powerful and potentially make software
faster. The task for you as developer is to take somehow advantage of
these cores by running as much of your code as possible in parallel on
-as many cores you have available (typically 4 or more in modern laptops
+as many cores you have available (typically 4-8 or even more in modern laptops
and sometimes much more on high-end machines). In this situation
\textit{mutable} variables like \texttt{i} in the C-code above are evil,
or at least a major nuisance: Because if you want to distribute some of
@@ -471,43 +480,42 @@
\noindent
If you need any after-work distractions, you might have fun reading
-this about FP (functional programming) --- you
+the following article about FP (functional programming) --- you
might have to disable your browser cookies though if you want to read
it for free. And spoiler alert: This is tongue-in-cheek \texttt{;o)}
\begin{quote}
-\url{https://betterprogramming.pub/fp-toy-7f52ea0a947e}
+ \url{https://archive.ph/vrofC}
\end{quote}
\subsection*{The Very Basics}
-One advantage of Scala over Java is that it includes an interpreter (a
-REPL, or
+Let us get back to Scala: One advantage of Scala over Java is that it
+includes an interpreter (a REPL, or
\underline{R}ead-\underline{E}val-\underline{P}rint-\underline{L}oop)
with which you can run and test small code snippets without the need
of a compiler. This helps a lot with interactively developing
-programs. It is my preferred way of writing small Scala
-programs. Once you installed Scala, you can start the interpreter by
-typing on the command line:
+programs. It is my preferred way of writing small Scala programs. Once
+you installed Scala, you can start the interpreter by typing on the
+command line:
\begin{lstlisting}[language={},numbers=none,basicstyle=\ttfamily\small]
$ scala
-Welcome to Scala 2.13.9 (OpenJDK 64-Bit Server VM, Java 17.0.1).
-Type in expressions for evaluation. Or try :help.
+Welcome to Scala 3.3.1 (17.0.8.1, Java OpenJDK 64-Bit Server VM).
+Type in expressions for evaluation. Or try :help.
scala>
\end{lstlisting}%$
-
-
\noindent The precise response may vary depending
-on the version and platform where you installed Scala. At the Scala
+on the version and platform where you installed Scala. Make sure
+you have installed Scala version 3. At the Scala
prompt you can type things like \code{2 + 3}\;\keys{Ret} and
the output will be
-\begin{lstlisting}[numbers=none]
+\begin{lstlisting}[numbers=none,language={}]
scala> 2 + 3
-res0: Int = 5
+val res0: Int = 5
\end{lstlisting}
\noindent The answer means that he result of the addition is of type
@@ -515,15 +523,15 @@
Scala gives automatically to the result. You can reuse this name later
on, for example
-\begin{lstlisting}[numbers=none]
+\begin{lstlisting}[numbers=none,language={}]
scala> res0 + 4
-res1: Int = 9
+val res1: Int = 9
\end{lstlisting}
\noindent
Another classic example you can try out is
-\begin{lstlisting}[numbers=none]
+\begin{lstlisting}[numbers=none,language={}]
scala> print("hello world")
hello world
\end{lstlisting}
@@ -620,6 +628,12 @@
\subsection*{Values}
+\begin{tcolorbox}[colback=red!5!white,colframe=red!75!black]
+ Do not use \code{var} in your code for PEP! This declares a mutable variable.
+ Only use \code{val}!
+\end{tcolorbox}\medskip
+
+\noindent
In the lectures I will try to avoid as much as possible the term
\emph{variables} familiar from other programming languages. The reason
is that Scala has \emph{values}, which can be seen as abbreviations of
@@ -628,13 +642,13 @@
\begin{lstlisting}[numbers=none]
scala> val x = 42
-x: Int = 42
+val x: Int = 42
scala> val y = 3 + 4
-y: Int = 7
+val y: Int = 7
scala> val z = x / y
-z: Int = 6
+val z: Int = 6
\end{lstlisting}
\noindent
@@ -646,9 +660,12 @@
\begin{lstlisting}[numbers=none]
scala> z = 9
-error: reassignment to val
- z = 9
- ^
+-- [E052] Type Error: -----------------------------------
+1 |z = 9
+ |^^^^^
+ |Reassignment to val z
+ | ...
+1 error found
\end{lstlisting}
\noindent
@@ -709,7 +726,7 @@
where each argument, \texttt{arg1}, \texttt{arg2} and so on, requires
its type and the result type of the
function, \code{rty}, should also be given. If the body of the function is
-more complex, then it can be enclosed in braces, like above. If it it
+more complex, then it can be enclosed in braces, like above. If it
is just a simple expression, like \code{x + 1}, you can omit the
braces. Very often functions are recursive (that is call themselves),
like the venerable factorial function:
@@ -720,7 +737,8 @@
\end{lstlisting}
\noindent
-We could also have written this with braces as
+where we have to give the return type \code{Int}. Note we could also
+have written this with braces as
\begin{lstlisting}[numbers=none]
def fact(n: Int) : Int = {
@@ -731,7 +749,7 @@
\noindent
but this seems a bit overkill for a small function like \code{fact}.
-Note that Scala does not have a \code{then}-keyword in an
+Notice that Scala does not have a \code{then}-keyword in an
\code{if}-statement. Also important is that there should be always an
\code{else}-branch. Never write an \code{if} without an \code{else},
unless you know what you are doing! While \code{def} is the main
@@ -748,7 +766,7 @@
actually produce? A rule-of-thumb is whatever is in the last line of the
function is the value that will be returned. Consider the following
example:\footnote{We could have written this function in just one line,
-but for the sake of argument lets keep the two intermediate values.}
+but for the sake of argument let's keep the two intermediate values.}
\begin{lstlisting}[numbers=none]
def average(xs: List[Int]) : Int = {
@@ -776,11 +794,12 @@
\end{lstlisting}
\noindent
-Here the function still only returns the expression in the last line.
-The \code{println} before just prints out some information about the
-input of this function, but does not contribute to the result of the
-function. Similarly, the value \code{h} is used in the \code{println}
-but does not contribute to what integer is returned.
+Here the function still only returns the expression \code{s / n} in
+the last line. The \code{println} before just prints out some
+information about the input of this function, but does not contribute
+to the result of the function. Similarly, the value \code{h} is used
+in the \code{println} but does not contribute to what integer is
+returned by the function.
A caveat is that the idea with the ``last line'' is only a rough
rule-of-thumb. A better rule might be: the last expression that is
@@ -820,6 +839,13 @@
\noindent
which still satisfies the rule-of-thumb.
+\begin{tcolorbox}[colback=red!5!white,colframe=red!75!black]
+ Do not use \code{return} in your code to indicate what a function
+ produces as a result! It has a different meaning in Scala than in
+ Java. It can change the meaning of your program, and you should
+ never use it.
+\end{tcolorbox}
+
\subsection*{Loops, or Better the Absence Thereof}
@@ -830,9 +856,9 @@
build the list of squares. The list of numbers from 1 to 8
can be constructed in Scala as follows:
-\begin{lstlisting}[numbers=none]
+\begin{lstlisting}[numbers=none,language={}]
scala> (1 to 8).toList
-res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
+val res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
\end{lstlisting}
\noindent Generating from this list the list of corresponding
@@ -904,7 +930,7 @@
\begin{lstlisting}[numbers=none]
scala> for (n <- (1 to 8).toList) yield n * n
-res2: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64)
+val res2: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64)
\end{lstlisting}
\noindent This for-comprehension states that from the list of numbers
@@ -924,17 +950,19 @@
val j = n - 1
i * j + 1
}
-res3: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64)
+val res3: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64)
\end{lstlisting}
-As you can see in for-comprehensions above, we specified the list where
-each \code{n} comes from, namely \code{(1 to 8).toList}, and how each
-element needs to be transformed. This can also be expressed in a second
-way in Scala by using directly the function \code{map} as follows:
+Let us come back to the simple example of squaring a list of numbers.
+As you can see in the for-comprehensions above, we specified the list
+where each \code{n} comes from, namely \code{(1 to 8).toList}, and how
+each element needs to be transformed, the expression after the
+\code{yield}. This can also be expressed in a second way in Scala by
+using directly the function \code{map} as follows:
-\begin{lstlisting}[numbers=none]
+\begin{lstlisting}[numbers=none,language={}]
scala> (1 to 8).toList.map(n => n * n)
-res3 = List(1, 4, 9, 16, 25, 36, 49, 64)
+val res3 = List(1, 4, 9, 16, 25, 36, 49, 64)
\end{lstlisting}
\noindent In this way, the expression \code{n => n * n} stands for the
@@ -949,43 +977,41 @@
as lists, sets, vectors, options and so on. For example if we instead
compute the remainders modulo 3 of this list, we can write
-\begin{lstlisting}[numbers=none]
+\begin{lstlisting}[numbers=none,language={}]
scala> (1 to 8).toList.map(n => n % 3)
-res4 = List(1, 2, 0, 1, 2, 0, 1, 2)
+val res4 = List(1, 2, 0, 1, 2, 0, 1, 2)
\end{lstlisting}
\noindent If we, however, transform the numbers 1 to 8 not
into a list, but into a set, and then compute the remainders
modulo 3 we obtain
-\begin{lstlisting}[numbers=none]
-scala> (1 to 8).toSet[Int].map(n => n % 3)
-res5 = Set(2, 1, 0)
+\begin{lstlisting}[numbers=none,language={}]
+scala> (1 to 8).toSet.map(n => n % 3)
+val res5 = Set(2, 1, 0)
\end{lstlisting}
-\noindent This\footnote{This returns actually \code{HashSet(2, 1, 3)},
+\noindent This\footnote{This returns actually \code{HashSet(1, 2, 3)},
but this is just an implementation detail of how sets are implemented in
Scala.} is the correct result for sets, as there are only three
-equivalence classes of integers modulo 3. Note that in this example we
-need to ``help'' Scala to transform the numbers into a set of integers
-by explicitly annotating the type \code{Int}. Since maps and
+equivalence classes of integers modulo 3. Since maps and
for-comprehensions are just syntactic variants of each other, the latter
can also be written as
\begin{lstlisting}[numbers=none]
-scala> for (n <- (1 to 8).toSet[Int]) yield n % 3
-res5 = Set(2, 1, 0)
+scala> for (n <- (1 to 8).toSet) yield n % 3
+val res5 = Set(2, 1, 0)
\end{lstlisting}
For-comprehensions can also be nested and the selection of
-elements can be guarded. For example if we want to pair up
+elements can be guarded (or filtered). For example if we want to pair up
the numbers 1 to 4 with the letters a to c, we can write
\begin{lstlisting}[numbers=none]
scala> for (n <- (1 to 4).toList;
m <- ('a' to 'c').toList) yield (n, m)
-res6 = List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c),
- (3,a), (3,b), (3,c), (4,a), (4,b), (4,c))
+val res6 = List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c),
+ (3,a), (3,b), (3,c), (4,a), (4,b), (4,c))
\end{lstlisting}
\noindent
@@ -997,7 +1023,7 @@
scala> for (n <- (1 to 3).toList;
m <- (1 to 3).toList;
if (n + m) % 2 == 0) yield (n, m)
-res7 = List((1,1), (1,3), (2,2), (3,1), (3,3))
+val res7 = List((1,1), (1,3), (2,2), (3,1), (3,3))
\end{lstlisting}
\noindent The \code{if}-condition in this for-comprehension filters out
@@ -1013,7 +1039,7 @@
scala> val cs = ('a' to 'h').toList
scala> for (n <- (0 until cs.length).toList)
yield cs(n).capitalize
-res8: List[Char] = List(A, B, C, D, E, F, G, H)
+val res8: List[Char] = List(A, B, C, D, E, F, G, H)
\end{lstlisting}
\noindent
@@ -1023,7 +1049,7 @@
\begin{lstlisting}[numbers=none]
scala> val cs = ('a' to 'h').toList
scala> for (c <- cs) yield c.capitalize
-res9: List[Char] = List(A, B, C, D, E, F, G, H)
+val res9: List[Char] = List(A, B, C, D, E, F, G, H)
\end{lstlisting}
\subsection*{Results and Side-Effects}
@@ -1046,7 +1072,7 @@
\noindent
where you need to omit the keyword \code{yield}. You can
-also do more elaborate calculations such as
+also do more elaborate calculations before printingh such as
\begin{lstlisting}[numbers=none]
scala> for (n <- (1 to 5).toList) {
@@ -1063,7 +1089,7 @@
\noindent In this code I use a value assignment (\code{val
square = ...} ) and also what is called in Scala a
\emph{string interpolation}, written \code{s"..."}. The latter
-is for printing out an equation. It allows me to refer to the
+is for printing out formatted strings. It allows me to refer to the
integer values \code{n} and \code{square} inside a string.
This is very convenient for printing out ``things''.
@@ -1269,13 +1295,13 @@
of anything simple, but for example in the Compiler module next year I
show a compilation functions that needs to generate functions as
intermediate result. Anyway, notice the interesting type we had to
-annotate to \code{mkfn}. Types of Scala are described next.
+annotate to \code{mkfn}. The types in Scala are described next.
\subsection*{Types}
In most functional programming languages, types play an
-important role. Scala is such a language. You have already
+essential role. Scala is such a language. You have already
seen built-in types, like \code{Int}, \code{Boolean},
\code{String} and \code{BigInt}, but also user-defined ones,
like \code{Rexp} (see coursework). Unfortunately, types can be a thorny
@@ -1302,6 +1328,23 @@
example \code{List[Int]} or \code{Set[List[String]]} or
\code{Map[Int, Int]}.
+Scala provides a basic mechanism to check the type of a (closed)
+expression---closed means that all parts are already known to Scala.
+Then you can use the command \code{:type} and check in the REPL:
+
+\begin{lstlisting}[ numbers=none]
+scala> :type (1, List(3), Set(4,5), "hello")
+(Int, List[Int], Set[Int], String)
+\end{lstlisting}
+
+\noindent
+If Scala can calculate the type of the given expression, then it
+will print it. Unfortunately, this way of finding out a type is almost
+unusable: for `things' where the type is pretty obvious, it gives an
+answer; but for `things' that are actually of interest (such as
+what is the type of a pre-defined function), it gives up with
+an error message.
+
There are a few special type-constructors that fall outside
this pattern. One is for tuples, where the type is written
with parentheses. For example
@@ -1420,10 +1463,12 @@
You might ask: Apart from silly functions like above, what is
the point of having functions as input arguments to other
-functions? In Java there is indeed no need of this kind of
-feature: at least in the past it did not allow such
-constructions. I think, the point of Java 8 and successors was to lift this
-restriction. But in all functional programming languages,
+functions?
+%In Java there is indeed no need of this kind of
+%feature: at least in the past it did not allow such
+%constructions. I think, the point of Java 8 and successors was to lift this
+%restriction.
+Well, in all functional programming languages,
including Scala, it is really essential to allow functions as
input argument. Above you have already seen \code{map} and
\code{foreach} which need this feature. Consider the functions
@@ -1698,7 +1743,7 @@
\end{lstlisting}\bigskip
\noindent
-Type for list of Strings:
+Compound types, say the type for list of Strings:
\begin{lstlisting}[language=Java]
List<String>/*!\annotation{Java}!*/
@@ -1743,7 +1788,7 @@
\subsection*{More Info}
There is much more to Scala than I can possibly describe in
-this document and teach in the lectures. Fortunately there are a
+this short document and teach in the lectures. Fortunately there are a
number of free books
about Scala and of course lots of help online. For example
@@ -1766,11 +1811,13 @@
\end{itemize}
While I am quite enthusiastic about Scala, I am also happy to
-admit that it has more than its fair share of faults. The
-problem seen earlier of having to give an explicit type to
-\code{toSet}, but not \code{toList} is one of them. There are
-also many ``deep'' ideas about types in Scala, which even to
-me as seasoned functional programmer are puzzling. Whilst
+admit that it has more than its fair share of faults.
+%The
+%problem seen earlier of having to give an explicit type to
+%\code{toSet}, but not \code{toList} is one of them. There are
+%also many ``deep'' ideas about types in Scala, which even to
+%me as seasoned functional programmer are puzzling.
+For example, whilst
implicits are great, they can also be a source of great
headaches, for example consider the code:
@@ -1799,12 +1846,15 @@
language is lately developing at lightening speed (in comparison to the past)
taking on many
features of Scala and other languages, and it seems it even introduces
-new features on its own.
+new features on its own. So there is seemingly even more incentive to
+stick with the old stuff you know.
Scala is deep: After many years, I still continue to learn new technique
-for writing more elegant code. Unfortunately, I have not yet managed to
-switch over my code to Scala 3.0 due to time constraints. Scala 3 seems
+for writing more elegant code.
+%Unfortunately, I have not yet managed to
+%switch over my code to Scala 3.0 due to time constraints.
+Scala 3 seems
to iron out a number of snags from Scala 2, but why on earth are they
introducing Python-esque indentation and why on earth are they
re-introducing the \texttt{then}-keyword in Scala 3, when I just about got