Ist Ruby funktional

Wenn die Liste der funktionalen Sprachen erstellt wird, dann tauchen Haskell, Scala, Erlang, F#, Clojure und einige andere Lisp-Varianten auf.

Wenn man sich anschaut, welche Merkmale funktionale Sprachen auszeichnen, dann stellt sich die Frage, ob das nicht alles mit Ruby auch machbar ist.

Schauen wir einmal was man so typischerweise findet, meist auf Englisch:

  • Functions as „first class citizen“
  • Closures
  • Pure Functions
  • Higher Order functions
  • Everything returns a value
  • Immutability
  • No hidden state
  • Prefer recursion over iteration (immutable loop variable…)

Funktionen existieren in Ruby also losgelöste Objekte, in verschiedenen Formen, z.B. als proc, als lambda, als anonymer Block und durch Referenzierung einer Methode über ihren Namen (Reflection).

Closures werden von Ruby problemlos unterstützt, bei all diesen Formen der Funktionen werden Variablen aus dem definierenden Kontext eingebunden, wo sie referenziert werden. Methoden kann man übrigens als Spezialfall von Closures ansehen, weil sie als Kontext das Objekt einbinden, zu dem sie gehören.

Unter “pure function” versteht man Funktionen, die den Funktionen aus der Mathematik entsprechen. Sie haben absolut keinen Seiteneffekt, sind reproduzierbar, können in beliebiger Zahl parallel ausgeführt werden und geben bei mehrfachen Aufrufen immer dasselbe Resultat. Sie eignen sich für Memoize, was nun eigentlich wieder ein Seiteneffekt ist, aber sozusagen ein transparenter. Man denke an sort() und sort!() in Ruby. Dies verlangt Disziplin vom Entwickler und gute Dokumentation.

“Higher Order Functions” sind Funktionen höherer Ordnung, die also selbst Funktionen als Parameter oder Rückgabewert haben. Das ist in der funktionalen Programmierung Routine und nicht so ein spezieller Spezialfall, den man mal alle paar Jahre benutzt, wie Funktionspointer in C. Typische Beispiele sind Methoden wie inject(), map(), group_by()… each() sollte man nur verwenden, wenn man die Seiteneffekte wirklich braucht.

Alle Ausdrücke haben einen Wert. Das ist recht gut in Ruby umgesetzt, z.B. x = if (...) ... else ... end kann man verwenden…

Immutibility (Unveränderbarkeit) ist die Achillesferse. Es wird nicht wirklich gut unterstützt. Man soll Variablen nicht neu zuweisen und auch nicht irgendwas mutieren. Warum nimmt man nicht freeze()? Wir brauchen ein deepfreeze(), aber was bedeutet das? Wie sieht es mit collections aus? Es gibt immer Möglichkeiten, diese unverändert zu lassen und mit jedem Schritt eine neue Collection zu produzieren. Dasselbe gilt für Zeichenketten.

“No hidden State”, also kein versteckter Zustand. Man kann Kontextobjekte haben und herumreichen. Zustand ist unerwünscht und sollte kontrolliert an wenigen Orten gehandhabt werden.

“Recursion instead of Iteration” steht für Rekursion statt Iteration. Funktionale Sprachen unterstützen Optimierung bei Tailrekursion (Endrekursion). Einige andere Sprachen, z.B. C mit gcc, Scala und viele Lisp-Dialekte, aber nicht Java, unterstützen diese Optimierung und erlauben es, zumindest Endrekursion ohne zu große Furcht einzusetzen. Bei Ruby hängt es von der Version und den Einstellungen ab, ist also mit Vorsicht zu genießen. Der Ruby-Ansatz ist es eher, die Iteratorn zu verwenden.

Fazit: Man kann mit ein paar Einschränkungen in Ruby funktional programmieren, aber es erfordert etwas mehr Disziplin, weil einige Dinge vom Entwickler beachtet werden müssen und nicht von der Sprache unterstützt werden.

Share

Zufällige Zeichenkette erzeugen

Oft braucht man so eine zufällige Zeichenkette, die nur aus bestimmten Zeichen bestehen darf.

Hier ist eine einfache Ruby-implementierung dafür:


#!/usr/bin/ruby

