You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
5.3 KiB
86 lines
5.3 KiB
% -*- mode: latex; coding: utf-8; TeX-master: ../thesis -*-
|
|
% !TEX TS-program = pdflatexmk
|
|
% !TEX encoding = UTF-8 Unicode
|
|
% !TEX root = ../thesis.tex
|
|
|
|
The aforementioned extensions to the Go language and its tooling should be a help to learn
|
|
functional programming. I believe that through these extensions it is easier to write
|
|
purely functional code in Go, enabling a developer to learn functional programming with
|
|
a familiar syntax in an obvious way. Here, Go's simplicity and verbosity are a key differentiator
|
|
to other languages. Instead of having as many features as possible to support every usecase,
|
|
Go has been designed with simplicity in mind\footnote{For example, Go only has 25 keywords, compared
|
|
to 37 in C99 and 84 in C++11}.
|
|
|
|
In many cases, this leads to more `verbose' code --- more lines of code compared to a similar
|
|
implementation in other languages. However, I argue that, especially for the first steps
|
|
in functional programming,
|
|
|
|
\begin{quote}
|
|
Clear is better than clever\autocite{cheney-clear}
|
|
\end{quote}
|
|
|
|
Staying in touch with this core Go principle, this results in functional code that may be
|
|
verbose, but easy to read and understand.
|
|
|
|
It should be clear that the result is not a `production-ready' functional programming language.
|
|
It is a language to help getting started with functional programming; either by re-implemeting pieces
|
|
of code that have not been clear in how they work, or by taking an imperative block of code
|
|
and refactoring it to make it purely functional.
|
|
|
|
In many cases, the resulting code will still look familiar to the imperative counterpart,
|
|
even if `funcheck' assures that it is purely functional. This, I believe, bridges the gap
|
|
that developers usually have to overcome by themselves.
|
|
|
|
To be a purely functional programming language, Go is missing too many features that would be
|
|
required to write concise functional code. The very basic type system\footnote{Not only
|
|
does Go not have polymorphism (yet), Go's type system is simple by design: there are no
|
|
implicit type conversions, no sum types (tagged unions, variant) and almost no type inference.
|
|
}, no advanced pattern matching and only explicit currying are all examples why Go is not useful
|
|
in day-to-day functional programming.
|
|
|
|
At the same time, the obvious nature of Go is exactly because it is missing all
|
|
of these features. The Go team explicitly tries not to include too many features within
|
|
the language in order to keep the complexity of code to a minimum\autocite{go-feature}.
|
|
The simplicity of the language is a key feature of Go and an important reason why it was
|
|
chosen to implement the ideas in the first place.
|
|
Especially for learning new concepts, hiding implementations and ideas behind features
|
|
may not be what is desired and helpful.
|
|
|
|
On another note, what has not been an aspect in this thesis is
|
|
performance. Go by itself is relatively performant, however functional constructs, for example
|
|
recursive function calls, come with a performance cost. While in purely functional languages
|
|
this can be optimised, Go cannot or does not want to do these optimisations\footnote{For example,
|
|
with tail call optimisation, the Go team explicitly decided not to do it because the stack trace
|
|
would be lost\autocite{go-tco-nope}}.
|
|
|
|
While the newly built-in functions do not have any low-hanging fruits in regards to optimisation,
|
|
they would benefit from more aggressive inlining\autocite{go-compiler-inline}, for example.
|
|
Benchmarking and optimising these functions was out of scope for this thesis, but may be tackled
|
|
in the future.
|
|
|
|
\newglossaryentry{sumtypes}{name=sum types,description={Sum types, often also called aggregated types,
|
|
variant or tagged union is a data structure that can hold one of several, predefined data types. For
|
|
example, Haskell's \mintinline{haskell}|Either| holds either a value of type A or type B. Similar to that,
|
|
\mintinline{haskell}|Maybe| can hold either a concrete value, or `Nothing'}}
|
|
|
|
The number one issue that still exists is the simple type system. Not only the lack of polymorphism, which
|
|
has been mitigated slightly by providing the most used higher-order functions as built-ins, but also the
|
|
lack of algebraic data types, especially \gls{sumtypes}.
|
|
|
|
Algebraic data types can be split up into two groups, product types and sum types.
|
|
Most product types can be built with Go too; records are basically
|
|
equal to structs, and tuples are not needed too often, as functions can just return multiple values.
|
|
Sum types however are not available in Go at all. It is possible to imitate sum types in Go
|
|
with interfaces (see the example code in Appendix~\ref{appendix:sum-types}), and ensure an
|
|
exhaustive match by a linter. This linter should have been implemented as part of this thesis.
|
|
However, after careful consideration, it has been decided that this will not be done
|
|
due to the simple reason that such a linter already exists\autocite{sushi-sumtypes}.
|
|
That linter could be merged with `funcheck', which is left as an exercise to the reader.
|
|
|
|
Further, a linter does not eliminate the fact that sum types are not properly integrated
|
|
into the language.
|
|
This may be an interesting area for further
|
|
research and implementation possibilities\footnote{There is a mention about sum types in the current
|
|
Go Generics Proposal\autocite{go-generics-proposal}, but the initial implementation of generics will
|
|
most likely not contain sum types}.
|