arr = ('a'...'z').to_a + ('A'...'Z').to_a + ('0'...'9').to_a + ['.', '/']
val = (0..16).inject("") do |a, x| i = (arr.size() * rand()).to_i;a + arr[i] end
puts val

Es wird eine 16-Zeichen lange Zeichenkette generiert, die aus den Zeichen [a-zA-Z0-9./] besteht.

Share

Jolla Mobiltelefon

Bekanntlich hat sich die Firma Nokia erst aus ihren eigenen Entwicklungen bezüglich Mobiltelefonsoftware und später auch aus dem zugehörigen Hardwaregeschäft zurückgezogen und erlaubt einer Nordamerikanischen Firma für eine gewisse Zeit, ihre Telefone mit “Nokia” zu benennen, etwa so wie für die Autofans “Volvo” auf Autos steht, die sicher nicht von der seit vielen Jahren auf ihr Kerngeschäft, nämlich Lkws, Baumaschinen und Busse, spezialisierten Firma Volvo hergestellt werden. Nun hat Nokia in den letzten Jahren viele gute Mitarbeiter verloren, die im Bereich der Mobiltelefonentwicklung tätig waren. Diese haben dann eine neue Firma, “Jolla”, gegründet. Bis hier ist das alles normal, oft gründen entlassene oder frustriert selber gegangene ehemalige Mitarbeiter eine Firma, mit der sie das machen wollen, was sie bei ihrem alten Arbeitgeber machen wollten, aber nicht durften. Manche von diesen Firmen sind dann sehr erfolgreich, aber gleich das ehemalige Kerngeschäft der einst größten und wichtigsten Firma Europas in so einer Startup-Firma neu aufzubauen ist schon recht ehrgeizig und man musste es immer mit einer gewissen Skepsis betrachten. Auch wenn Jolla dort eher ein Nischenanbieter und nicht mehr wie einst Nokia und danach bis heute Samsung Marktführer ist.

Nun ist aber Jolla seit einigen Monaten so weit und man kann die Telefone bestellen, bezahlen und mit ihnen sogar telefonieren. Ich habe mir so eines beschafft und die Grundfunktionen sind auch vorhanden und ganz brauchbar. Die Benutzeroberfläche ist etwas gewöhnungsbedürftig, was aber eher daran liegt, dass wir die Oberfläche von Android-Geräten gewohnt sind und hier einige Dinge im Detail etwas anders laufen. Typisch ist, dass es eine Art virtuellen Bildschirm gibt und dass man Applikationen verlässt, indem man vom rechten Rand kommend auf den Bildschirm streicht. Das ist besonders gut zu wissen für das “Tutorial”, das irgendwie immer wieder bei Starten des Gerätes hochkommt und für das man keine einfache Art findet, um es zu verlassen. Ein anderes häufiges Element sind Punktreihen oben links, die irgendwie eine Tiefe im Dialog angeben und mit denen man zurück zur nächst höheren Ebene kommt. Menüs bekommt man oft, indem man von oben in den Bildschirm hereinstreicht. Alles drei Dinge, die Android mit drei spezifischen Tasten gelöst hat.

Nun soll man Apps installieren können. Dafür sollen sowohl Android-Apps vom Google-Play-Store als auch native in C++ & Qt geschriebene Apps vom Jolla-Eigenen App-Store verfügbar sein. Mehr dazu kommt vielleicht, wenn ich damit Erfahrungen gesammelt habe. Da Jolla wie Android auf Linux basiert, wäre vielleicht ein xterm und die ganzen GNU-Tools und so etwas schön. Es sollte möglich sein. Für Android gibt es das auch, aber da muss man wohl alles in Java nochmal schreiben, um es in eine App zu bringen. Was ja passiert ist, man hat Apps mit den wichtigsten GNU-Tools oder zumindest gleichnamigen Java-Attrappen. Auf dem N900 war das alles einfach nativ dabei, weil es mit dem Maemo-Linux mitkam.

Share

Laptopnetzteile

Bei Mobiltelefonen hat es endlich geklappt, dass alle Telefone denselben Anschluss für USB-Kabel und Ladegerät unterstützen. Fast alle, nämlich genaugenommen alle außer Apple. Aber die überwältigende Mehrheit der Mobiltelefone hat denselben Anschluss und funktioniert mit denselben Ladegeräten.

So etwas wäre bei Laptops auch schön. Tatsache ist aber, dass jeder Hersteller eine Vielfalt von Modellen hat, die sich noch laufend ändern, typischerweise auch innerhalb derselben Modellbezeichnung, und die auch jeweils spezifische Netzteile brauchen. Wenn man sein Netzteil vergessen hat und in einen großen Computerladen geht, kann man das selbstverständlich bestellen, aber die Chance, dass ein passendes Teil in dem Laden oder in einem anderen Laden in einer größeren Stadt (z.B. Zürich) direkt erhältlich ist, ist vernachlässigbar. Das war schon vor 10-15 Jahren so.

Es wäre wirklich gut, wenn sich wie beim Mobiltelefon die Hersteller auf einen Standard für Netzteile für alle Laptops (meinetwegen wieder alle bis auf einen Hersteller mit einem angebissenen-Obst-Logo) einigen könnten. Ich glaube, darüber würden sich viele Kunden freuen. Aber sie schaffen es ja heute nicht einmal innerhalb ihrer eigenen Marke, was angeblich der Hersteller mit halb gegessenen Apfel immerhin geschafft haben soll, zumindest mit einer größeren Adaptersammlung.

So werden wir also weiterhin viel Elektronikmüll produzieren, weil gute Netzteile in den Müll wandern, wenn der Laptop dazu kaputt ist, und wir werden weiterhin ein paar Stunden mit der Fahrt verbringen, wenn wir das Netzteil einmal vergessen haben.

Share

Visit to Scala Days in Berlin 2014

Deutsch

Around mid of June 2014 I have been visiting the Scala Days in Berlin. Like usual these events contain a lot of speeches, which were distributed in four tracks, apart from the key notes. The event location was a cinama, like the Devoxx in Antwerp, but this time one that has been transformed to something else many years ago, but good projectors were available. Major topics where issues about compiler construction which is a hard task, but looked at with the right functional perspective it can be derived from the simple task of writing an interpreter. This helps understanding language constructs in Scala, but the idea was applied to many other areas as well, for example for compiling and optimizing SQL queries and for analyzing source code.

Another major topic was “streams”, which can be useful for web services. Other than traditional web services which usually receive the whole request before starting to process it, concepts where discussed for dealing with large requests whose size is painful or impossible to keep at once in memory or who are even unlimited in size. These can also be applied to websockets. This demands processing data as soon as useful parts have arrived.

Another minor, but very interesting topic was development of Android apps with Scala. The commonly known approach is off course Scaloid, but an alternative, Macroid, was presented. It looked quite promising, because it allows to write nice Android apps with less code. A major worry is that scala apps consume too much memory due to their additional libraries. Because Scala uses its own libraries on top of the usual preinstalled Java libraries which are about 5 MB in size, this can easily anihilate the attractiveness of Scala for modern smart phone development, unless we assume rooted devices which have the Scala libs preinstalled. But that would seriously limit the scope of the app. This is not as bad as it sounds, because the build process contains one step in which unnecessary classes are removed, so that we only install what is really needed. When going as crazy as running Akka on the cell phone it becomes quite a challenge to configure this step because Akka uses a lot of reflection and so all these reflective entry points need to be configured, leaving a wide door open for bugs that occur at runtime when some class is not found.

API design was another interesting talk. Many ideas were quite similar to what I have heard in a API design traing for Perl by Damian Conway a couple of years ago, but off course there are many interesting Scala specific aspects to the topic. It is surprisingly hard to obtain binary compatibility of classes and this even forces to ugly compromises. So always recompiling everything looks tempting, but is not always reasonable. So ugly compromises remain part of our world, even when we are working with Scala.

Share

Scala Days in Berlin

English

Am 16., 17. und 18. Juni 2014 war ich bei der Konferenz “Scala Days” in Berlin. Wie so oft bei diesen Veranstaltungen gibt es einen Haufen Vorträge, in diesem Fall bis auf die jeweilige “Keynote” jeweils vier gleichzeitig. Das Veranstaltungslokal war wie bei der Devoxx in Antwerpen ein Kino, allerdings in diesem Fall schon lange umgewidmet für andere Zwecke, aber gute Projektoren gab es noch. Große Themen waren Fragen des Compilerbaus und wie man mit der richtigen funktionalen Perspektive aus der relativ einfachen Aufgabe, einen Interpreter zu schreiben, zu der schwierigen Aufgabe kommt, einen Compiler zu schreiben. Das hilft sicher, Sprachkonstrukte in Scala zu verstehen, aber die Idee wurde auch auf andere Felder angewendet, etwa um SQL-Queries zu kompilieren und zu optimieren oder um mit einem aus Compilercode gebauten Programm Quelltexte zu analysieren.

Ein anderes großes Thema waren “Streams”, die für Webservices nützlich sein sollen. Im Gegensatz zu klassischen Webservices, bei denen man den ganzen Request erstmal in Empfang nimmt, wurden auch Konzepte behandelt, um sehr große oder quasi unbegrenzte Requests zu verarbeiten. Dazu muss man diese natürlich schon verarbeiten, sobald eine gewisse nutzbare Datenmenge angekommen ist.

Ein kleines, aber interessantes Thema war die Entwicklung von Android-Apps mit Scala. Bekannt ist als Ansatz dafür natürlich Scaloid, aber hier wurde Macroid, ein alternativer Ansatz vorgestellt. Es sah vielversprechend aus, dass man mit weniger Code gute Android-Apps schreiben kann. Eine große Sorge ist, dass diese Scala-Apps den Speicher sprengen. Weil sie zusätzlich zu den vorinstallierten Java-Libraries noch Scala-Libraries brauchen, die etwa 5 MB groß sind, vergeht einem schnell der Appetit, außer man setzt gerootete Android-Devices voraus, auf denen die Scala-Libraries vorinstalliert sind. Das Thema verliert aber ein bißchen seinen Schrecken, weil der Build-Prozess einen Schritt enthält, in dem unnötige Klassen aussortiert werden, so dass am Ende nur das installiert wird, was man wirklich braucht. Wenn man so weit geht, Akka auf dem Mobiltelefon laufen zu lassen, wird das aber spannend, weil Akka viel Reflection und damit sehr viel fehleranfällige Konfiguration für diesen Optimierungsschritt benötigt.

Interessant war auch das Thema API-Design. Vieles war deckungsgleich mit Dingen, die ich bei einer API-Design-Schulung für Perl von Damian Conway vor ein paar Jahren gehört hatte, aber es gibt natürlich Scala-spezifische Themen, die auch interessant sind. Es ist erstaunlisch schwierig, Binärkompatibilität von Klassen zu erzielen und zwingt auch zu unschönen Kompromissen. Aber die gehören wohl auch in der Scala-Welt zum Leben.

Share

Closures in C and Scala

Deutsch

Are closures at all possible in C, without falling back to writing some interpreter in C and using that interpreted langauge?

Function pointers alone are far less than what is needed for closures. But they are one of the building blocks. It is quite hard to get the signature right, but a typedef proves to be useful.

The next issue is that C does not allow inner functions by default and that it is not possible to automatically include a context, which is essential for the concept of closures.

But it is surprisingly easy to overcome that issue:

The function is defined before the function within which it should be meant to be defined. It has an additional parameter for some “context”-struct, which can be used to include variables from that context.

struct closure;
typedef int (*fun_type)(const struct closure *context, const int param);

This struct includes the variables and a function pointer:

struct closure {
int x;
fun_type fun;
};

Now the function definition in languages that support closures still have to be provided in some way and this is done anonymously with some mechanism called lambda or so, within another function or method whose variables are implicitely included. In a way methods can be considered a special case of this, since they include access to attributes of the enclosing object. In C all functions are defined in the regular way, but this time the fun_type signature needs to be observed. References to enclosed variables need to be bound by explicitely putting them into the context:

int f(const struct closure *context, const int param) {
return (context->x) + param;
}

The second order function that returns the closure can now be defined. We only have to accept the C notation, but it is fully equivalent to closures, just a little bit more noise:

struct closure *adder(int x) {
struct closure *result = malloc(sizeof(struct closure));
result->x = x;
result->fun = f;
return result;
}

Off course memory management is always an issue to observe in C…

Now the whole thing can be used like this:

int main(int argc, char *argv[]) {
int retcode;
if (argc < 2) {
usage(argv[0], "not enough parameters");
}
int x = atoi(argv[1]);
int y = atoi(argv[2]);
struct closure *cl = adder(x);
int i;
for (i = 0; i < y; i++) {
printf("cl(%d)=%d\n", i, cl->fun(cl, i));
}
}

The complete example can be found on github.

Off course the same is much shorter and more elegant in Scala:

object Closure {
def main(args : Array[String]) : Unit = {
val x : Int = args(0).toInt
val y : Int = args(1).toInt
val f : ((Int) => Int) = adder(x);
val arr = (1 to y).map(f)
println(arr.toString)
}

def adder(x : Int) : ((Int) => Int) = {
(y => x+y)
}
}

Even this can be found on
github.

Share

Closures in C

English

Geht so etwas überhaupt?

Ein Element sind die Funktionspointer. Es ist immer recht schwierig, die Signatur davon richtig zu treffen, aber ein typedef hilft.

Die nächste Schwierigkeit ist, dass C normalerweise keine inneren Funktionen erlaubt und dass man auch keinen Kontext einbinden kann.

Das lässt sich lösen:

Die Funktion hat einen weiteren Parameter für ein Context-Struct, in dem die Variablen eingebunden werden.

struct closure;
typedef int (*fun_type)(const struct closure *context, const int param);

Das sieht so aus, dass dort die Variable(n) und ein Funktionspointer enthalten sind:

struct closure {
  int x;
  fun_type fun;
};

Nun muss man die Funktionen ja in für Closures gemachten Programmiersprachen trotzem noch hinschreiben, aber anonym und am richtigen Ort.
In C muss man alle möglichen Funktionen regulär, aber mit der fun_type-Signatur von oben definieren. Die Referenzen auf die eingebundenen Variablen müsse vom context-Parameter kommen, statt implizit verfügbar zu bleiben, z.B.:

int f(const struct closure *context, const int param) {
  return (context->x) + param;
}

Die Funktion 2. Ordnung, die die Closure zurückgibt, kann man nun auch definieren, man muss nur die C-Schreibweise akzeptieren und statt die Funktion an Ort und Stelle zu definieren eine der vorher definierten Funktionen referenzieren. Auch das ist äquivalent zu Closures:

struct closure *adder(int x) {
  struct closure *result = malloc(sizeof(struct closure));
  result->x = x;
  result->fun = f;
  return result;
}

Und so kann man das ganze dann verwenden:

int main(int argc, char *argv[]) {
  int retcode;
  if (argc < 2) {
    usage(argv[0], "not enough parameters");
  }
  int x = atoi(argv[1]);
  int y = atoi(argv[2]);
  struct closure *cl = adder(x);
  int i;
  for (i = 0; i < y; i++) {
    printf("cl(%d)=%d\n", i, cl->fun(cl, i));
  }
}

Das komplette Beispiel ist auf github.

In Scala sieht das natürlich viel kürzer aus:

object Closure {
  def main(args : Array[String]) : Unit = {
    val x : Int = args(0).toInt
    val y : Int = args(1).toInt
    val f : ((Int) => Int) = adder(x);
    val arr = (1 to y).map(f)
    println(arr.toString)
  }

  def adder(x : Int) : ((Int) => Int) = {
    (y => x+y)
  }
}

Auch das ist auf Github

Share

Getter und Setter

In der objektorientierten Programmierung gilt es als fortschrittlich, getter und setter zu verwenden, statt auf Attribute direkt zuzugreifen, weil das einem die Flexibilität gibt, später auf berechnete Attribute umzuschwenken. Etwas hässlich ist das, weil die getter und setter, etwas willkürlich den Attributnamen mit so einem vorangestellten “get” oder “is” oder “set” und eventueller Umwandlung der Groß- und Kleinschreibung einzelner Zeichen versehen. Eine subtile Besonderheit ist, dass es verwirrend wird, wenn Attributnamen mit “get”, “is” oder “set” beginnen. Gerade Boolean-Attribute ist man versucht mit “hasSomething”, “isSomething”, “doesSomething”, “canSomething”, “mustSomething”,… o.ä. zu benennen, was dann zu dem Getter “getIsSomething()” oder “isIsSomething()” führt. Oder man lässt in dem Fall das Präfix weg, aber nur beim Getter…

Schöner ist es, wenn man Getter und Setter natürlich bennen kann, wie das z.B. in C#, Ruby und Scala der Fall ist: Man schreibt den Getter so, als würde man das Attribut public machen und darauf zugreifen, aber hat durch die entsprechenden Sprachkonstrukte die Möglichkeit, die Getter und Setter durch andere Implementierungen zu ersetzen, wenn der Bedarf besteht. Es gibt sicher wichtigeres, aber das ist zumindest schöner, lesbarer und deshalb weniger fehleranfällig. Und sprachlich auch sauberer als diese “halb-magic”-Bedeutung von “get…”, “set…” und “is…”.

Im Grunde genommen sind aber auch Zugriffe auf Listen und Maps oft eine Art Getter und Setter:
y=a.get(pos) könnte man auch als y=a[pos] schreiben wollen, entsprechend a.put(pos, x) auch als a[pos]=x. Dasselbe gilt für Maps mit u=m.get(k), was schöner und intuitiver als etwas in der Art von u=m[k] wäre. Oder statt m.put(k, v) so etwas wie m[k]=v. Aus genügend abstrakter Sicht ist das nicht so wichtig, aber wenn die Lesbarkeit sich verbessert, macht man weniger Fehler und so hat man pragmatisch gesehen einen kleinen Qualitäts und Effizienzgewinn mit der Zuweisungsschreibweise.

Nun sind aber Setter in Wirklichkeit oft problematisch. Es ist immer gut, Objekte immutable zu haben, weil man sie dann problemloser zwischen Threads herumreichen kann, ohne dass es zu Fehler bei gleichzeitigen Zugriffen kommen kann. Nun stellt sich aber die Frage, wie man dann das Objekt konstruieren soll. Ein Konstruktor mit positionalen Parametern ist zwar möglich, aber oft nicht sehr lesbar, wenn die Parameterliste nicht völlig überschaubar und klar ist. So etwas wie benannte Parameter könnte sehr viel helfen. Ein anderes Muster ist es, ein temporäres Objekt mit Settern aufzubauen und dann daraus das eigenteliche unveränderliche (immutable) Objekt zu generieren. Man kann dafür spezielle Setter nehmen, die jeweils das veränderte Objekt zurückgeben und das etwa so etwas schreiben wie
SomethingImmutable s = new SomethingTemp().setX(x).setY(y).setZ(z).toSomething(),
was nicht superschön ist, aber wenn man auf Java Wert legt, doch eine Möglichkeit.

Hier zeigt sich auch, warum es so schön ist, wenn man Listen und Maps und vielleicht andere Collections einfach mit allen Elementen konstruieren und dann gleich immutable machen kann. In Java geht das für Listen immerhin schon mit
Collections.immutableList(Arrays.asList(a, b, c, d, e, f, g, h))
machen. Wobei diese Konstruktion relativ neu ist und wegen der Konstruktionsphase Collections nicht defaultmäßig immutable sein können. Immerhin könnte man ein
Arrays.asImmutableList(T..t)
definieren. Oder eine Methode auf List
.immutable().
Schöner (klarer, lesbarer, weniger fehleranfällig) wäre es aber, wenn man das als
[a, b, c, d, e, f, g, h]
schreiben könnte. Für die Ausgabe von Listen mittels toString() wird so etwas ja schon verstanden. Für das Konstruieren von Maps gibt es in anderen Programmiersprachen auch Schreibweisen, die etwa so aussehen wie
m = { k1 => v1, k2 => v2, k3 => v3, k4 => v4}.
Will man sich normalerweise dafür interessieren, welche Map-Implementierung jetzt genommen wird? So etwas ließe sich als
m = new TreeMap{k1 => v1, k2 => v2, k3 => v3, k4 => v4}
schreiben. Solche Dinge waren für Java 8 vorgesehen, sind aber wohl in letzter Minute rausgeflogen oder auf Java 9 verschoben worden.

Share

Neue Projekte

Ab 1. September 2014 bin ich für neue Projekte verfügbar.

Share