diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 000000000..57d4641d1 --- /dev/null +++ b/.bundle/config @@ -0,0 +1,3 @@ +--- +BUNDLE_PATH: vendor/bundle +BUNDLE_DISABLE_SHARED_GEMS: '1' diff --git a/.gitignore b/.gitignore index f11e63506..c05f72793 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ _site/ -.DS_Store \ No newline at end of file +.DS_Store +vendor/bundle diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..167ee20bb --- /dev/null +++ b/Gemfile @@ -0,0 +1,2 @@ +source 'https://rubygems.org' +gem 'jekyll' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..0a04a1a4f --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,39 @@ +GEM + remote: https://rubygems.org/ + specs: + colorator (0.1) + ffi (1.9.10) + jekyll (3.0.1) + colorator (~> 0.1) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 3.0) + mercenary (~> 0.3.3) + rouge (~> 1.7) + safe_yaml (~> 1.0) + jekyll-sass-converter (1.3.0) + sass (~> 3.2) + jekyll-watch (1.3.0) + listen (~> 3.0) + kramdown (1.9.0) + liquid (3.0.6) + listen (3.0.5) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + mercenary (0.3.5) + rb-fsevent (0.9.6) + rb-inotify (0.9.5) + ffi (>= 0.5.0) + rouge (1.10.1) + safe_yaml (1.0.4) + sass (3.4.19) + +PLATFORMS + ruby + +DEPENDENCIES + jekyll + +BUNDLED WITH + 1.10.6 diff --git a/README.md b/README.md index 3f5ae2eb2..e50306d1d 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,56 @@ This repository contains the _static_ source of [scala-lang.org](http://scala-la It's a static site generated by [Jekyll](https://github.com/mojombo/jekyll), and uses a whole host of open-source tools including a touch of Twitter's Bootstrap. -## Dependencies +## Dependencies ## -You'll need Jekyll installed to generate and test the site. To get it, most people can install via RubyGems: +This site uses a Jekyll, a Ruby framework. You'll need Ruby and Bundler installed; see [Jekyll installation instructions](http://jekyllrb.com/docs/installation/) for the details. - gem install jekyll +## Building & Viewing ## -OSX users might have to update RubyGems: +cd into the directory where you cloned this repository, then install the required gems with `bundle install`. This will automatically put the gems into `./vendor/bundle`. - sudo gem update --system +Start the server in the context of the bundle: -If in doubt, head over to the [Jekyll wiki](https://github.com/mojombo/jekyll/wiki) for installation instructions. + bundle exec jekyll serve -i -## Building +The generated site is available at `http://localhost:4000` -After cloning, cd into the `scala/scala-lang` directory and run: +Jekyll will automatically watch for changes on the filesystem, and regenerate the site. It can take a few minutes for your changes to appear. Watch the output from `jekyll serve`. When you start up you'll see this: - jekyll serve +bundle exec jekyll serve -i +Configuration file: /home/soc/Entwicklung/scala-lang/_config.yml + Source: /home/soc/Entwicklung/scala-lang + Destination: /home/soc/Entwicklung/scala-lang/_site + Incremental build: enabled + Generating... + done in 1.04 seconds. + Auto-regeneration: enabled for '/home/soc/Entwicklung/scala-lang' +Configuration file: /home/soc/Entwicklung/scala-lang/_config.yml + Server address: http://127.0.0.1:4000/ + Server running... press ctrl-c to stop. -To see the generated site, just visit `http://localhost:4000`. + + $ bundle exec jekyll serve -i + Configuration file: /Users/ben/src/scala.github.com/_config.yml + Source: /Users/ben/src/scala.github.com + Destination: /Users/ben/src/scala.github.com/_site + Incremental build: enabled + Generating... + done in 1.04 seconds. + Auto-regeneration: enabled for '/Users/ben/src/scala-lang' + +When you change a file, this output will tell you that jekyll is regenerating. It's not done until it says `done.` + + Server running... press ctrl-c to stop. + Regenerating: 1 file(s) at 2014-11-29 09:19:04 ...done in 0.9704294 seconds. + Regenerating: 3 file(s) at 2014-11-29 09:21:39 ...done in 1.9161814 seconds. + Regenerating: 2 file(s) at 2014-11-29 09:25:10 ...done in 1.2371298 seconds. + Regenerating: 2 file(s) at 2014-11-29 09:27:49 + +If you get `incompatible encoding` errors when generating the site under Windows, then ensure that the +console in which you are running jekyll can work with UTF-8 characters. As described in the blog +[Solving UTF problem with Jekyll on Windows](http://joseoncode.com/2011/11/27/solving-utf-problem-with-jekyll-on-windows/) +you have to execute `chcp 65001`. This command is best added to the `jekyll.bat`-script. ## YAML Front Matter diff --git a/_config.yml b/_config.yml index da3698bc3..fb6d69cfd 100644 --- a/_config.yml +++ b/_config.yml @@ -2,4 +2,6 @@ title: The Scala Programming Language scalaversion: "2.11.7" devscalaversion: "2.12.0-M3" + baseurl: "" +exclude: ["vendor"] \ No newline at end of file diff --git a/_includes/footer.html b/_includes/footer.html index 6236d409f..2030decfd 100644 --- a/_includes/footer.html +++ b/_includes/footer.html @@ -1,105 +1,2 @@ - - - - - - - - - - - - - - - - - - - - - - - - - {% unless page.layout == 'page' %} - - - - {% endunless %} - - - - - +{% include footertop.html %} +{% include footerbottom.html %} \ No newline at end of file diff --git a/_includes/footerbottom.html b/_includes/footerbottom.html new file mode 100644 index 000000000..b605728ee --- /dev/null +++ b/_includes/footerbottom.html @@ -0,0 +1,2 @@ + + diff --git a/_includes/footertop.html b/_includes/footertop.html new file mode 100644 index 000000000..4983a6cbd --- /dev/null +++ b/_includes/footertop.html @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + {% unless page.layout == 'page' %} + + + + {% endunless %} + + + diff --git a/_includes/headerbottom.html b/_includes/headerbottom.html index d9e11dede..c87827902 100644 --- a/_includes/headerbottom.html +++ b/_includes/headerbottom.html @@ -1,3 +1,2 @@ - diff --git a/_layouts/glossary.html b/_layouts/glossary.html new file mode 100644 index 000000000..e3fe580c3 --- /dev/null +++ b/_layouts/glossary.html @@ -0,0 +1,67 @@ +--- +layout: default +--- + +{% include headertop.html %} + +{% include headerbottom.html %} + +
+ +
+
+ +
+
+ +
+
+

{{ page.title }}

+
+
+ +
+
+
+ {% if page.by %} +
Written By: {{ page.by }}
+ {% endif %} +
+
Glossary from the definitive book on Scala, Programming in Scala.

+
+
+ + +
+ {{ content }} +
+
+
+ +
+
+
+ +{% include footertop.html %} + +{% include footerbottom.html %} diff --git a/de/tutorial/index.md b/de/tutorial/index.md new file mode 100644 index 000000000..b240e62af --- /dev/null +++ b/de/tutorial/index.md @@ -0,0 +1,632 @@ +--- +layout: page +title: Ein Scala Tutorial für Java Programmierer +overview: scala-for-java-programmers + +disqus: true +multilingual-overview: true +language: de +by: Michel Schinz und Philipp Haller, deutsche Übersetzung von Christian Krause +--- + +## Einleitung + +Dieses Tutorial dient einer kurzen Vorstellung der Programmiersprache Scala und deren Compiler. Sie +ist für fortgeschrittene Programmierer gedacht, die sich einen Überblick darüber verschaffen wollen, +wie man mit Scala arbeitet. Grundkenntnisse in Objekt-orientierter Programmierung, insbesondere +Java, werden vorausgesetzt. + +## Das erste Beispiel + +Als erstes folgt eine Implementierung des wohlbekannten *Hallo, Welt!*-Programmes. Obwohl es sehr +einfach ist, eignet es sich sehr gut, Scalas Funktionsweise zu demonstrieren, ohne dass man viel +über die Sprache wissen muss. + + object HalloWelt { + def main(args: Array[String]) { + println("Hallo, Welt!") + } + } + +Die Struktur des Programmes sollte Java Anwendern bekannt vorkommen: es besteht aus einer Methode +namens `main`, welche die Kommandozeilenparameter als Feld (Array) von Zeichenketten (String) +übergeben bekommt. Der Körper dieser Methode besteht aus einem einzelnen Aufruf der vordefinierten +Methode `println`, die die freundliche Begrüßung als Parameter übergeben bekommt. Weiterhin hat die +`main`-Methode keinen Rückgabewert - sie ist also eine Prozedur. Daher ist es auch nicht notwendig, +einen Rückgabetyp zu spezifizieren. + +Was Java-Programmierern allerdings weniger bekannt sein sollte, ist die Deklaration `object +HalloWelt`, welche die Methode `main` enthält. Eine solche Deklaration stellt dar, was gemeinhin als +*Singleton Objekt* bekannt ist: eine Klasse mit nur einer Instanz. Im Beispiel oben werden also mit +dem Schlüsselwort `object` sowohl eine Klasse namens `HalloWelt` als auch die dazugehörige, +gleichnamige Instanz definiert. Diese Instanz wird erst bei ihrer erstmaligen Verwendung erstellt. + +Dem aufmerksamen Leser ist vielleicht aufgefallen, dass die `main`-Methode nicht als `static` +deklariert wurde. Der Grund dafür ist, dass statische Mitglieder (Attribute oder Methoden) in Scala +nicht existieren. Die Mitglieder von Singleton Objekten stellen in Scala dar, was Java und andere +Sprachen mit statischen Mitgliedern erreichen. + +### Das Beispiel kompilieren + +Um das obige Beispiel zu kompilieren, wird `scalac`, der Scala-Compiler verwendet. `scalac` arbeitet +wie die meisten anderen Compiler auch: er akzeptiert Quellcode-Dateien als Parameter, einige weitere +Optionen, und übersetzt den Quellcode in Java-Bytecode. Dieser Bytecode wird in ein oder mehrere +Java-konforme Klassen-Dateien, Dateien mit der Endung `.class`, geschrieben. + +Schreibt man den obigen Quellcode in eine Datei namens `HalloWelt.scala`, kann man diese mit dem +folgenden Befehl kompilieren (das größer-als-Zeichen `>` repräsentiert die Eingabeaufforderung und +sollte nicht mit geschrieben werden): + + > scalac HalloWelt.scala + +Damit werden einige Klassen-Dateien in das aktuelle Verzeichnis geschrieben. Eine davon heißt +`HalloWelt.class` und enthält die Klasse, die direkt mit dem Befehl `scala` ausgeführt werden kann, +was im folgenden Abschnitt erklärt wird. + +### Das Beispiel ausführen + +Sobald kompiliert, kann ein Scala-Programm mit dem Befehl `scala` ausgeführt werden. Die Anwendung +ist dem Befehl `java`, mit dem man Java-Programme ausführt, nachempfunden und akzeptiert dieselben +Optionen. Das obige Beispiel kann demnach mit folgendem Befehl ausgeführt werden, was das erwartete +Resultat ausgibt: + + > scala -classpath . HalloWelt + Hallo, Welt! + +## Interaktion mit Java + +Eine Stärke der Sprache Scala ist, dass man mit ihr sehr leicht mit Java interagieren kann. Alle +Klassen des Paketes `java.lang` stehen beispielsweise automatisch zur Verfügung, während andere +explizit importiert werden müssen. + +Als nächstes folgt ein Beispiel, was diese Interoperabilität demonstriert. Ziel ist es, das aktuelle +Datum zu erhalten und gemäß den Konventionen eines gewissen Landes zu formatieren, zum Beispiel +Frankreich. + +Javas Klassen-Bibliothek enthält viele nützliche Klassen, beispielsweise `Date` und `DateFormat`. +Dank Scala Fähigkeit, nahtlos mit Java zu interoperieren, besteht keine Notwendigkeit, äquivalente +Klassen in der Scala Klassen-Bibliothek zu implementieren - man kann einfach die entsprechenden +Klassen der Java-Pakete importieren: + + import java.util.{Date, Locale} + import java.text.DateFormat + import java.text.DateFormat._ + + object FrenchDate { + def main(args: Array[String]) { + val now = new Date + val df = getDateInstance(LONG, Locale.FRANCE) + println(df format now) + } + } + +Scala Import-Anweisung ähnelt sehr der von Java, obwohl sie viel mächtiger ist. Mehrere Klassen des +gleichen Paketes können gleichzeitig importiert werden, indem sie, wie in der ersten Zeile, in +geschweifte Klammern geschrieben werden. Ein weiterer Unterschied ist, dass, wenn man alle +Mitglieder eines Paketes importieren will, einen Unterstrich (`_`) anstelle des Asterisk (`*`) +verwendet. Der Grund dafür ist, dass der Asterisk ein gültiger Bezeichner in Scala ist, +beispielsweise als Name für Methoden, wie später gezeigt wird. Die Import-Anweisung der dritten +Zeile importiert demnach alle Mitglieder der Klasse `DateFormat`, inklusive der statischen Methode +`getDateInstance` und des statischen Feldes `LONG`. + +Innerhalb der `main`-Methode wird zuerst eine Instanz der Java-Klasse `Date` erzeugt, welche +standardmäßig das aktuelle Datum enthält. Als nächstes wird mithilfe der statischen Methode +`getDateInstance` eine Instanz der Klasse `DateFormat` erstellt. Schließlich wird das aktuelle Datum +gemäß der Regeln der lokalisierten `DateFormat`-Instanz formatiert ausgegeben. Außerdem +veranschaulicht die letzte Zeile eine interessante Fähigkeit Scalas Syntax: Methoden, die nur einen +Parameter haben, können in der Infix-Syntax notiert werden. Dies bedeutet, dass der Ausdruck + + df format now + +eine andere, weniger verbose Variante des folgenden Ausdruckes ist: + + df.format(now) + +Dies scheint nur ein nebensächlicher, syntaktischer Zucker zu sein, hat jedoch bedeutende +Konsequenzen, wie im folgenden Abschnitt gezeigt wird. + +Um diesen Abschnitt abzuschließen, soll bemerkt sein, dass es außerdem direkt in Scala möglich ist, +von Java-Klassen zu erben sowie Java-Schnittstellen zu implementieren. + +## Alles ist ein Objekt + +Scala ist eine pur Objekt-orientierte Sprache, in dem Sinne dass *alles* ein Objekt ist, Zahlen und +Funktionen eingeschlossen. Der Unterschied zu Java ist, dass Java zwischen primitiven Typen, wie +`boolean` und `int`, und den Referenz-Typen unterscheidet und es nicht erlaubt ist, Funktionen wie +Werte zu behandeln. + +### Zahlen sind Objekte + +Zahlen sind Objekte und haben daher Methoden. Tatsächlich besteht ein arithmetischer Ausdruck wie +der folgende + + 1 + 2 * 3 / x + +exklusiv aus Methoden-Aufrufen, da es äquivalent zu folgendem Ausdruck ist, wie in vorhergehenden +Abschnitt gezeigt wurde: + + (1).+(((2).*(3))./(x)) + +Dies bedeutet außerdem, dass `+`, `*`, etc. in Scala gültige Bezeichner sind. + +Die Zahlen umschließenden Klammern der zweiten Variante sind notwendig, weil Scalas lexikalischer +Scanner eine Regel zur längsten Übereinstimmung der Token verwendet. Daher würde der folgende +Ausdruck: + + 1.+(2) + +in die Token `1.`, `+`, und `2` zerlegt werden. Der Grund für diese Zerlegung ist, dass `1.` eine +längere, gültige Übereinstimmung ist, als `1`. Daher würde das Token `1.` als das Literal `1.0` +interpretiert, also als Gleitkommazahl anstatt als Ganzzahl. Den Ausdruck als + + (1).+(2) + +zu schreiben, verhindert also, dass `1.` als Gleitkommazahl interpretiert wird. + +### Funktionen sind Objekte + +Vermutlich überraschender für Java-Programmierer ist, dass auch Funktionen in Scala Objekte sind. +Daher ist es auch möglich, Funktionen als Parameter zu übergeben, als Werte zu speichern, und von +anderen Funktionen zurückgeben zu lassen. Diese Fähigkeit, Funktionen wie Werte zu behandeln, ist +einer der Grundsteine eines sehr interessanten Programmier-Paradigmas, der *funktionalen +Programmierung*. + +Ein sehr einfaches Beispiel, warum es nützlich sein kann, Funktionen wie Werte zu behandeln, ist +eine Timer-Funktion, deren Ziel es ist, eine gewisse Aktion pro Sekunde durchzuführen. Wie übergibt +man die durchzuführende Aktion? Offensichtlich als Funktion. Diese einfache Art der Übergabe einer +Funktion sollte den meisten Programmieren bekannt vorkommen: dieses Prinzip wird häufig bei +Schnittstellen für Rückruf-Funktionen (call-back) verwendet, die ausgeführt werden, wenn ein +bestimmtes Ereignis eintritt. + +Im folgenden Programm akzeptiert die Timer-Funktion `oncePerSecond` eine Rückruf-Funktion als +Parameter. Deren Typ wird `() => Unit` geschrieben und ist der Typ aller Funktionen, die keine +Parameter haben und nichts zurück geben (der Typ `Unit` ist das Äquivalent zu `void`). Die +`main`-Methode des Programmes ruft die Timer-Funktion mit der Rückruf-Funktion auf, die einen Satz +ausgibt. In anderen Worten: das Programm gibt endlos den Satz "Die Zeit vergeht wie im Flug." +einmal pro Sekunde aus. + + object Timer { + def oncePerSecond(callback: () => Unit) { + while (true) { + callback() + Thread sleep 1000 + } + } + + def timeFlies() { + println("Die Zeit vergeht wie im Flug.") + } + + def main(args: Array[String]) { + oncePerSecond(timeFlies) + } + } + +Weiterhin ist zu bemerken, dass, um die Zeichenkette auszugeben, die in Scala vordefinierte Methode +`println` statt der äquivalenten Methode in `System.out` verwendet wird. + +#### Anonyme Funktionen + +Während das obige Programm schon leicht zu verstehen ist, kann es noch verbessert werden. Als erstes +sei zu bemerken, dass die Funktion `timeFlies` nur definiert wurde, um der Funktion `oncePerSecond` +als Parameter übergeben zu werden. Dieser nur einmal verwendeten Funktion einen Namen zu geben, +scheint unnötig und es wäre angenehmer, sie direkt mit der Übergabe zu erstellen. Dies ist in Scala +mit *anonymen Funktionen* möglich, die eine Funktion ohne Namen darstellen. Die überarbeitete +Variante des obigen Timer-Programmes verwendet eine anonyme Funktion anstatt der Funktion +`timeFlies`: + + object TimerAnonymous { + def oncePerSecond(callback: () => Unit) { + while (true) { + callback() + Thread sleep 1000 + } + } + + def main(args: Array[String]) { + oncePerSecond(() => println("Die Zeit vergeht wie im Flug.")) + } + } + +Die anonyme Funktion erkennt man an dem Rechtspfeil `=>`, der die Parameter der Funktion von deren +Körper trennt. In diesem Beispiel ist die Liste der Parameter leer, wie man an den leeren Klammern +erkennen kann. Der Körper der Funktion ist derselbe, wie bei der `timeFlies` Funktion des +vorangegangenen Beispiels. + +## Klassen + +Wie weiter oben zu sehen war, ist Scala eine pur Objekt-orientierte Sprache, und als solche enthält +sie das Konzept von Klassen (der Vollständigkeit halber soll bemerkt sein, dass nicht alle +Objekt-orientierte Sprachen das Konzept von Klassen unterstützen, aber Scala ist keine von denen). +Klassen in Scala werden mit einer ähnlichen Syntax wie Java deklariert. Ein wichtiger Unterschied +ist jedoch, dass Scalas Klassen Argumente haben. Dies soll mit der folgenden Definition von +komplexen Zahlen veranschaulicht werden: + + class Complex(real: Double, imaginary: Double) { + def re() = real + def im() = imaginary + } + +Diese Klasse akzeptiert zwei Argumente, den realen und den imaginären Teil der komplexen Zahl. Sie +müssen beim Erzeugen einer Instanz der Klasse übergeben werden: + + val c = new Complex(1.5, 2.3) + +Weiterhin enthält die Klasse zwei Methoden, `re` und `im`, welche als Zugriffsfunktionen (Getter) +dienen. Außerdem soll bemerkt sein, dass der Rückgabe-Typ dieser Methoden nicht explizit deklariert +ist. Der Compiler schlussfolgert ihn automatisch, indem er ihn aus dem rechten Teil der Methoden +ableitet, dass der Rückgabewert vom Typ `Double` ist. + +Der Compiler ist nicht immer fähig, auf den Rückgabe-Typ zu schließen, und es gibt leider keine +einfache Regel, vorauszusagen, ob er dazu fähig ist oder nicht. In der Praxis stellt das +üblicherweise kein Problem dar, da der Compiler sich beschwert, wenn es ihm nicht möglich ist. +Scala-Anfänger sollten versuchen, Typ-Deklarationen, die leicht vom Kontext abzuleiten sind, +wegzulassen, um zu sehen, ob der Compiler zustimmt. Nach einer gewissen Zeit, bekommt man ein Gefühl +dafür, wann man auf diese Deklarationen verzichten kann und wann man sie explizit angeben sollte. + +### Methoden ohne Argumente + +Ein Problem der obigen Methoden `re` und `im` ist, dass man, um sie zu verwenden, ein leeres +Klammerpaar hinter ihren Namen anhängen muss: + + object ComplexNumbers { + def main(args: Array[String]) { + val c = new Complex(1.2, 3.4) + println("imaginary part: " + c.im()) + } + } + +Besser wäre es jedoch, wenn man den realen und imaginären Teil so abrufen könnte, als wären sie +Felder, also ohne das leere Klammerpaar. Mit Scala ist dies möglich, indem Methoden *ohne Argumente* +definiert werden. Solche Methoden haben keine Klammern nach ihrem Namen, weder bei ihrer Definition +noch bei ihrer Verwendung. Die Klasse für komplexe Zahlen kann demnach folgendermaßen umgeschrieben +werden: + + class Complex(real: Double, imaginary: Double) { + def re = real + def im = imaginary + } + +### Vererbung und Überschreibung + +Alle Klassen in Scala erben von einer Oberklasse. Wird keine Oberklasse angegeben, wie bei der +Klasse `Complex` des vorhergehenden Abschnittes, wird implizit `scala.AnyRef` verwendet. + +Außerdem ist es möglich, von einer Oberklasse vererbte Methoden zu überschreiben. Dabei muss jedoch +explizit das Schlüsselwort `override` angegeben werden, um versehentliche Überschreibungen zu +vermeiden. Als Beispiel soll eine Erweiterung der Klasse `Complex` dienen, die die Methode +`toString` neu definiert: + + class Complex(real: Double, imaginary: Double) { + def re = real + def im = imaginary + + override def toString() = + "" + re + (if (im < 0) "" else "+") + im + "i" + } + +## Container-Klassen und Musterabgleiche + +Eine Datenstruktur, die häufig in Programmen vorkommt, ist der Baum. Beispielsweise repräsentieren +Interpreter und Compiler Programme intern häufig als Bäume, XML-Dokumente sind Bäume und einige +Container basieren auf Bäumen, wie Rot-Schwarz-Bäume. + +Als nächstes wird anhand eines kleinen Programmes für Berechnungen gezeigt, wie solche Bäume in +Scala repräsentiert und manipuliert werden können. Das Ziel dieses Programmes ist, einfache +arithmetische Ausdrücke zu manipulieren, die aus Summen, Ganzzahlen und Variablen bestehen. +Beispiele solcher Ausdrücke sind: `1+2` und `(x+x)+(7+y)`. + +Dafür muss zuerst eine Repräsentation für die Ausdrücke gewählt werden. Die natürlichste ist ein +Baum, dessen Knoten Operationen (Additionen) und dessen Blätter Werte (Konstanten und Variablen) +darstellen. + +In Java würde man solche Bäume am ehesten mithilfe einer abstrakten Oberklasse für den Baum und +konkreten Implementierungen für Knoten und Blätter repräsentieren. In einer funktionalen Sprache +würde man algebraische Datentypen mit dem gleichen Ziel verwenden. Scala unterstützt das Konzept +einer Container-Klasse (case class), die einen gewissen Mittelweg dazwischen darstellen. Der +folgenden Quellcode veranschaulicht deren Anwendung: + + abstract class Tree + case class Sum(l: Tree, r: Tree) extends Tree + case class Var(n: String) extends Tree + case class Const(v: Int) extends Tree + +Die Tatsache, dass die Klassen `Sum`, `Var` und `Const` als Container-Klassen deklariert sind, +bedeutet, dass sie sich in einigen Gesichtspunkten von normalen Klassen unterscheiden: + +- das Schlüsselwort `new` ist nicht mehr notwendig, um Instanzen dieser Klassen zu erzeugen (man + kann also `Const(5)` anstelle von `new Const(5)` schreiben) +- Zugriffsfunktionen werden automatisch anhand der Parameter des Konstruktors erstellt (man kann + den Wert `v` einer Instanz `c` der Klasse `Const` erhalten, indem man `c.v` schreibt) +- der Compiler fügt Container-Klassen automatisch Implementierungen der Methoden `equals` und + `hashCode` hinzu, die auf der *Struktur* der Klassen basieren, anstelle deren Identität +- außerdem wird eine `toString`-Methode bereitgestellt, die einen Wert in Form der Quelle + darstellt (der String-Wert des Baum-Ausdruckes `x+1` ist `Sum(Var(x),Const(1))`) +- Instanzen dieser Klassen können mithilfe von Musterabgleichen zerlegt werden, wie weiter unten + zu sehen ist + +Da jetzt bekannt ist, wie die Datenstruktur der arithmetischen Ausdrücke repräsentiert wird, können +jetzt Operationen definiert werden, um diese zu manipulieren. Der Beginn dessen soll eine Funktion +darstellen, die Ausdrücke in einer bestimmten *Umgebung* auswertet. Das Ziel einer Umgebung ist es, +Variablen Werte zuzuweisen. Beispielsweise wird der Ausdruck `x+1` in der Umgebung, die der Variable +`x` den Wert `5` zuweist, geschrieben als `{ x -> 5 }`, mit dem Resultat `6` ausgewertet. + +Demnach muss ein Weg gefunden werden, solche Umgebungen auszudrücken. Dabei könnte man sich für eine +assoziative Datenstruktur entscheiden, wie eine Hash-Tabelle, man könnte jedoch auch direkt eine +Funktion verwenden. Eine Umgebung ist nicht mehr als eine Funktion, die Werte mit Variablen +assoziiert. Die obige Umgebung `{ x -> 5 }` wird in Scala folgendermaßen notiert: + + { case "x" => 5 } + +Diese Schreibweise definiert eine Funktion, welche bei dem String `"x"` als Argument die Ganzzahl +`5` zurückgibt, und in anderen Fällen mit einer Ausnahme fehlschlägt. + +Vor dem Schreiben der Funktionen zum Auswerten ist es sinnvoll, für die Umgebungen einen eigenen Typ +zu definieren. Man könnte zwar immer `String => Int` verwenden, es wäre jedoch besser einen +dedizierten Namen dafür zu verwenden, der das Programmieren damit einfacher macht und die Lesbarkeit +erhöht. Dies wird in Scala mit der folgenden Schreibweise erreicht: + + type Environment = String => Int + +Von hier an wird `Environment` als Alias für den Typ von Funktionen von `String` nach `Int` +verwendet. + +Nun ist alles für die Definition der Funktion zur Auswertung vorbereitet. Konzeptionell ist die +Definition sehr einfach: der Wert der Summe zweier Ausdrücke ist die Summe der Werte der einzelnen +Ausdrücke, der Wert einer Variablen wird direkt der Umgebung entnommen und der Wert einer Konstante +ist die Konstante selbst. Dies in Scala auszudrücken, ist nicht viel schwieriger: + + def eval(t: Tree, env: Environment): Int = t match { + case Sum(l, r) => eval(l, env) + eval(r, env) + case Var(n) => env(n) + case Const(v) => v + } + +Diese Funktion zum Auswerten von arithmetischen Ausdrücken nutzt einen *Musterabgleich* (pattern +matching) am Baumes `t`. Intuitiv sollte die Bedeutung der einzelnen Fälle klar sein: + +1. Als erstes wird überprüft, ob `t` eine Instanz der Klasse `Sum` ist. Falls dem so ist, wird der +linke Teilbaum der Variablen `l` und der rechte Teilbaum der Variablen `r` zugewiesen. Daraufhin +wird der Ausdruck auf der rechten Seite des Pfeiles ausgewertet, der die auf der linken Seite +gebundenen Variablen `l` und `r` verwendet. + +2. Sollte die erste Überprüfung fehlschlagen, also `t` ist keine `Sum`, wird der nächste Fall +abgehandelt und überprüft, ob `t` eine `Var` ist. Ist dies der Fall, wird analog zum ersten Fall der +Wert an `n` gebunden und der Ausdruck rechts vom Pfeil ausgewertet. + +3. Schlägt auch die zweite Überprüfung fehl, also `t` ist weder `Sum` noch `Val`, wird überprüft, +ob es eine Instanz des Typs `Const` ist. Analog wird bei einem Erfolg wie bei den beiden +vorangegangenen Fällen verfahren. + +4. Schließlich, sollten alle Überprüfungen fehlschlagen, wird eine Ausnahme ausgelöst, die +signalisiert, dass der Musterabgleich nicht erfolgreich war. Dies wird unweigerlich geschehen, +sollten neue Baum-Unterklassen erstellt werden. + +Die prinzipielle Idee eines Musterabgleiches ist, einen Wert anhand einer Reihe von Mustern +abzugleichen und, sobald ein Treffer erzielt wird, Werte zu extrahieren, mit denen darauf +weitergearbeitet werden kann. + +Erfahrene Objekt-orientierte Programmierer werden sich fragen, warum `eval` nicht als Methode der +Klasse `Tree` oder dessen Unterklassen definiert wurde. Dies wäre möglich, da Container-Klassen +Methoden definieren können, wie normale Klassen auch. Die Entscheidung, einen Musterabgleich oder +Methoden zu verwenden, ist Geschmackssache, hat jedoch wichtige Auswirkungen auf die +Erweiterbarkeit: + +- einerseits ist es mit Methoden einfach, neue Arten von Knoten als Unterklassen von `Tree` + hinzuzufügen, andererseits ist die Ergänzung einer neuen Operation zur Manipulation des Baumes + mühsam, da sie die Modifikation aller Unterklassen von `Tree` erfordert +- nutzt man einen Musterabgleich kehrt sich die Situation um: eine neue Art von Knoten erfordert + die Modifikation aller Funktionen die einen Musterabgleich am Baum vollführen, wogegen eine neue + Operation leicht hinzuzufügen ist, indem einfach eine unabhängige Funktion dafür definiert wird + +Einen weiteren Einblick in Musterabgleiche verschafft eine weitere Operation mit arithmetischen +Ausdrücken: partielle Ableitungen. Dafür gelten zur Zeit folgende Regeln: + +1. die Ableitung einer Summe ist die Summe der Ableitungen +2. die Ableitung einer Variablen ist eins, wenn sie die abzuleitende Variable ist, ansonsten `0` +3. die Ableitung einer Konstanten ist `0` + +Auch diese Regeln können fast wörtlich in Scala übersetzt werden: + + def derive(t: Tree, v: String): Tree = t match { + case Sum(l, r) => Sum(derive(l, v), derive(r, v)) + case Var(n) if (v == n) => Const(1) + case _ => Const(0) + } + +Diese Funktion führt zwei neue, mit dem Musterabgleich zusammenhängende Konzepte ein. Der zweite, +sich auf eine Variable beziehende Fall hat eine *Sperre* (guard), einen Ausdruck, der dem +Schlüsselwort `if` folgt. Diese Sperre verhindert eine Übereinstimmung, wenn der Ausdruck falsch +ist. In diesem Fall wird sie genutzt, die Konstante `1` nur zurückzugeben, wenn die Variable die +abzuleitende ist. Die zweite Neuerung ist der *Platzhalter* `_`, der mit allem übereinstimmt, jedoch +ohne einen Namen dafür zu verwenden. + +Die volle Funktionalität von Musterabgleichen wurde mit diesen Beispielen nicht demonstriert, doch +soll dies fürs Erste genügen. Eine Vorführung der beiden Funktionen an realen Beispielen steht immer +noch aus. Zu diesem Zweck soll eine `main`-Methode dienen, die den Ausdruck `(x+x)+(7+y)` als +Beispiel verwendet: zuerst wird der Wert in der Umgebung `{ x -> 5, y -> 7 }` berechnet und darauf +die beiden partiellen Ableitungen gebildet: + + def main(args: Array[String]) { + val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y"))) + val env: Environment = { + case "x" => 5 + case "y" => 7 + } + println("Ausdruck: " + exp) + println("Auswertung mit x=5, y=7: " + eval(exp, env)) + println("Ableitung von x:\n " + derive(exp, "x")) + println("Ableitung von y:\n " + derive(exp, "y")) + } + +Führt man das Programm aus, erhält man folgende Ausgabe: + + Ausdruck: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y))) + Auswertung mit x=5, y=7: 24 + Ableitung von x: + Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0))) + Ableitung von y: + Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1))) + +Beim Anblick dieser Ausgabe ist offensichtlich, dass man die Ergebnisse der Ableitungen noch +vereinfachen sollte. Eine solche Funktion zum Vereinfachen von Ausdrücken, die Musterabgleiche +nutzt, ist ein interessantes, aber gar nicht so einfaches Problem, was als Übung offen steht. + +## Traits + +Neben dem Vererben von Oberklassen ist es in Scala auch möglich von mehreren, sogenannten *Traits* +zu erben. Der beste Weg für einen Java-Programmierer einen Trait zu verstehen, ist sich eine +Schnittstelle vorzustellen, die Implementierungen enthält. Wenn in Scala eine Klasse von einem Trait +erbt, implementiert sie dessen Schnittstelle und erbt dessen Implementierungen. + +Um die Nützlichkeit von Traits zu demonstrieren, werden wir ein klassisches Beispiel implementieren: +Objekte mit einer natürlichen Ordnung oder Rangfolge. Es ist häufig hilfreich, Instanzen einer +Klasse untereinander vergleichen zu können, um sie beispielsweise sortieren zu können. In Java +müssen die Klassen solcher Objekte die Schnittstelle `Comparable` implementieren. In Scala kann dies +mit einer äquivalenten, aber besseren Variante von `Comparable` als Trait bewerkstelligt werden, die +im Folgenden `Ord` genannt wird. + +Wenn Objekte verglichen werden, sind sechs verschiedene Aussagen sinnvoll: kleiner, kleiner gleich, +gleich, ungleich, größer, und größer gleich. Allerdings ist es umständlich, immer alle sechs +Methoden dafür zu implementieren, vor allem in Anbetracht der Tatsache, dass vier dieser sechs durch +die verbliebenen zwei ausgedrückt werden können. Sind beispielsweise die Aussagen für gleich und +kleiner gegeben, kann man die anderen damit ausdrücken. In Scala können diese Beobachtungen mit +dem folgenden Trait zusammengefasst werden: + + trait Ord { + def < (that: Any): Boolean + def <=(that: Any): Boolean = (this < that) || (this == that) + def > (that: Any): Boolean = !(this <= that) + def >=(that: Any): Boolean = !(this < that) + } + +Diese Definition erzeugt sowohl einen neuen Typ namens `Ord`, welcher dieselbe Rolle wie Javas +Schnittstelle `Comparable` spielt, und drei vorgegebenen Funktionen, die auf einer vierten, +abstrakten basieren. Die Methoden für Gleichheit und Ungleichheit erscheinen hier nicht, da sie +bereits in allen Objekten von Scala vorhanden sind. + +Der Typ `Any`, welcher oben verwendet wurde, stellt den Ober-Typ aller Typen in Scala dar. Er kann +als noch allgemeinere Version von Javas `Object` angesehen werden, da er außerdem Ober-Typ der +Basis-Typen wie `Int` und `Float` ist. + +Um Objekte einer Klasse vergleichen zu können, ist es also hinreichend, Gleichheit und die +kleiner-als-Beziehung zu implementieren, und dieses Verhalten gewissermaßen mit der eigentlichen +Klasse zu vermengen (mix in). Als Beispiel soll eine Klasse für Datumsangaben dienen, die Daten +eines gregorianischen Kalenders repräsentiert. Solche Daten bestehen aus Tag, Monat und Jahr, welche +durch Ganzzahlen dargestellt werden: + + class Date(y: Int, m: Int, d: Int) extends Ord { + def year = y + def month = m + def day = d + + override def toString = year + "-" + month + "-" + day + +Der wichtige Teil dieser Definition ist die Deklaration `extends Ord`, welche dem Namen der Klasse +und deren Parametern folgt. Sie sagt aus, dass `Date` vom Trait `Ord` erbt. + +Nun folgt eine Re-Implementierung der Methode `equals`, die von `Object` geerbt wird, so dass die +Daten korrekt nach ihren Feldern verglichen werden. Die vorgegebene Implementierung von `equals` ist +dafür nicht nützlich, da in Java Objekte physisch, also nach deren Adressen im Speicher, verglichen +werden. Daher verwenden wir folgende Definition: + + override def equals(that: Any): Boolean = + that.isInstanceOf[Date] && { + val o = that.asInstanceOf[Date] + o.day == day && o.month == month && o.year == year + } + +Diese Methode verwendet die vordefinierten Methoden `isInstanceOf` und `asInstanceOf`. Erstere +entspricht Javas `instanceof`-Operator und gibt `true` zurück, wenn das zu testende Objekt eine +Instanz des angegebenen Typs ist. Letztere entspricht Javas Operator für Typ-Umwandlungen (cast): +ist das Objekt eine Instanz des angegebenen Typs, kann es als solcher angesehen und gehandhabt +werden, ansonsten wird eine `ClassCastException` ausgelöst. + +Schließlich kann die letzte Methode definiert werden, die für `Ord` notwendig ist, und die +kleiner-als-Beziehung implementiert. Diese nutzt eine andere, vordefinierte Methode, namens `error`, +des Paketes `sys`, welche eine `RuntimeException` mit der angegebenen Nachricht auslöst. + + def <(that: Any): Boolean = { + if (!that.isInstanceOf[Date]) + sys.error("cannot compare " + that + " and a Date") + + val o = that.asInstanceOf[Date] + (year < o.year) || + (year == o.year && (month < o.month || + (month == o.month && day < o.day))) + } + } + +Diese Methode vervollständigt die Definition der `Date`-Klasse. Instanzen dieser Klasse stellen +sowohl Daten als auch vergleichbare Objekte dar. Vielmehr implementiert diese Klasse alle sechs +Methoden, die für das Vergleichen von Objekten notwendig sind: `equals` und `<`, die direkt in der +Definition von `Date` vorkommen, sowie die anderen, in dem Trait `Ord` definierten Methoden. + +Traits sind nützlich in Situationen wie der obigen, den vollen Funktionsumfang hier zu zeigen, würde +allerdings den Rahmen dieses Dokumentes sprengen. + +## Generische Programmierung + +Eine weitere Charakteristik Scalas, die in diesem Tutorial vorgestellt werden soll, behandelt das +Konzept der generischen Programmierung. Java-Programmierer, die die Sprache noch vor der Version 1.5 +kennen, sollten mit den Problemen vertraut sein, die auftreten, wenn generische Programmierung nicht +unterstützt wird. + +Generische Programmierung bedeutet, Quellcode nach Typen zu parametrisieren. Beispielsweise stellt +sich die Frage für einen Programmierer bei der Implementierung einer Bibliothek für verkettete +Listen, welcher Typ für die Elemente verwendet werden soll. Da diese Liste in verschiedenen +Zusammenhängen verwendet werden soll, ist es nicht möglich, einen spezifischen Typ, wie `Int`, zu +verwenden. Diese willkürliche Wahl wäre sehr einschränkend. + +Aufgrund dieser Probleme griff man in Java vor der Einführung der generischen Programmierung zu dem +Mittel, `Object`, den Ober-Typ aller Typen, als Element-Typ zu verwenden. Diese Lösung ist +allerdings auch weit entfernt von Eleganz, da sie sowohl ungeeignet für die Basis-Typen, wie `int` +oder `float`, ist, als auch viele explizite Typ-Umwandlungen für den nutzenden Programmierer +bedeutet. + +Scala ermöglicht es, generische Klassen und Methoden zu definieren, um diesen Problemen aus dem Weg +zu gehen. Für die Demonstration soll ein einfacher, generischer Container als Referenz-Typ dienen, +der leer sein kann, oder auf ein Objekt des generischen Typs zeigt: + + class Reference[T] { + private var contents: T = _ + + def get: T = contents + + def set(value: T) { + contents = value + } + } + +Die Klasse `Reference` ist anhand des Types `T` parametrisiert, der den Element-Typ repräsentiert. +Dieser Typ wird im Körper der Klasse genutzt, wie bei dem Feld `contents`. Dessen Argument wird +durch die Methode `get` abgefragt und mit der Methode `set` verändert. + +Der obige Quellcode führt veränderbare Variablen in Scala ein, welche keiner weiteren Erklärung +erfordern sollten. Schon interessanter ist der initiale Wert dieser Variablen, der mit `_` +gekennzeichnet wurde. Dieser Standardwert ist für numerische Typen `0`, `false` für Wahrheitswerte, +`()` für den Typ `Unit` und `null` für alle anderen Typen. + +Um diese Referenz-Klasse zu verwenden, muss der generische Typ bei der Erzeugung einer Instanz +angegeben werden. Für einen Ganzzahl-Container soll folgendes Beispiel dienen: + + object IntegerReference { + def main(args: Array[String]) { + val cell = new Reference[Int] + cell.set(13) + println("Reference contains the half of " + (cell.get * 2)) + } + } + +Wie in dem Beispiel zu sehen ist, muss der Wert, der von der Methode `get` zurückgegeben wird, nicht +umgewandelt werden, wenn er als Ganzzahl verwendet werden soll. Es wäre außerdem nicht möglich, +einen Wert, der keine Ganzzahl ist, in einem solchen Container zu speichern, da er speziell und +ausschließlich für Ganzzahlen erzeugt worden ist. + +## Zusammenfassung + +Dieses Dokument hat einen kurzen Überblick über die Sprache Scala gegeben und dazu einige einfache +Beispiele verwendet. Interessierte Leser können beispielsweise mit dem Dokument *Scala by Example* +fortfahren, welches fortgeschrittenere Beispiele enthält, und die *Scala Language Specification* +konsultieren, sofern nötig. + diff --git a/documentation/faq/index.md b/documentation/faq/index.md new file mode 100644 index 000000000..e69de29bb diff --git a/documentation/glossary/index.md b/documentation/glossary/index.md new file mode 100644 index 000000000..92c0fcf20 --- /dev/null +++ b/documentation/glossary/index.md @@ -0,0 +1,382 @@ +--- +layout: glossary +title: Glossary +--- + +* #### algebraic data type +A type defined by providing several alternatives, each of which comes with its own constructor. It usually comes with a way to decompose the type through pattern matching. The concept is found in specification languages and functional programming languages. Algebraic data types can be emulated in Scala with case classes. + +* #### alternative +A branch of a match expression. It has the form “`case` _pattern_ => _expression_.” Another name for alternative is _case_. + +* #### annotation +An annotation appears in source code and is attached to some part of the syntax. Annotations are computer processable, so you can use them to effectively add an extension to Scala. + +* #### anonymous class +An anonymous class is a synthetic subclass generated by the Scala compiler from a new expression in which the class or trait name is followed by curly braces. The curly braces contains the body of the anonymous subclass, which may be empty. However, if the name following new refers to a trait or class that contains abstract members, these must be made concrete inside the curly braces that define the body of the anonymous subclass. + +* #### anonymous function +Another name for [function literal](#function-literal). + +* #### apply +You can apply a method, function, or closure to arguments, which means you invoke it on those arguments. + +* #### argument +When a function is invoked, an argument is passed for each parameter of that function. The parameter is the variable that refers to the argument. The argument is the object passed at invocation time. In addition, applications can take (command line) arguments that show up in the `Array[String]` passed to main methods of singleton objects. + +* #### assign +You can assign an object to a variable. Afterwards, the variable will refer to the object. + +* #### auxiliary constructor +Extra constructors defined inside the curly braces of the class definition, which look like method definitions named this, but with no result type. + +* #### block +One or more expressions and declarations surrounded by curly braces. When the block evaluates, all of its expressions and declarations are processed in order, and then the block returns the value of the last expression as its own value. Blocks are commonly used as the bodies of functions, [for expressions](#for-expression), `while` loops, and any other place where you want to group a number of statements together. More formally, a block is an encapsulation construct for which you can only see side effects and a result value. The curly braces in which you define a class or object do not, therefore, form a block, because fields and methods (which are defined inside those curly braces) are visible from the out- side. Such curly braces form a template. + +* #### bound variable +A bound variable of an expression is a variable that’s both used and defined inside the expression. For instance, in the function literal expression `(x: Int) => (x, y)`, both variables `x` and `y` are used, but only `x` is bound, because it is defined in the expression as an `Int` and the sole argument to the function described by the expression. + +* #### by-name parameter +A parameter that is marked with a `=>` in front of the parameter type, e.g., `(x: => Int)`. The argument corresponding to a by-name parameter is evaluated not before the method is invoked, but each time the parameter is referenced by name inside the method. If a parameter is not by-name, it is by-value. + +* #### by-value parameter +A parameter that is not marked with a `=>` in front of the parameter type, e.g., `(x: Int)`. The argument corresponding to a by-value parameter is evaluated before the method is invoked. By-value parameters contrast with by-name parameters. + +* #### class +Defined with the `class` keyword, a _class_ may either be abstract or concrete, and may be parameterized with types and values when instantiated. In `new Array[String](2)`, the class being instantiated is `Array` and the type of the value that results is `Array[String]`. A class that takes type parameters is called a _type constructor_. A type can be said to have a class as well, as in: the class of type `Array[String]` is `Array`. + +* #### closure +A function object that captures free variables, and is said to be “closed” over the variables visible at the time it is created. + +* #### companion class +A class that shares the same name with a singleton object defined in the same source file. The class is the singleton object’s companion class. + +* #### companion object +A singleton object that shares the same name with a class defined in the same source file. Companion objects and classes have access to each other’s private members. In addition, any implicit conversions defined in the companion object will be in scope anywhere the class is used. + +* #### contravariant +A _contravariant_ annotation can be applied to a type parameter of a class or trait by putting a minus sign (-) before the type parameter. The class or trait then subtypes contravariantly with—in the opposite direction as—the type annotated parameter. For example, `Function1` is contravariant in its first type parameter, and so `Function1[Any, Any]` is a subtype of `Function1[String, Any]`. + +* #### covariant +A _covariant_ annotation can be applied to a type parameter of a class or trait by putting a plus sign (+) before the type parameter. The class or trait then subtypes covariantly with—in the same direction as—the type annotated parameter. For example, `List` is covariant in its type parameter, so `List[String]` is a subtype of `List[Any]`. + +* #### currying +A way to write functions with multiple parameter lists. For instance `def f(x: Int)(y: Int)` is a curried function with two parameter lists. A curried function is applied by passing several arguments lists, as in: `f(3)(4)`. However, it is also possible to write a _partial application_ of a curried function, such as `f(3)`. + +* #### declare +You can _declare_ an abstract field, method, or type, which gives an entity a name but not an implementation. The key difference between declarations and definitions is that definitions establish an implementation for the named entity, declarations do not. + +* #### define +To _define_ something in a Scala program is to give it a name and an implementation. You can define classes, traits, singleton objects, fields, methods, local functions, local variables, _etc_. Because definitions always involve some kind of implementation, abstract members are declared not defined. + +* #### direct subclass +A class is a _direct subclass_ of its direct superclass. + +* #### direct superclass +The class from which a class or trait is immediately derived, the nearest class above it in its inheritance hierarchy. If a class `Parent` is mentioned in a class `Child`’s optional extends clause, then `Parent` is the direct superclass of `Child`. If a trait is mentioned in `Child`’s extends clause, the trait’s direct superclass is the `Child`’s direct superclass. If `Child` has no extends clause, then `AnyRef` is the direct superclass of `Child`. If a class’s direct superclass takes type parameters, for example class `Child` extends `Parent[String]`, the direct superclass of `Child` is still `Parent`, not `Parent[String]`. On the other hand, `Parent[String]` would be the direct supertype of `Child`. See [supertype](#supertype) for more discussion of the distinction between class and type. + +* #### equality +When used without qualification, _equality_ is the relation between values expressed by `==`. See also [reference equality](#reference-equality). + +* #### existential type +An existential type includes references to type variables that are unknown. For example, `Array[T] forSome { type T }` is an existential type. It is an array of `T`, where `T` is some completely unknown type. All that is assumed about `T` is that it exists at all. This assumption is weak, but it means at least that an `Array[T] forSome { type T }` is indeed an array and not a banana. + +* #### expression +Any bit of Scala code that yields a result. You can also say that an expression _evaluates_ to a result or _results_ in a value. + +* #### filter +An `if` followed by a boolean expression in a [for expression](#for-expression). In `for(i <- 1 to 10; if i % 2 == 0)`, the filter is “`if i % 2 == 0`”. The value to the right of the `if` is the [filter expression](#filter-expression). Also known as a guard. + +* #### filter expression +A _filter expression_ is the boolean expression following an `if` in a [for expression](#for-expression). In `for( i <- 1 to 10 ; if i % 2 == 0)`,the filter expression is “`i % 2 == 0`”. + +* #### first-class function +Scala supports _first-class functions_, which means you can express functions in function literal syntax, i.e., `(x: Int) => x + 1`, and that functions can be represented by objects, which are called [function values](#function-value). + +* #### for comprehension +A _for comprehension_ is a type of [for expression](#for-expression) that creates a new collection. For each iteration of the `for` comprehension, the [yield](#yield) clause defines an element of the new collection. For example, `for (i <- (0 until 2); j <- (2 until 4)) yield (i, j)` returns the collection `Vector((0,2), (0,3), (1,2), (1,3))`. + +* #### for expression +A _for expression_ is either a [for loop](#for-loop), which iterates over one or more collections, or a [for comprehension](#for-comprehension), which builds a new collection from the elements of one or more collections. A `for` expression is built up of [generators](#generator), [filters](#filter), variable definitions, and (in the case of [for comprehensions](#for-comprehension)) a [yield](#yield) clause. + +* #### for loop +A _for loop_ is a type of [for expression](#for-expression) that loops over one or more collections. Since `for` loops return unit, they usually produce side-effects. For example, `for (i <- 0 until 100) println(i)` prints the numbers 0 through 99. + +* #### free variable +A _free variable_ of an expression is a variable that’s used inside the expression but not defined inside the expression. For instance, in the function literal expression `(x: Int) => (x, y)`, both variables `x` and `y` are used, but only `y` is a free variable, because it is not defined inside the expression. + +* #### function +A _function_ can be [invoked](#invoke) with a list of arguments to produce a result. A function has a parameter list, a body, and a result type. Functions that are members of a class, trait, or singleton object are called [methods](#method). Functions defined inside other functions are called [local functions](#local-function). Functions with the result type of `Unit` are called [procedures](#procedure). Anonymous functions in source code are called [function literals](#function-literal). At run time, function literals are instantiated into objects called [function values](#function-value). + +* #### function literal +A function with no name in Scala source code, specified with function literal syntax. For example, `(x: Int, y: Int) => x + y`. + +* #### function value +A function object that can be invoked just like any other function. A function value’s class extends one of the `FunctionN` traits (e.g., `Function0`, `Function1`) from package `scala`, and is usually expressed in source code via [function literal](#function-literal) syntax. A function value is “invoked” when its apply method is called. A function value that captures free variables is a [closure](#closure). + +* #### functional style +The _functional style_ of programming emphasizes functions and evaluation results and deemphasizes the order in which operations occur. The style is characterized by passing function values into looping methods, immutable data, methods with no side effects. It is the dominant paradigm of languages such as Haskell and Erlang, and contrasts with the [imperative style](#imperative-style). + +* #### generator +A generator defines a named val and assigns to it a series of values in a [for expression](#for-expression). For example, in `for(i <- 1 to 10)`, the generator is “`i <- 1 to 10`”. The value to the right of the `<-` is the [generator expression](#generator-expression). + +* #### generator expression +A generator expression generates a series of values in a [for expression](#for-expression). For example, in `for(i <- 1 to 10)`, the generator expression is “`1 to 10`”. + +* #### generic class +A class that takes type parameters. For example, because `scala.List` takes a type parameter, `scala.List` is a generic class. + +* #### generic trait +A trait that takes type parameters. For example, because trait `scala.collection.Set` takes a type parameter, it is a generic trait. + +* #### guard +See [filter](#filter). + +* #### helper function +A function whose purpose is to provide a service to one or more other functions nearby. Helper functions are often implemented as local functions. + +* #### helper method +A [helper function](#helper-function) that’s a member of a class. Helper methods are often private. + +* #### immutable +An object is _immutable_ if its value cannot be changed after it is created in any way visible to clients. Objects may or may not be immutable. + +* #### imperative style +The _imperative style_ of programming emphasizes careful sequencing of operations so that their effects happen in the right order. The style is characterized by iteration with loops, mutating data in place, and methods with side effects. It is the dominant paradigm of languages such as C, C++, C# and Java, and contrasts with the [functional style](#functional-style). + +* #### initialize +When a variable is defined in Scala source code, you must initialize it with an object. + +* #### instance +An _instance_, or class instance, is an object, a concept that exists only at run time. + +* #### instantiate +To _instantiate_ a class is to make a new object from the class, an action that happens only at run time. + +* #### invariant +_Invariant_ is used in two ways. It can mean a property that always holds true when a data structure is well-formed. For example, it is an invariant of a sorted binary tree that each node is ordered before its right subnode, if it has a right subnode. Invariant is also sometimes used as a synonym for nonvariant: “class `Array` is invariant in its type parameter.” + +* #### invoke +You can _invoke_ a method, function, or closure _on_ arguments, meaning its body will be executed with the specified arguments. + +* #### JVM +The _JVM_ is the Java Virtual Machine, or [runtime](#runtime), that hosts a running Scala program. + +* #### literal +`1`, `"One"`, and `(x: Int) => x + 1` are examples of _literals_. A literal is a shorthand way to describe an object, where the shorthand exactly mirrors the structure of the created object. + +* #### local function +A _local function_ is a `def` defined inside a block. To contrast, a `def` defined as a member of a class, trait, or singleton object is called a [method](#method). + +* #### local variable +A _local variable_ is a `val` or `var` defined inside a block. Although similar to [local variables](#local-variable), parameters to functions are not referred to as local variables, but simply as parameters or “variables” without the “local.” + +* #### member +A _member_ is any named element of the template of a class, trait, or singleton object. A member may be accessed with the name of its owner, a dot, and its simple name. For example, top-level fields and methods defined in a class are members of that class. A trait defined inside a class is a member of its enclosing class. A type defined with the type keyword in a class is a member of that class. A class is a member of the package in which is it defined. By contrast, a local variable or local function is not a member of its surrounding block. + +* #### message +Actors communicate with each other by sending each other _messages_. Sending a message does not interrupt what the receiver is doing. The receiver can wait until it has finished its current activity and its invariants have been reestablished. + +* #### meta-programming +Meta-programming software is software whose input is itself software. Compilers are meta-programs, as are tools like `scaladoc`. Meta-programming software is required in order to do anything with an annotation. + +* #### method +A _method_ is a function that is a member of some class, trait, or singleton object. + +* #### mixin +_Mixin_ is what a trait is called when it is being used in a mixin composition. In other words, in “`trait Hat`,” `Hat` is just a trait, but in “`new Cat extends AnyRef with Hat`,” `Hat` can be called a mixin. When used as a verb, “mix in” is two words. For example, you can _mix_ traits _in_to classes or other traits. + +* #### mixin composition +The process of mixing traits into classes or other traits. _Mixin composition_ differs from traditional multiple inheritance in that the type of the super reference is not known at the point the trait is defined, but rather is determined anew each time the trait is mixed into a class or other trait. + +* #### modifier +A keyword that qualifies a class, trait, field, or method definition in some way. For example, the `private` modifier indicates that a class, trait, field, or method being defined is private. + +* #### multiple definitions +The same expression can be assigned in _multiple definitions_ if you use the syntax `val v1, v2, v3 = exp`. + +* #### nonvariant +A type parameter of a class or trait is by default _nonvariant_. The class or trait then does not subtype when that parameter changes. For example, because class `Array` is nonvariant in its type parameter, `Array[String]` is neither a subtype nor a supertype of `Array[Any]`. + +* #### operation +In Scala, every _operation_ is a method call. Methods may be invoked in _operator notation_, such as `b + 2`, and when in that notation, `+` is an _operator_. + +* #### parameter +Functions may take zero to many _parameters_. Each parameter has a name and a type. The distinction between parameters and arguments is that arguments refer to the actual objects passed when a function is invoked. Parameters are the variables that refer to those passed arguments. + +* #### parameterless function +A function that takes no parameters, which is de- fined without any empty parentheses. Invocations of parameterless functions may not supply parentheses. This supports the [uniform access principle](#uniform-access-principle), which enables the `def` to be changed into a `val` without requiring a change to client code. + +* #### parameterless method +A _parameterless method_ is a parameterless function that is a member of a class, trait, or singleton object. + +* #### parametric field +A field defined as a class parameter. + +* #### partially applied function +A function that’s used in an expression and that misses some of its arguments. For instance, if function `f` has type `Int => Int => Int`, then `f` and `f(1)` are _partially applied functions_. + +* #### path-dependent type +A type like `swiss.cow.Food`. The `swiss.cow` part is a path that forms a reference to an object. The meaning of the type is sensitive to the path you use to access it. The types `swiss.cow.Food` and `fish.Food`, for example, are different types. + +* #### pattern +In a `match` expression alternative, a _pattern_ follows each `case` keyword and precedes either a _pattern guard_ or the `=>` symbol. + +* #### pattern guard +In a `match` expression alternative, a _pattern guard_ can follow a [pattern](#pattern). For example, in “`case x if x % 2 == 0 => x + 1`”, the pattern guard is “`if x % 2 == 0`”. A case with a pattern guard will only be selected if the pattern matches and the pattern guard yields true. + +* #### predicate +A _predicate_ is a function with a `Boolean` result type. + +* #### primary constructor +The main constructor of a class, which invokes a superclass constructor, if necessary, initializes fields to passed values, and executes any top-level code defined between the curly braces of the class. Fields are initialized only for value parameters not passed to the superclass constructor, except for any that are not used in the body of the class and can therefore be optimized away. + +* #### procedure +A _procedure_ is a function with result type of `Unit`, which is therefore executed solely for its side effects. + +* #### reassignable +A variable may or may not be _reassignable_. A `var` is reassignable while a `val` is not. + +* #### recursive +A function is _recursive_ if it calls itself. If the only place the function calls itself is the last expression of the function, then the function is [tail recursive](#tail-recursive). + +* #### reference +A _reference_ is the Java abstraction of a pointer, which uniquely identifies an object that resides on the JVM’s heap. Reference type variables hold references to objects, because reference types (instances of `AnyRef`) are implemented as Java objects that reside on the JVM’s heap. Value type variables, by contrast, may sometimes hold a reference (to a boxed wrapper type) and sometimes not (when the object is being represented as a primitive value). Speaking generally, a Scala variable [refers](#refers) to an object. The term “refers” is more abstract than “holds a reference.” If a variable of type `scala.Int` is currently represented as a primitive Java `int` value, then that variable still refers to the `Int` object, but no reference is involved. + +* #### reference equality +_Reference equality_ means that two references identify the very same Java object. Reference equality can be determined, for reference types only, by calling `eq` in `AnyRef`. (In Java programs, reference equality can be determined using `==` on Java [reference types](#reference-type).) + +* #### reference type +A _reference type_ is a subclass of `AnyRef`. Instances of reference types always reside on the JVM’s heap at run time. + +* #### referential transparency +A property of functions that are independent of temporal context and have no side effects. For a particular input, an invocation of a referentially transparent function can be replaced by its result without changing the program semantics. + +* #### refers +A variable in a running Scala program always _refers_ to some object. Even if that variable is assigned to `null`, it conceptually refers to the `Null` object. At runtime, an object may be implemented by a Java object or a value of a primitive type, but Scala allows programmers to think at a higher level of abstraction about their code as they imagine it running. See also [reference](#reference). + +* #### refinement type +A type formed by supplying a base type a number of members inside curly braces. The members in the curly braces refine the types that are present in the base type. For example, the type of “animal that eats grass” is `Animal { type SuitableFood = Grass }`. + +* #### result +An expression in a Scala program yields a _result_. The result of every expression in Scala is an object. + +* #### result type +A method’s _result type_ is the type of the value that results from calling the method. (In Java, this concept is called the return type.) + +* #### return +A function in a Scala program `returns` a value. You can call this value the [result](#result) of the function. You can also say the function _results in_ the value. The result of every function in Scala is an object. + +* #### runtime +The Java Virtual Machine, or [JVM](#jvm), that hosts a running Scala program. Runtime encompasses both the virtual machine, as defined by the Java Virtual Machine Specification, and the runtime libraries of the Java API and the standard Scala API. The phrase at run time (with a space between run and time) means when the program is running, and contrasts with compile time. + +* #### runtime type +The type of an object at run time. To contrast, a [static type](#static-type) is the type of an expression at compile time. Most runtime types are simply bare classes with no type parameters. For example, the runtime type of `"Hi"` is `String`, and the runtime type of `(x: Int) => x + 1` is `Function1`. Runtime types can be tested with `isInstanceOf`. + +* #### script +A file containing top level definitions and statements, which can be run directly with `scala` without explicitly compiling. A script must end in an expression, not a definition. + +* #### selector +The value being matched on in a `match` expression. For example, in “`s match { case _ => }`”, the selector is `s`. + +* #### self type +A _self type_ of a trait is the assumed type of `this`, the receiver, to be used within the trait. Any concrete class that mixes in the trait must ensure that its type conforms to the trait’s self type. The most common use of self types is for dividing a large class into several traits (as described in Chapter 29 of [Programming in Scala](http://www.artima.com/shop/programming_in_scala). + +* #### semi-structured data +XML data is semi-structured. It is more structured than a flat binary file or text file, but it does not have the full structure of a programming language’s data structures. + +* #### serialization +You can _serialize_ an object into a byte stream which can then be saved to files or transmitted over the network. You can later _deserialize_ the byte stream, even on different computer, and obtain an object that is the same as the original serialized object. + +* #### shadow +A new declaration of a local variable _shadows_ one of the same name in an enclosing scope. + +* #### signature +_Signature_ is short for [type signature](#type-signature). + +* #### singleton object +An object defined with the object keyword. Each singleton object has one and only one instance. A singleton object that shares its name with a class, and is defined in the same source file as that class, is that class’s [companion object](#companion-object). The class is its [companion class](#companion-class). A singleton object that doesn’t have a companion class is a [standalone object](#standalone-object). + +* #### standalone object +A [singleton object](#singleton-object) that has no [companion class](#companion-class). + +* #### statement +An expression, definition, or import, _i.e._, things that can go into a template or a block in Scala source code. + +* #### static type +See [type](#type). + +* #### structural type +A [refinement type](#refinement-type) where the refinements are for members not in the base type. For example, `{ def close(): Unit }` is a structural type, because the base type is `AnyRef`, and `AnyRef` does not have a member named `close`. + +* #### subclass +A class is a _subclass_ of all of its [superclasses](#superclass) and [supertraits](#supertrait). + +* #### subtrait +A trait is a _subtrait_ of all of its [supertraits](#supertrait). + +* #### subtype +The Scala compiler will allow any of a type’s _subtypes_ to be used as a substitute wherever that type is required. For classes and traits that take no type parameters, the subtype relationship mirrors the subclass relationship. For example, if class `Cat` is a subclass of abstract class `Animal`, and neither takes type parameters, type `Cat` is a subtype of type `Animal`. Likewise, if trait `Apple` is a subtrait of trait `Fruit`, and neither takes type parameters, type `Apple` is a subtype of type `Fruit`. For classes and traits that take type parameters, however, variance comes into play. For example, because abstract class `List` is declared to be covariant in its lone type parameter (i.e., `List` is declared `List[+A]`), `List[Cat]` is a subtype of `List[Animal]`, and `List[Apple]` a subtype of `List[Fruit]`. These subtype relationships exist even though the class of each of these types is `List`. By contrast, because `Set` is not declared to be covariant in its type parameter (i.e., `Set` is declared `Set[A]` with no plus sign), `Set[Cat]` is not a subtype of `Set[Animal]`. A subtype should correctly implement the contracts of its supertypes, so that the Liskov Substitution Principle applies, but the compiler only verifies this property at the level of type checking. + +* #### superclass +A class’s _superclasses_ include its direct superclass, its direct superclass’s direct superclass, and so on, all the way up to `Any`. + +* #### supertrait +A class’s or trait’s _supertraits_, if any, include all traits directly mixed into the class or trait or any of its superclasses, plus any supertraits of those traits. + +* #### supertype +A type is a _supertype_ of all of its subtypes. + +* #### synthetic class +A synthetic class is generated automatically by the compiler rather than being written by hand by the programmer. + +* #### tail recursive +A function is _tail recursive_ if the only place the function calls itself is the last operation of the function. + +* #### target typing +_Target typing_ is a form of type inference that takes into account the type that’s expected. In `nums.filter((x) => x > 0)`, for example, the Scala compiler infers type of `x` to be the element type of `nums`, because the `filter` method invokes the function on each element of `nums`. + +* #### template +A _template_ is the body of a class, trait, or singleton object definition. It defines the type signature, behavior and initial state of the class, trait, or object. + +* #### trait +A _trait_, which is defined with the `trait` keyword, is like an abstract class that cannot take any value parameters and can be “mixed into” classes or other traits via the process known as [mixin composition](#mixin-composition). When a trait is being mixed into a class or trait, it is called a [mixin](#mixin). A trait may be parameterized with one or more types. When parameterized with types, the trait constructs a type. For example, `Set` is a trait that takes a single type parameter, whereas `Set[Int]` is a type. Also, `Set` is said to be “the trait of” type `Set[Int]`. + +* #### type +Every variable and expression in a Scala program has a _type_ that is known at compile time. A type restricts the possible values to which a variable can refer, or an expression can produce, at run time. A variable or expression’s type can also be referred to as a _static type_ if necessary to differentiate it from an object’s [runtime type](#runtime-type). In other words, “type” by itself means static type. Type is distinct from class because a class that takes type parameters can construct many types. For example, `List` is a class, but not a type. `List[T]` is a type with a free type parameter. `List[Int]` and `List[String]` are also types (called ground types because they have no free type parameters). A type can have a “[class](#class)” or “[trait](#trait).” For example, the class of type `List[Int]` is `List`. The trait of type `Set[String]` is `Set`. + +* #### type constraint +Some [annotations](#annotation) are _type constraints_, meaning that they add additional limits, or constraints, on what values the type includes. For example, `@positive` could be a type constraint on the type `Int`, limiting the type of 32-bit integers down to those that are positive. Type constraints are not checked by the standard Scala compiler, but must instead be checked by an extra tool or by a compiler plugin. + +* #### type constructor +A class or trait that takes type parameters. + +* #### type parameter +A parameter to a generic class or generic method that must be filled in by a type. For example, class `List` is defined as “`class List[T] { . . . `”, and method `identity`, a member of object `Predef`, is defined as “`def identity[T](x:T) = x`”. The `T` in both cases is a type parameter. + +* #### type signature +A method’s _type signature_ comprises its name, the number, order, and types of its parameters, if any, and its result type. The type signature of a class, trait, or singleton object comprises its name, the type signatures of all of its members and constructors, and its declared inheritance and mixin relations. + +* #### uniform access principle +The _uniform access principle_ states that variables and parameterless functions should be accessed using the same syntax. Scala supports this principle by not allowing parentheses to be placed at call sites of parameterless functions. As a result, a parameterless function definition can be changed to a `val`, or _vice versa_, without affecting client code. + +* #### unreachable +At the Scala level, objects can become _unreachable_, at which point the memory they occupy may be reclaimed by the runtime. Unreachable does not necessarily mean unreferenced. Reference types (instances of `AnyRef`) are implemented as objects that reside on the JVM’s heap. When an instance of a reference type becomes unreachable, it indeed becomes unreferenced, and is available for garbage collection. Value types (instances of `AnyVal`) are implemented as both primitive type values and as instances of Java wrapper types (such as `java.lang.Integer`), which reside on the heap. Value type instances can be boxed (converted from a primitive value to a wrapper object) and unboxed (converted from a wrapper object to a primitive value) throughout the lifetime of the variables that refer to them. If a value type instance currently represented as a wrapper object on the JVM’s heap becomes unreachable, it indeed becomes unreferenced, and is available for garbage collection. But if a value type currently represented as a primitive value becomes unreachable, then it does not become unreferenced, because it does not exist as an object on the JVM’s heap at that point in time. The runtime may reclaim memory occupied by unreachable objects, but if an Int, for example, is implemented at run time by a primitive Java int that occupies some memory in the stack frame of an executing method, then the memory for that object is “reclaimed” when the stack frame is popped as the method completes. Memory for reference types, such as `Strings`, may be reclaimed by the JVM’s garbage collector after they become unreachable. + +* #### unreferenced +See [unreachable](#unreachable). + +* #### value +The result of any computation or expression in Scala is a _value_, and in Scala, every value is an object. The term value essentially means the image of an object in memory (on the JVM’s heap or stack). + +* #### value type +A _value type_ is any subclass of `AnyVal`, such as `Int`, `Double`, or `Unit`. This term has meaning at the level of Scala source code. At runtime, instances of value types that correspond to Java primitive types may be implemented in terms of primitive type values or instances of wrapper types, such as `java.lang.Integer`. Over the lifetime of a value type instance, the runtime may transform it back and forth be- tween primitive and wrapper types (_i.e._, to box and unbox it). + +* #### variable +A named entity that refers to an object. A variable is either a `val` or a `var`. Both `val`s and `var`s must be initialized when defined, but only `var`s can be later reassigned to refer to a different object. + +* #### variance +A type parameter of a class or trait can be marked with a _variance_ annotation, either [covariant](#covariant) (+) or [contravariant](#contravariant) (-). Such variance annotations indicate how subtyping works for a generic class or trait. For example, the generic class `List` is covariant in its type parameter, and thus `List[String]` is a subtype of `List[Any]`. By default, _i.e._, absent a `+` or `-` annotation, type parameters are [nonvariant](#nonvariant). + +* #### yield +An expression can _yield_ a result. The `yield` keyword designates the result of a [for comprehension](#for-comprehension). diff --git a/documentation/index.md b/documentation/index.md index fa86384b1..9d87420dc 100644 --- a/documentation/index.md +++ b/documentation/index.md @@ -14,8 +14,8 @@ title: Learn

Access detailed documentation on important language features.

-

Tutorials

-

Digest bite-size pieces of the essentials.

+

Tutorial

+

This Scala tutorial for Java developers gets you up to speed.

@@ -29,7 +29,7 @@ title: Learn

Get an in-depth overview of the language.

-

Glossary

+

Glossary

Understand Scala's vocabulary.

@@ -44,8 +44,8 @@ title: Learn

Learn how to code elegantly.

-

Common Scala Questions

-

Dispel your doubts about common Scala features.

+

Common Questions

+

Frequent questions and answers about the Scala and its ecosystem.

diff --git a/documentation/tutorial/java/index.md b/documentation/tutorial/java/index.md new file mode 100644 index 000000000..f061e0034 --- /dev/null +++ b/documentation/tutorial/java/index.md @@ -0,0 +1,722 @@ +--- +layout: page +title: A Scala Tutorial for Java Programmers +overview: scala-for-java-programmers + +disqus: true +multilingual-overview: true +languages: [es, ko, de] +by: Michel Schinz and Philipp Haller +--- + +## Introduction + +This document gives a quick introduction to the Scala language and +compiler. It is intended for people who already have some programming +experience and want an overview of what they can do with Scala. A +basic knowledge of object-oriented programming, especially in Java, is +assumed. + +## A First Example + +As a first example, we will use the standard *Hello world* program. It +is not very fascinating but makes it easy to demonstrate the use of +the Scala tools without knowing too much about the language. Here is +how it looks: + + object HelloWorld { + def main(args: Array[String]) { + println("Hello, world!") + } + } + +The structure of this program should be familiar to Java programmers: +it consists of one method called `main` which takes the command +line arguments, an array of strings, as parameter; the body of this +method consists of a single call to the predefined method `println` +with the friendly greeting as argument. The `main` method does not +return a value (it is a procedure method). Therefore, it is not necessary +to declare a return type. + +What is less familiar to Java programmers is the `object` +declaration containing the `main` method. Such a declaration +introduces what is commonly known as a *singleton object*, that +is a class with a single instance. The declaration above thus declares +both a class called `HelloWorld` and an instance of that class, +also called `HelloWorld`. This instance is created on demand, +the first time it is used. + +The astute reader might have noticed that the `main` method is +not declared as `static` here. This is because static members +(methods or fields) do not exist in Scala. Rather than defining static +members, the Scala programmer declares these members in singleton +objects. + +### Compiling the example + +To compile the example, we use `scalac`, the Scala compiler. `scalac` +works like most compilers: it takes a source file as argument, maybe +some options, and produces one or several object files. The object +files it produces are standard Java class files. + +If we save the above program in a file called +`HelloWorld.scala`, we can compile it by issuing the following +command (the greater-than sign `>` represents the shell prompt +and should not be typed): + + > scalac HelloWorld.scala + +This will generate a few class files in the current directory. One of +them will be called `HelloWorld.class`, and contains a class +which can be directly executed using the `scala` command, as the +following section shows. + +### Running the example + +Once compiled, a Scala program can be run using the `scala` command. +Its usage is very similar to the `java` command used to run Java +programs, and accepts the same options. The above example can be +executed using the following command, which produces the expected +output: + + > scala -classpath . HelloWorld + + Hello, world! + +## Interaction with Java + +One of Scala's strengths is that it makes it very easy to interact +with Java code. All classes from the `java.lang` package are +imported by default, while others need to be imported explicitly. + +Let's look at an example that demonstrates this. We want to obtain +and format the current date according to the conventions used in a +specific country, say France. (Other regions such as the +French-speaking part of Switzerland use the same conventions.) + +Java's class libraries define powerful utility classes, such as +`Date` and `DateFormat`. Since Scala interoperates +seemlessly with Java, there is no need to implement equivalent +classes in the Scala class library--we can simply import the classes +of the corresponding Java packages: + + import java.util.{Date, Locale} + import java.text.DateFormat + import java.text.DateFormat._ + + object FrenchDate { + def main(args: Array[String]) { + val now = new Date + val df = getDateInstance(LONG, Locale.FRANCE) + println(df format now) + } + } + +Scala's import statement looks very similar to Java's equivalent, +however, it is more powerful. Multiple classes can be imported from +the same package by enclosing them in curly braces as on the first +line. Another difference is that when importing all the names of a +package or class, one uses the underscore character (`_`) instead +of the asterisk (`*`). That's because the asterisk is a valid +Scala identifier (e.g. method name), as we will see later. + +The import statement on the third line therefore imports all members +of the `DateFormat` class. This makes the static method +`getDateInstance` and the static field `LONG` directly +visible. + +Inside the `main` method we first create an instance of Java's +`Date` class which by default contains the current date. Next, we +define a date format using the static `getDateInstance` method +that we imported previously. Finally, we print the current date +formatted according to the localized `DateFormat` instance. This +last line shows an interesting property of Scala's syntax. Methods +taking one argument can be used with an infix syntax. That is, the +expression + + df format now + +is just another, slightly less verbose way of writing the expression + + df.format(now) + +This might seem like a minor syntactic detail, but it has important +consequences, one of which will be explored in the next section. + +To conclude this section about integration with Java, it should be +noted that it is also possible to inherit from Java classes and +implement Java interfaces directly in Scala. + +## Everything is an Object + +Scala is a pure object-oriented language in the sense that +*everything* is an object, including numbers or functions. It +differs from Java in that respect, since Java distinguishes +primitive types (such as `boolean` and `int`) from reference +types, and does not enable one to manipulate functions as values. + +### Numbers are objects + +Since numbers are objects, they also have methods. And in fact, an +arithmetic expression like the following: + + 1 + 2 * 3 / x + +consists exclusively of method calls, because it is equivalent to the +following expression, as we saw in the previous section: + + (1).+(((2).*(3))./(x)) + +This also means that `+`, `*`, etc. are valid identifiers +in Scala. + +The parentheses around the numbers in the second version are necessary +because Scala's lexer uses a longest match rule for tokens. +Therefore, it would break the following expression: + + 1.+(2) + +into the tokens `1.`, `+`, and `2`. The reason that +this tokenization is chosen is because `1.` is a longer valid +match than `1`. The token `1.` is interpreted as the +literal `1.0`, making it a `Double` rather than an +`Int`. Writing the expression as: + + (1).+(2) + +prevents `1` from being interpreted as a `Double`. + +### Functions are objects + +Perhaps more surprising for the Java programmer, functions are also +objects in Scala. It is therefore possible to pass functions as +arguments, to store them in variables, and to return them from other +functions. This ability to manipulate functions as values is one of +the cornerstone of a very interesting programming paradigm called +*functional programming*. + +As a very simple example of why it can be useful to use functions as +values, let's consider a timer function whose aim is to perform some +action every second. How do we pass it the action to perform? Quite +logically, as a function. This very simple kind of function passing +should be familiar to many programmers: it is often used in +user-interface code, to register call-back functions which get called +when some event occurs. + +In the following program, the timer function is called +`oncePerSecond`, and it gets a call-back function as argument. +The type of this function is written `() => Unit` and is the type +of all functions which take no arguments and return nothing (the type +`Unit` is similar to `void` in C/C++). The main function of +this program simply calls this timer function with a call-back which +prints a sentence on the terminal. In other words, this program +endlessly prints the sentence "time flies like an arrow" every +second. + + object Timer { + def oncePerSecond(callback: () => Unit) { + while (true) { callback(); Thread sleep 1000 } + } + def timeFlies() { + println("time flies like an arrow...") + } + def main(args: Array[String]) { + oncePerSecond(timeFlies) + } + } + +Note that in order to print the string, we used the predefined method +`println` instead of using the one from `System.out`. + +#### Anonymous functions + +While this program is easy to understand, it can be refined a bit. +First of all, notice that the function `timeFlies` is only +defined in order to be passed later to the `oncePerSecond` +function. Having to name that function, which is only used once, might +seem unnecessary, and it would in fact be nice to be able to construct +this function just as it is passed to `oncePerSecond`. This is +possible in Scala using *anonymous functions*, which are exactly +that: functions without a name. The revised version of our timer +program using an anonymous function instead of *timeFlies* looks +like that: + + object TimerAnonymous { + def oncePerSecond(callback: () => Unit) { + while (true) { callback(); Thread sleep 1000 } + } + def main(args: Array[String]) { + oncePerSecond(() => + println("time flies like an arrow...")) + } + } + +The presence of an anonymous function in this example is revealed by +the right arrow `=>` which separates the function's argument +list from its body. In this example, the argument list is empty, as +witnessed by the empty pair of parenthesis on the left of the arrow. +The body of the function is the same as the one of `timeFlies` +above. + +## Classes + +As we have seen above, Scala is an object-oriented language, and as +such it has a concept of class. (For the sake of completeness, + it should be noted that some object-oriented languages do not have + the concept of class, but Scala is not one of them.) +Classes in Scala are declared using a syntax which is close to +Java's syntax. One important difference is that classes in Scala can +have parameters. This is illustrated in the following definition of +complex numbers. + + class Complex(real: Double, imaginary: Double) { + def re() = real + def im() = imaginary + } + +This complex class takes two arguments, which are the real and +imaginary part of the complex. These arguments must be passed when +creating an instance of class `Complex`, as follows: `new + Complex(1.5, 2.3)`. The class contains two methods, called `re` +and `im`, which give access to these two parts. + +It should be noted that the return type of these two methods is not +given explicitly. It will be inferred automatically by the compiler, +which looks at the right-hand side of these methods and deduces that +both return a value of type `Double`. + +The compiler is not always able to infer types like it does here, and +there is unfortunately no simple rule to know exactly when it will be, +and when not. In practice, this is usually not a problem since the +compiler complains when it is not able to infer a type which was not +given explicitly. As a simple rule, beginner Scala programmers should +try to omit type declarations which seem to be easy to deduce from the +context, and see if the compiler agrees. After some time, the +programmer should get a good feeling about when to omit types, and +when to specify them explicitly. + +### Methods without arguments + +A small problem of the methods `re` and `im` is that, in +order to call them, one has to put an empty pair of parenthesis after +their name, as the following example shows: + + object ComplexNumbers { + def main(args: Array[String]) { + val c = new Complex(1.2, 3.4) + println("imaginary part: " + c.im()) + } + } + +It would be nicer to be able to access the real and imaginary parts +like if they were fields, without putting the empty pair of +parenthesis. This is perfectly doable in Scala, simply by defining +them as methods *without arguments*. Such methods differ from +methods with zero arguments in that they don't have parenthesis after +their name, neither in their definition nor in their use. Our +`Complex` class can be rewritten as follows: + + class Complex(real: Double, imaginary: Double) { + def re = real + def im = imaginary + } + + +### Inheritance and overriding + +All classes in Scala inherit from a super-class. When no super-class +is specified, as in the `Complex` example of previous section, +`scala.AnyRef` is implicitly used. + +It is possible to override methods inherited from a super-class in +Scala. It is however mandatory to explicitly specify that a method +overrides another one using the `override` modifier, in order to +avoid accidental overriding. As an example, our `Complex` class +can be augmented with a redefinition of the `toString` method +inherited from `Object`. + + class Complex(real: Double, imaginary: Double) { + def re = real + def im = imaginary + override def toString() = + "" + re + (if (im < 0) "" else "+") + im + "i" + } + + +## Case Classes and Pattern Matching + +A kind of data structure that often appears in programs is the tree. +For example, interpreters and compilers usually represent programs +internally as trees; XML documents are trees; and several kinds of +containers are based on trees, like red-black trees. + +We will now examine how such trees are represented and manipulated in +Scala through a small calculator program. The aim of this program is +to manipulate very simple arithmetic expressions composed of sums, +integer constants and variables. Two examples of such expressions are +`1+2` and `(x+x)+(7+y)`. + +We first have to decide on a representation for such expressions. The +most natural one is the tree, where nodes are operations (here, the +addition) and leaves are values (here constants or variables). + +In Java, such a tree would be represented using an abstract +super-class for the trees, and one concrete sub-class per node or +leaf. In a functional programming language, one would use an algebraic +data-type for the same purpose. Scala provides the concept of +*case classes* which is somewhat in between the two. Here is how +they can be used to define the type of the trees for our example: + + abstract class Tree + case class Sum(l: Tree, r: Tree) extends Tree + case class Var(n: String) extends Tree + case class Const(v: Int) extends Tree + +The fact that classes `Sum`, `Var` and `Const` are +declared as case classes means that they differ from standard classes +in several respects: + +- the `new` keyword is not mandatory to create instances of + these classes (i.e., one can write `Const(5)` instead of + `new Const(5)`), +- getter functions are automatically defined for the constructor + parameters (i.e., it is possible to get the value of the `v` + constructor parameter of some instance `c` of class + `Const` just by writing `c.v`), +- default definitions for methods `equals` and + `hashCode` are provided, which work on the *structure* of + the instances and not on their identity, +- a default definition for method `toString` is provided, and + prints the value in a "source form" (e.g., the tree for expression + `x+1` prints as `Sum(Var(x),Const(1))`), +- instances of these classes can be decomposed through + *pattern matching* as we will see below. + +Now that we have defined the data-type to represent our arithmetic +expressions, we can start defining operations to manipulate them. We +will start with a function to evaluate an expression in some +*environment*. The aim of the environment is to give values to +variables. For example, the expression `x+1` evaluated in an +environment which associates the value `5` to variable `x`, written +`{ x -> 5 }`, gives `6` as result. + +We therefore have to find a way to represent environments. We could of +course use some associative data-structure like a hash table, but we +can also directly use functions! An environment is really nothing more +than a function which associates a value to a (variable) name. The +environment `{ x -> 5 }` given above can simply be written as +follows in Scala: + + { case "x" => 5 } + +This notation defines a function which, when given the string +`"x"` as argument, returns the integer `5`, and fails with an +exception otherwise. + +Before writing the evaluation function, let us give a name to the type +of the environments. We could of course always use the type +`String => Int` for environments, but it simplifies the program +if we introduce a name for this type, and makes future changes easier. +This is accomplished in Scala with the following notation: + + type Environment = String => Int + +From then on, the type `Environment` can be used as an alias of +the type of functions from `String` to `Int`. + +We can now give the definition of the evaluation function. +Conceptually, it is very simple: the value of a sum of two expressions +is simply the sum of the value of these expressions; the value of a +variable is obtained directly from the environment; and the value of a +constant is the constant itself. Expressing this in Scala is not more +difficult: + + def eval(t: Tree, env: Environment): Int = t match { + case Sum(l, r) => eval(l, env) + eval(r, env) + case Var(n) => env(n) + case Const(v) => v + } + +This evaluation function works by performing *pattern matching* +on the tree `t`. Intuitively, the meaning of the above definition +should be clear: + +1. it first checks if the tree `t` is a `Sum`, and if it + is, it binds the left sub-tree to a new variable called `l` and + the right sub-tree to a variable called `r`, and then proceeds + with the evaluation of the expression following the arrow; this + expression can (and does) make use of the variables bound by the + pattern appearing on the left of the arrow, i.e., `l` and + `r`, +2. if the first check does not succeed, that is, if the tree is not + a `Sum`, it goes on and checks if `t` is a `Var`; if + it is, it binds the name contained in the `Var` node to a + variable `n` and proceeds with the right-hand expression, +3. if the second check also fails, that is if `t` is neither a + `Sum` nor a `Var`, it checks if it is a `Const`, and + if it is, it binds the value contained in the `Const` node to a + variable `v` and proceeds with the right-hand side, +4. finally, if all checks fail, an exception is raised to signal + the failure of the pattern matching expression; this could happen + here only if more sub-classes of `Tree` were declared. + +We see that the basic idea of pattern matching is to attempt to match +a value to a series of patterns, and as soon as a pattern matches, +extract and name various parts of the value, to finally evaluate some +code which typically makes use of these named parts. + +A seasoned object-oriented programmer might wonder why we did not +define `eval` as a *method* of class `Tree` and its +subclasses. We could have done it actually, since Scala allows method +definitions in case classes just like in normal classes. Deciding +whether to use pattern matching or methods is therefore a matter of +taste, but it also has important implications on extensibility: + +- when using methods, it is easy to add a new kind of node as this + can be done just by defining a sub-class of `Tree` for it; on + the other hand, adding a new operation to manipulate the tree is + tedious, as it requires modifications to all sub-classes of + `Tree`, +- when using pattern matching, the situation is reversed: adding a + new kind of node requires the modification of all functions which do + pattern matching on the tree, to take the new node into account; on + the other hand, adding a new operation is easy, by just defining it + as an independent function. + +To explore pattern matching further, let us define another operation +on arithmetic expressions: symbolic derivation. The reader might +remember the following rules regarding this operation: + +1. the derivative of a sum is the sum of the derivatives, +2. the derivative of some variable `v` is one if `v` is the + variable relative to which the derivation takes place, and zero + otherwise, +3. the derivative of a constant is zero. + +These rules can be translated almost literally into Scala code, to +obtain the following definition: + + def derive(t: Tree, v: String): Tree = t match { + case Sum(l, r) => Sum(derive(l, v), derive(r, v)) + case Var(n) if (v == n) => Const(1) + case _ => Const(0) + } + +This function introduces two new concepts related to pattern matching. +First of all, the `case` expression for variables has a +*guard*, an expression following the `if` keyword. This +guard prevents pattern matching from succeeding unless its expression +is true. Here it is used to make sure that we return the constant `1` +only if the name of the variable being derived is the same as the +derivation variable `v`. The second new feature of pattern +matching used here is the *wildcard*, written `_`, which is +a pattern matching any value, without giving it a name. + +We did not explore the whole power of pattern matching yet, but we +will stop here in order to keep this document short. We still want to +see how the two functions above perform on a real example. For that +purpose, let's write a simple `main` function which performs +several operations on the expression `(x+x)+(7+y)`: it first computes +its value in the environment `{ x -> 5, y -> 7 }`, then +computes its derivative relative to `x` and then `y`. + + def main(args: Array[String]) { + val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y"))) + val env: Environment = { case "x" => 5 case "y" => 7 } + println("Expression: " + exp) + println("Evaluation with x=5, y=7: " + eval(exp, env)) + println("Derivative relative to x:\n " + derive(exp, "x")) + println("Derivative relative to y:\n " + derive(exp, "y")) + } + +Executing this program, we get the expected output: + + Expression: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y))) + Evaluation with x=5, y=7: 24 + Derivative relative to x: + Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0))) + Derivative relative to y: + Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1))) + +By examining the output, we see that the result of the derivative +should be simplified before being presented to the user. Defining a +basic simplification function using pattern matching is an interesting +(but surprisingly tricky) problem, left as an exercise for the reader. + +## Traits + +Apart from inheriting code from a super-class, a Scala class can also +import code from one or several *traits*. + +Maybe the easiest way for a Java programmer to understand what traits +are is to view them as interfaces which can also contain code. In +Scala, when a class inherits from a trait, it implements that trait's +interface, and inherits all the code contained in the trait. + +To see the usefulness of traits, let's look at a classical example: +ordered objects. It is often useful to be able to compare objects of a +given class among themselves, for example to sort them. In Java, +objects which are comparable implement the `Comparable` +interface. In Scala, we can do a bit better than in Java by defining +our equivalent of `Comparable` as a trait, which we will call +`Ord`. + +When comparing objects, six different predicates can be useful: +smaller, smaller or equal, equal, not equal, greater or equal, and +greater. However, defining all of them is fastidious, especially since +four out of these six can be expressed using the remaining two. That +is, given the equal and smaller predicates (for example), one can +express the other ones. In Scala, all these observations can be +nicely captured by the following trait declaration: + + trait Ord { + def < (that: Any): Boolean + def <=(that: Any): Boolean = (this < that) || (this == that) + def > (that: Any): Boolean = !(this <= that) + def >=(that: Any): Boolean = !(this < that) + } + +This definition both creates a new type called `Ord`, which +plays the same role as Java's `Comparable` interface, and +default implementations of three predicates in terms of a fourth, +abstract one. The predicates for equality and inequality do not appear +here since they are by default present in all objects. + +The type `Any` which is used above is the type which is a +super-type of all other types in Scala. It can be seen as a more +general version of Java's `Object` type, since it is also a +super-type of basic types like `Int`, `Float`, etc. + +To make objects of a class comparable, it is therefore sufficient to +define the predicates which test equality and inferiority, and mix in +the `Ord` class above. As an example, let's define a +`Date` class representing dates in the Gregorian calendar. Such +dates are composed of a day, a month and a year, which we will all +represent as integers. We therefore start the definition of the +`Date` class as follows: + + class Date(y: Int, m: Int, d: Int) extends Ord { + def year = y + def month = m + def day = d + override def toString(): String = year + "-" + month + "-" + day + +The important part here is the `extends Ord` declaration which +follows the class name and parameters. It declares that the +`Date` class inherits from the `Ord` trait. + +Then, we redefine the `equals` method, inherited from +`Object`, so that it correctly compares dates by comparing their +individual fields. The default implementation of `equals` is not +usable, because as in Java it compares objects physically. We arrive +at the following definition: + + override def equals(that: Any): Boolean = + that.isInstanceOf[Date] && { + val o = that.asInstanceOf[Date] + o.day == day && o.month == month && o.year == year + } + +This method makes use of the predefined methods `isInstanceOf` +and `asInstanceOf`. The first one, `isInstanceOf`, +corresponds to Java's `instanceof` operator, and returns true +if and only if the object on which it is applied is an instance of the +given type. The second one, `asInstanceOf`, corresponds to +Java's cast operator: if the object is an instance of the given type, +it is viewed as such, otherwise a `ClassCastException` is +thrown. + +Finally, the last method to define is the predicate which tests for +inferiority, as follows. It makes use of another predefined method, +`error`, which throws an exception with the given error message. + + def <(that: Any): Boolean = { + if (!that.isInstanceOf[Date]) + error("cannot compare " + that + " and a Date") + + val o = that.asInstanceOf[Date] + (year < o.year) || + (year == o.year && (month < o.month || + (month == o.month && day < o.day))) + } + +This completes the definition of the `Date` class. Instances of +this class can be seen either as dates or as comparable objects. +Moreover, they all define the six comparison predicates mentioned +above: `equals` and `<` because they appear directly in +the definition of the `Date` class, and the others because they +are inherited from the `Ord` trait. + +Traits are useful in other situations than the one shown here, of +course, but discussing their applications in length is outside the +scope of this document. + +## Genericity + +The last characteristic of Scala we will explore in this tutorial is +genericity. Java programmers should be well aware of the problems +posed by the lack of genericity in their language, a shortcoming which +is addressed in Java 1.5. + +Genericity is the ability to write code parametrized by types. For +example, a programmer writing a library for linked lists faces the +problem of deciding which type to give to the elements of the list. +Since this list is meant to be used in many different contexts, it is +not possible to decide that the type of the elements has to be, say, +`Int`. This would be completely arbitrary and overly +restrictive. + +Java programmers resort to using `Object`, which is the +super-type of all objects. This solution is however far from being +ideal, since it doesn't work for basic types (`int`, +`long`, `float`, etc.) and it implies that a lot of +dynamic type casts have to be inserted by the programmer. + +Scala makes it possible to define generic classes (and methods) to +solve this problem. Let us examine this with an example of the +simplest container class possible: a reference, which can either be +empty or point to an object of some type. + + class Reference[T] { + private var contents: T = _ + def set(value: T) { contents = value } + def get: T = contents + } + +The class `Reference` is parametrized by a type, called `T`, +which is the type of its element. This type is used in the body of the +class as the type of the `contents` variable, the argument of +the `set` method, and the return type of the `get` method. + +The above code sample introduces variables in Scala, which should not +require further explanations. It is however interesting to see that +the initial value given to that variable is `_`, which represents +a default value. This default value is 0 for numeric types, +`false` for the `Boolean` type, `()` for the `Unit` +type and `null` for all object types. + +To use this `Reference` class, one needs to specify which type to use +for the type parameter `T`, that is the type of the element +contained by the cell. For example, to create and use a cell holding +an integer, one could write the following: + + object IntegerReference { + def main(args: Array[String]) { + val cell = new Reference[Int] + cell.set(13) + println("Reference contains the half of " + (cell.get * 2)) + } + } + +As can be seen in that example, it is not necessary to cast the value +returned by the `get` method before using it as an integer. It +is also not possible to store anything but an integer in that +particular cell, since it was declared as holding an integer. + +## Conclusion + +This document gave a quick overview of the Scala language and +presented some basic examples. The interested reader can go on, for example, by +reading the document *Scala By Example*, which +contains much more advanced examples, and consult the *Scala + Language Specification* when needed. diff --git a/es/tutorials/index.md b/es/tutorials/index.md new file mode 100644 index 000000000..b3ccaf83f --- /dev/null +++ b/es/tutorials/index.md @@ -0,0 +1,409 @@ +--- +layout: page +title: Tutorial de Scala para programadores Java +overview: scala-for-java-programmers + +disqus: true +language: es +by: por Michel Schinz y Philipp Haller, traducción y arreglos Santiago Basulto +--- + +## Introducción + +Este documento provee una rápida introducción al lenguaje Scala como también a su compilador. Está pensado para personas que ya poseen cierta experiencia en programación y quieren una vista rápida de lo que pueden hacer con Scala. Se asume como un conocimiento básico de programación orientada a objetos, especialmente en Java. + +## Un primer ejemplo + +Como primer ejemplo, usaremos el programa *Hola mundo* estándar. No es muy fascinante, pero de esta manera resulta fácil demostrar el uso de herramientas de Scala sin saber demasiado acerca del lenguaje. Veamos como luce: + + object HolaMundo { + def main(args: Array[String]) { + println("¡Hola, mundo!") + } + } + +La estructura de este programa debería ser familiar para programadores Java: consiste de un método llamado `main` que toma los argumentos de la línea de comando (un array de objetos String) como parámetro; el cuerpo de este método consiste en una sola llamada al método predefinido `println` con el saludo amistoso como argumento. El método `main` no retorna un valor (se puede entender como un procedimiento). Por lo tanto, no es necesario que se declare un tipo retorno. + +Lo que es menos familiar a los programadores Java es la declaración de `object` que contiene al método `main`. Esa declaración introduce lo que es comúnmente conocido como *objeto singleton*, que es una clase con una sola instancia. Por lo tanto, dicha construcción declara tanto una clase llamada `HolaMundo` como una instancia de esa clase también llamada `HolaMundo`. Esta instancia es creada bajo demanda, es decir, la primera vez que es utilizada. + +El lector astuto notará que el método `main` no es declarado como `static`. Esto es así porque los miembros estáticos (métodos o campos) no existen en Scala. En vez de definir miembros estáticos, el programador de Scala declara estos miembros en un objeto singleton. + +### Compilando el ejemplo + +Para compilar el ejemplo utilizaremos `scalac`, el compilador de Scala. `scalac` funciona como la mayoría de los compiladores. Toma un archivo fuente como argumento, algunas opciones y produce uno o varios archivos objeto. Los archivos objeto que produce son archivos class de Java estándar. + +Si guardamos el programa anterior en un archivo llamado `HolaMundo.scala`, podemos compilarlo ejecutando el siguiente comando (el símbolo mayor `>` representa el prompt del shell y no debe ser escrita): + + > scalac HolaMundo.scala + +Esto generará algunos archivos class en el directorio actual. Uno de ellos se llamará `HolaMundo.class` y contiene una clase que puede ser directamente ejecutada utilizando el comando `scala`, como mostramos en la siguiente sección. + +### Ejecutando el ejemplo + +Una vez compilado, un programa Scala puede ser ejecutado utilizando el comando `scala`. Su uso es muy similar al comando `java` utilizado para ejecutar programas Java, y acepta las mismas opciones. El ejemplo de arriba puede ser ejecutado utilizando el siguiente comando, que produce la salida esperada: + + > scala -classpath . HolaMundo + + ¡Hola, mundo! + +## Interacción con Java + +Una de las fortalezas de Scala es que hace muy fácil interactuar con código Java. Todas las clases del paquete `java.lang` son importadas por defecto, mientras otras necesitan ser importadas explícitamente. + +Veamos un ejemplo que demuestra esto. Queremos obtener y formatear la fecha actual de acuerdo a convenciones utilizadas en un país específico, por ejemplo Francia. + +Las librerías de clases de Java definen clases de utilería poderosas, como `Date` y `DateFormat`. Ya que Scala interacciona fácilmente con Java, no es necesario implementar estas clases equivalentes en las librerías de Scala --podemos simplemente importar las clases de los correspondientes paquetes de Java: + + import java.util.{Date, Locale} + import java.text.DateFormat + import java.text.DateFormat._ + + object FrenchDate { + def main(args: Array[String]) { + val ahora = new Date + val df = getDateInstance(LONG, Locale.FRANCE) + println(df format ahora) + } + } + +Las declaraciones de importación de Scala lucen muy similares a las de Java, sin embargo, las primeras son bastante más poderosas. Múltiples clases pueden ser importadas desde el mismo paquete al encerrarlas en llaves como se muestra en la primer línea. Otra diferencia es que podemos importar todos los nombres de un paquete o clase, utilizando el carácter guión bajo (`_`) en vez del asterisco (`*`). Eso es porque el asterisco es un identificador válido en Scala (quiere decir que por ejemplo podemos nombrar a un método `*`), como veremos más adelante. + +La declaración `import` en la tercer línea por lo tanto importa todos los miembros de la clase `DateFormat`. Esto hace que el método estático `getDateInstance` y el campo estático `LONG` sean directamente visibles. + +Dentro del método `main` primero creamos una instancia de la clase `Date` la cual por defecto contiene la fecha actual. A continuación definimos un formateador de fechas utilizando el método estático `getDateInstance` que importamos previamente. Finalmente, imprimimos la fecha actual formateada de acuerdo a la instancia de `DateFormat` que fue "localizada". Esta última línea muestra una propiedad interesante de la sintaxis de Scala. Los métodos que toman un solo argumento pueden ser usados con una sintaxis de infijo Es decir, la expresión + + df format ahora + +es solamente otra manera más corta de escribir la expresión: + + df.format(ahora) + +Esto parece tener como un detalle sintáctico menor, pero tiene importantes consecuencias, una de ellas la exploraremos en la próxima sección. + +Para concluir esta sección sobre la interacción con Java, es importante notar que es también posible heredar de clases Java e implementar interfaces Java directamente en Scala. + +## Todo es un objeto + +Scala es un lenguaje puramente orientado a objetos en el sentido de que *todo* es un objeto, incluyendo números o funciones. Difiere de Java en este aspecto, ya que Java distingue tipos primitivos (como `boolean` e `int`) de tipos referenciales, y no nos permite manipular las funciones como valores. + +### Los números son objetos + +Ya que los números son objetos, estos también tienen métodos. De hecho, una expresión aritmética como la siguiente: + + 1 + 2 * 3 / x + +Consiste exclusivamente de llamadas a métodos, porque es equivalente a la siguiente expresión, como vimos en la sección anterior: + + (1).+(((2).*(3))./(x)) + +Esto también indica que `+`, `*`, etc. son identificadores válidos en Scala. + +Los paréntesis alrededor de los números en la segunda versión son necesarios porque el analizador léxico de Scala usa la regla de "mayor coincidencia". Por lo tanto partiría la siguiente expresión: + + 1.+(2) + +En estas partes: `1.`, `+`, y `2`. La razón que esta regla es elegida es porque `1.` es una coincidencia válida y es mayor que `1`, haciendo a este un `Double` en vez de un `Int`. Al escribir la expresión así: + + (1).+(2) + +previene que el `1` sea tomado como un `Double`. + +### Las funciones son objetos + +Tal vez suene más sorprendente para los programadores Java, las funciones en Scala también son objetos. Por lo tanto es posible pasar funciones como argumentos, almacenarlas en variables, y retornarlas desde otras funciones. Esta habilidad de manipular funciones como valores es una de las valores fundamentales de un paradigma de programación muy interesante llamado *programación funcional*. + +Como un ejemplo muy simple de por qué puede ser útil usar funciones como valores consideremos una función *temporizador* (o timer, en inglés) cuyo propósito es realizar alguna acción cada un segundo. ¿Cómo pasamos al temporizador la acción a realizar? Bastante lógico, como una función. Este simple concepto de pasar funciones debería ser familiar para muchos programadores: es generalmente utilizado en código relacionado con Interfaces gráficas de usuario (GUIs) para registrar "retrollamadas" (call-back en inglés) que son invocadas cuando un evento ocurre. + +En el siguiente programa, la función del temporizador se llama `unaVezPorSegundo` y recibe una función call-back como argumento. El tipo de esta función es escrito de la siguiente manera: `() => Unit` y es el tipo de todas las funciones que no toman argumentos ni retornan valores (el tipo `Unit` es similar a `void` en Java/C/C++). La función principal de este programa simplemente invoca esta función temporizador con una call-back que imprime una sentencia en la terminal. En otras palabras, este programa imprime interminablemente la sentencia "El tiempo vuela como una flecha" cada segundo. + + object Temporizador { + def unaVezPorSegundo(callback: () => Unit) { + while (true) { callback(); Thread sleep 1000 } + } + def tiempoVuela() { + println("El tiempo vuela como una flecha...") + } + def main(args: Array[String]) { + unaVezPorSegundo(tiempoVuela) + } + } + +_Nota: si nunca tuviste experiencias previas con programación funcional te recomiendo que te tomes unos segundos para analizar cuando se utilizan paréntesis y cuando no en los lugares donde aparece *callback*. Por ejemplo, dentro de la declaración de `unaVezPorSegundo` no aparece, ya que se trata de la función como un "valor", a diferencia de cómo aparece dentro del método, ya que en ese caso se la está invocando (por eso los paréntesis)._ +Note that in order to print the string, we used the predefined method +`println` instead of using the one from `System.out`. + +#### Funciones anónimas + +El programa anterior es fácil de entender, pero puede ser refinado aún más. Primero que nada es interesante notar que la función `tiempoVuela` está definida solamente para ser pasada posteriormente a la función `unaVezPorSegundo`. Tener que nombrar esa función, que es utilizada solamente una vez parece un poco innecesario y sería bueno poder construirla justo cuando sea pasada a `unaVezPorSegundo`. Esto es posible en Scala utilizando *funciones anónimas*, que son exactamente eso: funciones sin nombre. La versión revisada de nuestro temporizador utilizando una función anónima luce así: + + object TemporizadorAnonimo { + def unaVezPorSegundo(callback: () => Unit) { + while (true) { callback(); Thread sleep 1000 } + } + def main(args: Array[String]) { + unaVezPorSegundo( + () => println("El tiempo vuela como una flecha...") + ) + } + } + +La presencia de una función anónima en este ejemplo es revelada por la flecha a la derecha `=>` que separa los argumentos de la función del cuerpo de esta. En este ejemplo, la lista de argumentos está vacía, como se ve por el par de paréntesis vacíos a la izquierda de la flecha. El cuerpo de la función es el mismo que en `tiempoVuela` del programa anterior. + +## Clases + +Como hemos visto anteriormente, Scala es un lenguaje orientado a objetos, y como tal tiene el concepto de Clase (en realidad existen lenguajes orientados a objetos que no cuentan con el concepto de clases, pero Scala no es uno de ellos). Las clases en Scala son declaradas utilizando una sintaxis que es cercana a la de Java. Una diferencia importante es que las clases en Scala pueden tener parámetros. Ilustramos esto en el siguiente ejemplo, la definición de un número complejo: + + class Complejo(real: Double, imaginaria: Double) { + def re() = real + def im() = imaginaria + } + +Esta clase compleja toma dos argumentos, que son las partes real e imaginarias de un número complejo. Estos argumentos deben ser pasados cuando se crea una instancia de la clase `Complejo`, de la siguiente manera: + + new Complejo(1.5, 2.3) + +La clase contiene dos métodos llamados `re` e `im`, que proveen acceso a las dos partes del número. + +Debe notarse que el tipo de retorno de estos dos métodos no está expresado explícitamente. Será inferido automáticamente por el compilador, que primero mira la parte derecha de estos métodos y puede deducir que ambos retornan un valor de tipo `Double`. + +El compilador no es siempre capaz de inferir los tipos como lo hace aquí, y desafortunadamente no existe una regla simple para saber cuándo será y cuándo no. En la práctica, esto generalmente no es un problema ya que el compilador se queja cuando no es capaz de inferir un tipo que no fue explícitamente fijado. Como regla simple, los programadores de Scala novatos deberían tratar de omitir las declaraciones de tipos que parecen ser simples de deducir del contexto y ver si el compilador no lanza errores. Después de algún tiempo, el programador debería tener una buena idea de cuando omitir tipos y cuando explicitarlos. + +### Métodos sin argumentos + +Un pequeño problema de los métodos `re` e `im` es que para poder llamarlos es necesario agregar un par de paréntesis vacíos después de sus nombres, como muestra el siguiente ejemplo: + + object NumerosComplejos { + def main(args: Array[String]) { + val c = new Complejo(1.2, 3.4) + println("Parte imaginaria: " + c.im()) + } + } + +Sería mejor poder acceder las partes imaginarias y reales como si fueran campos, sin poner los paréntesis vacíos. Esto es perfectamente realizable en Scala, simplemente al definirlos como *métodos sin argumentos*. Tales métodos difieren de los métodos con cero o más argumentos en que no tienen paréntesis después de su nombre, tanto en la definición como en el uso. Nuestra clase `Complejo` puede ser reescrita así: + + class Complejo(real: Double, imaginaria: Double) { + def re = real + def im = imaginaria + } + + +### Herencia y sobreescritura + +Todas las clases en Scala heredan de una superclase. Cuando ninguna superclase es especificada, como es el caso de `Complejo` se utiliza implícitamente `scala.AnyRef`. + +Es posible sobreescribir métodos heredados de una superclase en Scala. Aunque es necesario explicitar específicamente que un método sobreescribe otro utilizando el modificador `override`, de manera de evitar sobreescrituras accidentales. Como ejemplo, nuestra clase `Complejo` puede ser aumentada con la redefinición del método `toString` heredado de `Object`. + + class Complejo(real: Double, imaginaria: Double) { + def re = real + def im = imaginaria + override def toString() = + "" + re + (if (im < 0) "" else "+") + im + "i" + } + +## Clases Case y Reconocimiento de patrones + +Un tipo de estructura de datos que aparece seguido en programas es el Árbol. Por ejemplo, los intérpretes y compiladores usualmente representan los programas internamente como árboles; los documentos XML son árboles; y muchos otros tipos de contenedores están basados en árboles, como los árboles rojo y negro. + +Ahora examinaremos cómo estos árboles son representados y manipulados en Scala mediante un pequeño programa que oficie de calculadora. El objetivo de este programa es manipular expresiones aritméticas simples compuestas de sumas de enteros y variables. Dos ejemplos de estas expresiones pueden ser: `1+2` y `(x+x)+(7+y)`. + +Primero tenemos que decidir una representación para tales expresiones. La más natural es un árbol, donde los nodos son las operaciones (la adición en este caso) y las hojas son valores (constantes o variables). + +En Java, un árbol así sería representado utilizando una superclase abstracta para los árboles, y una subclase concreta por nodo u hoja. En un lenguaje de programación funcional uno utilizaría un tipo de dato algebraico para el mismo propósito. Scala provee el concepto de *clases case* que está en el medio de los dos conceptos anteriores. Aquí mostramos como pueden ser usadas para definir el tipo de los árboles en nuestro ejemplo: + + abstract class Arbol + case class Sum(l: Arbol, r: Arbol) extends Arbol + case class Var(n: String) extends Arbol + case class Const(v: Int) extends Arbol + +El hecho de que las clases `Sum`, `Var` y `Const` sean declaradas como clases case significa que dififieren de las clases normales en varios aspectos: + +- no es obligatorio utilizar la palabra clave `new` para crear + instancias de estas clases (es decir, se puede escribir `Const(5)` + en lugar de `new Const(5)`), +- se crea automáticamente un "getter" (un método para obtener el valor) + para los parámetros utilizados en el constructor (por ejemplo es posible + obtener el valor de `v` de una instancia `c` de la clase `Const` de la + siguiente manera: `c.v`), +- se proveen definiciones por defecto de los métodos `equals` y `hashCode`, + que trabajan sobre la estructura de las instancias y no sobre su identidad, +- se crea una definición por defecto del método `toString` que + imprime el valor de una forma "tipo código) (ej: la expresión + del árbol `x+1` se imprimiría `Sum(Var(x),Const(1))`), +- las instancias de estas clases pueden ser descompuestas + mediante *reconocimiento de patrones* (pattern matching) + como veremos más abajo. + +Ahora que hemos definido el tipo de datos para representar nuestra expresión aritmética podemos empezar definiendo operaciones para manipularlas. Empezaremos con una función para evaluar una expresión en un *entorno*. El objetivo del entorno es darle valores a las variables. Por ejemplo, la expresión `x+1` evaluada en un entorno que asocia el valor `5` a la variable `x`, escrito `{ x -> 5 }`, da como resultado `6`. + +Por lo tanto tenemos que encontrar una manera de representar entornos. Podríamos por supuesto utilizar alguna estructura de datos asociativa como una tabla hash, pero podemos directamente utilizar funciones! Un entorno realmente no es nada más que una función la cual asocia valores a variables. El entorno `{ x -> 5 }` mostrado anteriormente puede ser fácilmente escrito de la siguiente manera en Scala: + + { case "x" => 5 } + +Esta notación define una función la cual, dado un string `"x"` como argumento retorna el entero `5`, y falla con una excepción si no fuera así. + +Antes de escribir la función evaluadora, démosle un nombre al tipo de los entornos. Podríamos por supuesto simplemente utilizar `String => Int` para los entornos, pero simplifica el programa introducir un nombre para este tipo, y hace que los futuros cambios sean más fáciles. Esto lo realizamos de la siguiente manera: + + type Entorno = String => Int + +De ahora en más, el tipo `Entorno` puede ser usado como un alias del tipo de funciones definidas de `String` a `Int`. + +Ahora podemos dar la definición de la función evaluadora. Conceptualmente, es muy sencillo: el valor de una suma de dos expresiones es simplemente la suma de los valores de estas expresiones; el valor de una variable es obtenido directamente del entorno; y el valor de una constante es la constante en sí misma. Expresar esto en Scala no resulta para nada difícil: + + def eval(a: Arbol, ent: Entorno): Int = a match { + case Sum(i, d) => eval(i, ent) + eval(d, env) + case Var(n) => ent(n) + case Const(v) => v + } + +Esta función evaluadora función realizando un *reconocimiento de patrones* (pattern matching) en el árbol `a`. Intuitivamente, el significado de la definición de arriba debería estar claro: + +1. Primero comprueba si el árbol `t`es una `Sum`, y si lo es, asocia el sub-arbol izquierdo a una nueva variable llamada `i` y el sub-arbol derecho a la variable `r`, y después procede con la evaluación de la expresión que sigue a la flecha (`=>`); esta expresión puede (y hace) uso de las variables asociadas por el patrón que aparece del lado izquierdo de la flecha. +2. si la primer comprobación (la de `Sum`) no prospera, es decir que el árbol no es una `Sum`, sigue de largo y comprueba si `a` es un `Var`; si lo es, asocia el nombre contenido en el nodo `Var` a la variable `n` y procede con la parte derecha de la expresión. +3. si la segunda comprobación también falla, resulta que `a` no es un `Sum` ni un `Var`, por lo tanto comprueba que sea un `Const`, y si lo es, asocia el valor contenido en el nodo `Const` a la variable `v`y procede con el lado derecho. +4. finalmente, si todos las comprobaciones fallan, una excepción es lanzada para dar cuenta el fallo de la expresión; esto puede pasar solo si existen más subclases de `Arbol`. + +Hemos visto que la idea básica del reconocimiento de patrones es intentar coincidir un valor con una serie de patrones, y tan pronto como un patrón coincida, extraer y nombrar las varias partes del valor para finalmente evaluar algo de código que típicamente hace uso de esas partes nombradas. + +Un programador con experiencia en orientación a objetos puede preguntarse por qué no definimos `eval` como un método de la clase `Arbol` y sus subclases. En realidad podríamos haberlo hecho, ya que Scala permite la definición de métodos en clases case tal como en clases normales. Por lo tanto decidir en usar reconocimiento de patrones o métodos es una cuestión de gustos, pero también tiene grandes implicancias en cuanto a la extensibilidad: + +- cuando usamos métodos, es fácil añadir un nuevo tipo de nodo ya que esto puede ser realizado simplemente al definir una nueva subclase de `Arbol`; por otro lado, añadir una nueva operación para manipular el árbol es tedioso, ya que requiere la modificación en todas las subclases. + +- cuando utilizamos reconocimiento de patrones esta situación es inversa: agregar un nuevo tipo de nodo requiere la modificación de todas las funciones que hacen reconocimiento de patrones sobre el árbol, para tomar en cuenta un nuevo nodo; pero por otro lado agregar una nueva operación fácil, solamente definiendolo como una función independiente. + +Para explorar un poco más esto de pattern matching definamos otra operación aritmética: derivación simbólica. El lector recordará las siguientes reglas sobre esta operación: + +1. la derivada de una suma es la suma de las derivadas, +2. la derivada de una variable `v` es uno (1) si `v` es la variable relativa a la cual la derivada toma lugar, y cero (0)de otra manera, +3. la derivada de una constante es cero (0). + +Estas reglas pueden ser traducidas casi literalmente en código Sclaa, para obtener la siguiente definición. + + def derivada(a: Arbol, v: String): Arbol = a match { + case Sum(l, r) => Sum(derivada(l, v), derivada(r, v)) + case Var(n) if (v == n) => Const(1) + case _ => Const(0) + } + +Esta función introduce dos nuevos conceptos relacionados al pattern matching. Primero que nada la expresión `case` para variables tienen una *guarda*, una expresión siguiendo la palabra clave `if`. Esta guarda previene que el patrón concuerde al menos que la expresión sea verdadera. Aquí es usada para asegurarse que retornamos la constante 1 solo si el nombre de la variable siendo derivada es el mismo que la variable derivada `v`. El segundo concepto nuevo usado aquí es el *comodín*, escrito con el guión bajo `_`, que coincide con cualquier valor que aparezca, sin darle un nombre. + +No hemos explorado el completo poder del pattern matching aún, pero nos detendremos aquí para mantener este documento corto. Todavía nos queda pendiente ver cómo funcionan las dos funciones de arriba en un ejemplo real. Para ese propósito, escribamos una función main simple que realice algunas operaciones sobre la expresión `(x+x)+(7+y)`: primero computa su valor en el entorno `{ x -> 5, y -> 7 }` y después computa su derivada con respecto a `x` y después a `y`. + + def main(args: Array[String]) { + val exp: Arbol = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y"))) + val ent: Entonrno = { case "x" => 5 case "y" => 7 } + println("Expresión: " + exp) + println("Evaluación con x=5, y=7: " + eval(exp, ent)) + println("Derivada con respecto a x:\n " + derivada(exp, "x")) + println("Derivada con respecto a y:\n " + derivada(exp, "y")) + } + +Al ejecutar este programa obtenemos el siguiente resultado: + + Expresión: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y))) + Evaluación con x=5, y=7: 24 + Derivada con respecto a x: + Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0))) + Derivada con respecto a y: + Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1))) + +Al examinar la salida vemos que el resultado de la derivada debería ser simplificado antes de ser presentado al usuario. Definir una función de simplificación básica utilizando reconocimiento de patrones es un problema interesante (y, por no decir complejo, que necesita una solución astuta), lo dejamos para un ejercicio para el lector. + +## Traits + +_Nota: La palabra Trait(/treɪt/, pronunciado Treit) puede ser traducida literalmente como "Rasgo". De todas maneras decido utilizar la notación original por ser un concepto muy arraigado a Scala_ + +Aparte de poder heredar código de una super clase, una clase en Scala puede también importar código de uno o varios *traits*. + +Tal vez la forma más fácil para un programador Java de entender qué son los traits es verlos como interfaces que también pueden contener código. En Scala, cuando una clase hereda de un trait, implementa la interface de ese trait, y hereda todo el código contenido en el trait. + +Para ver la utilidad de los traits, veamos un ejemplo clásico: objetos ordenados. Generalmente es útil tener la posibilidad de comparar objetos de una clase dada entre ellos, por ejemplo, para ordenarlos. En Java, los objetos que son comparables implementan la interfaz `Comparable`. En Scala, podemos hacer algo un poco mejor que en Java al definir un trait equivalente `Comparable` que invocará a `Ord`. + +Cuando comparamos objetos podemos utilizar seis predicados distintos: menor, menor o igual, igual, distinto, mayor o igual y mayor. De todas maneras, definir todos estos es fastidioso, especialmente que cuatro de estos pueden ser expresados en base a los otros dos. Esto es, dados los predicados "igual" y "menor" (por ejemplo), uno puede expresar los otros. En Scala, todas estas observaciones pueden ser fácilmente capturadas mediante la siguiente declaración de un Trait: + + trait Ord { + def < (that: Any): Boolean + def <=(that: Any): Boolean = (this < that) || (this == that) + def > (that: Any): Boolean = !(this <= that) + def >=(that: Any): Boolean = !(this < that) + } + +Esta definición crea un nuevo tipo llamado `Ord` el cual juega el mismo rol que la interfaz `Comparable`, como también provee implementaciones de tres predicados en términos de un cuarto, abstracto. Los predicados para igualidad y su inverso (distinto, no igual) no aparecen aquí ya que por defecto están presenten en todos los objetos. + +El tipo `Any` el cual es usado arriba es el supertipo de todos los otros tipos en Scala. Puede ser visto como una versión más general del tipo `Object` en Java, ya que `Any` también es supertipo de `Int`, `Float`, etc. cosa que no se cumple en Java (`int` por ejemplo es un tipo primitivo). + +Para hacer a un objeto de la clase comparable es suficiente definir los predicados que comprueban la igualdad y la inferioridad y mezclar la clase `Ord` de arriba. Como un ejemplo, definamos una clase `Fecha` que representa fechas en el calendario gregoriano. + + class Fecha(d: Int, m: Int, a: Int) extends Ord { + def anno = a + def mes = m + def dia = d + override def toString(): String = anno + "-" + mes + "-" + dia + +La parte importante aquí es la declaración `extends Ord` la cual sigue al nombre de la clase y los parámetros. Declara que la clase `Fecha` hereda del trait `Ord`. + +Después redefinimos el método `equals`, heredado de `Object`, para comparar correctamente fechas mediante sus campos individuales. La implementación por defecto de `equals` no es utilizable, porque como en Java, compara los objetos físicamente. Por lo tanto llegamos a esto: + + override def equals(that: Any): Boolean = + that.isInstanceOf[Fecha] && { + val o = that.asInstanceOf[Fecha] + o.dia== dia && o.mes == mes && o.anno== anno + } + +Este método utiliza el método predefinido `isInstanceOf` ("es instancia de") y `asInstanceOf` ("como instancia de"). El primero `isInstanceOf` se corresponde con el operador java `instanceOf` y retorna `true` si y solo si el objeto en el cual es aplicado es una instancia del tipo dado. El segundo, `asInstanceOf`, corresponde al operador de casteo en Java: si el objeto es una instancia de un tipo dado, esta es vista como tal, de otra manera se lanza una excepción `ClassCastException`. + +Finalmente el último método para definir es el predicado que comprueba la inferioridad. Este hace uso de otro método predefinido, `error` que lanza una excepción con el mensaje de error provisto. + + def <(that: Any): Boolean = { + if (!that.isInstanceOf[Fecha]) + error("no se puede comparar" + that + " y una fecha") + + val o = that.asInstanceOf[Fecha] + (anno < o.anno) || + (anno== o.anno && (mes < o.mes || + (mes == o.mes && dia < o.dia))) + } + +Esto completa la definición de la clase `Fecha`. Las instancias de esta clase pueden ser vistas tanto como fechas o como objetos comparables. Además, todas ellas definen los seis predicados de comparación mencionados arriba: `equals` y `<` porque aparecen directamente en la definición de la clase `Fecha` y los otros porque son heredados del trait `Ord`. + +Los traits son útiles en muchas otras más situaciones que las aquí mostrada, pero discutir sus aplicaciones está fuera del alcance de este documento. + +## Tipos Genéricos + +_Nota: El diseñador de los tipos genéricos en Java fue nada más ni nada menos que Martin Odersky, el diseñador de Scala._ + +La última característica de Scala que exploraremos en este tutorial es la de los tipos genéricos. Los programadores de Java deben estar bien al tanto de los problemas que genera la falta de genéricos en su lenguaje, lo cual es solucionado en Java 1.5. + +Los tipos genéricos proveen al programador la habilidad de escribir código parametrizado por tipos. Por ejemplo, escribir una librería para listas enlazadas se enfrenta al problema de decidir qué tipo darle a los elementos de la lista. Ya que esta lista está pensada para ser usada en diferentes contextos, no es posible decidir que el tipo de elementos sea, digamos, `Int`. Esto sería completamente arbitrario y muy restrictivo. + +Los programadores Java cuentan como último recurso con `Object`, que es el supertipo de todos los objetos. Esta solución de todas maneras está lejos de ser ideal, ya que no funciona con tipos primitivos (`int`, `long`, `float`, etc.) e implica que el programador tenga que realizar muchos casteos de tipos en su programa. + +Scala hace posible definir clases genéricas (y métodos) para resolver este problema. Examinemos esto con un ejemplo del contenedor más simple posible: una referencia, que puede estar tanto vacía como apuntar a un objeto de algún tipo. + + class Referencia[T] { + private var contenido: T = _ + def set(valor: T) { contenido = valor } + def get: T = contenido + } + +La clase `Referencia` es parametrizada por un tipo llamado `T`, que es el tipo de sus elementos. Este tipo es usado en el cuerpo de la clase como el tipo de la variable `contenido`, el argumento del método `set` y el tipo de retorno del método `get`. + +El ejemplo anterior introduce a las variables en Scala, que no deberían requerir mayor explicación. Es interesante notar que el valor inicial dado a la variable `contenido` es `_`, que representa un valor por defecto. Este valor por defecto es 0 para tipos numéricos, `false` para tipos `Boolean`, `()` para el tipo `Unit` y `null` para el resto de los objetos. + +Para utilizar esta clase `Referencia`, uno necesita especificar qué tipo utilizar por el parámetro `T`, es decir, el tipo del elemento contenido por la referencia. Por ejemplo, para crear y utilizar una referencia que contenga un entero, podríamos escribir lo siguiente: + + object ReferenciaEntero { + def main(args: Array[String]) { + val ref = new Referencia[Int] + ref.set(13) + println("La referncia tiene la mitad de " + (ref.get * 2)) + } + } + +Como puede verse en el ejemplo, no es necesario castear el valor retornado por el método `get` antes de usarlo como un entero. Tampoco es posible almacenar otra cosa que no sea un entero en esa referencia en particular, ya que fue declarada como contenedora de un entero. + +## Conclusión + +Scala es un lenguaje tremendamente poderoso que ha sabido heredar las mejores cosas de cada uno de los lenguajes más exitosos que se han conocido. Java no es la excepción, y comparte muchas cosas con este. La diferencia que vemos es que para cada uno de los conceptos de Java, Scala los aumenta, refina y mejora. Poder aprender todas las características de Scala nos equipa con más y mejores herramientas a la hora de escribir nuestros programas. +Si bien la programación funcional no ha sido una característica de Java, el programador experimentado puede notar la falta de soporte de este paradigma en múltiples ocasiones. El solo pensar en el código necesario para proveer a un `JButton` con el código que debe ejecutar al ser presionado nos muestra lo necesario que sería contar con herramientas funcionales. Recomendamos entonces tratar de ir incorporando estas características, por más que sea difícil para el programador Java al estar tan acostumbrado al paradigma imperativo de este lenguaje. + +Este documento dio una rápida introducción al lenguaje Scala y presento algunos ejemplos básicos. El lector interesado puede seguir, por ejemplo, leyendo el *Tutorial de Scala* que figura en el sitio de documentación, o *Scala by Example* (en inglés). También puede consultar la especificación del lenguaje cuando lo desee. diff --git a/ko/tutorial/index.md b/ko/tutorial/index.md new file mode 100644 index 000000000..372b6e0ca --- /dev/null +++ b/ko/tutorial/index.md @@ -0,0 +1,679 @@ +--- +layout: page +title: 자바 프로그래머를 위한 스칼라 튜토리얼 +overview: scala-for-java-programmers + +disqus: true +language: ko +by: Michel Schinz and Philipp Haller 지음, 이희종 (heejong@gmail.com) 옮김 +--- + +## 시작하면서 + +이 문서는 Scala 언어와 그 컴파일러에 대해 간단히 소개한다. +어느 정도의 프로그래밍 경험이 있으며 Scala를 통해 무엇을 할 수 +있는지를 빠르게 배우고 싶은 사람들을 위해 만들어 졌다. +여기서는 독자가 객체 지향 프로그래밍, 특히 Java에 대한 지식을 +가지고 있다고 가정한다. + +## 첫 번째 예제 + +첫번째 예제로 흔히 쓰이는 *Hello world* 프로그램을 사용하자. +이 프로그램은 그다지 멋지지는 않지만 언어에 대한 많은 지식 없이도 +Scala 언어를 다루는데 필요한 도구들의 사용법을 쉽게 보여 줄 수 있다. +아래를 보자: + + object HelloWorld { + def main(args: Array[String]) { + println("Hello, world!") + } + } + +자바 프로그래머들은 이 프로그램의 구조가 익숙 할 것이다. +프로그램은 문자열 배열 타입의 명령줄 인자를 받는 이름이 `main`인 +함수 하나를 가지고 있다. 이 함수의 구현은 하나의 또 다른 함수 호출로 +이루어져 있는데 미리 정의 된 함수 `println`에 어디선가 많이 본 +바로 그 환영 메시지를 넘겨주어 호출 한다. `main` 함수는 값을 돌려주지 +않기 때문에 리턴 타입을 선언 할 필요가 없다. + +자바 프로그래머들에게 익숙하지 않은 부분은 `main` 함수를 감싸고 +있는 `object` 선언일 것이다. 이 선언은 **싱글턴 객체**를 생성하는데, +이는 하나의 인스턴스만을 가지는 클래스라 할 수 있다. 따라서 위의 선언은 +`HelloWorld`라는 클래스와 역시 `HelloWorld`라고 이름 +붙인 이 클래스의 인스턴스를 함께 정의 하는 것이다. 이 인스턴스는 처음 +사용 될 때에 필요에 따라 만들어 진다. + +똑똑한 독자들은 이미 눈치챘겠지만 위의 예제에서 `main` 함수는 +`static`이 아니다. Scala에는 정적 멤버(함수든 필드든)라는 개념이 +아얘 존재하지 않는다. 클래스의 일부로 정적 멤버를 정의하는 대신에 Scala +프로그래머들은 정적이기 원하는 멤버들을 싱글턴 객체안에 선언한다. + +### 예제를 컴파일 하기 + +예제를 컴파일 하기 위하여 Scala 컴파일러인 `scalac`를 사용한다. +`scalac`는 대부분의 컴파일러들과 비슷하게 동작한다. 소스파일과 필요에 +따라 몇개의 옵션들을 인자로 받아 한개 또는 여러개의 오브젝트 파일을 +생성한다. `scalac`가 생성하는 오브젝트 파일은 표준적인 Java 클래스 +파일이다. + +위의 예제 프로그램을 `HelloWorld.scala`라는 이름으로 저장했다면, +아래의 명령으로 컴파일 할 수 있다 (부등호 `>`는 쉘 프롬프트이므로 +함께 입력하지 말것) : + + > scalac HelloWorld.scala + +이제 현재 디렉토리에 몇개의 클래스 파일이 생성되는 것을 확인 할 수 있다. +그 중에 하나는 `HelloWorld.class`이며 `scala` 명령을 통해 바로 실행 +가능한 클래스를 포함하고 있다. 다음 장을 보자. + +### 예제를 실행하기 + +일단 컴파일 되면 Scala 프로그램은 `scala` 명령을 통해 실행 할 수 있다. +사용법은 Java 프로그램을 실행 할 때 사용하는 `java` 명령과 매우 비슷하며 +동일한 옵션을 사용 가능하다. 위의 예제는 아래의 명령으로 실행 할 수 있으며 +예상한대로의 결과가 나온다. + + > scala -classpath . HelloWorld + + Hello, world! + +## 자바와 함께 사용하기 + +Scala의 장점 중 하나는 Java 코드와 함께 사용하기 쉽다는 것이다. +사용하고 싶은 Java 클래스를 간단히 임포트 하면 되며, `java.lang` +패키지의 모든 클래스는 임포트 하지 않아도 기본적으로 사용 할 수 있다. + +아래는 Scala가 Java와 얼마나 잘 어울리는지를 보여주는 예제이다. +우리는 아래 예제에서 현재의 날짜를 구하여 특정 국가에서 사용하는 형식으로 +변환 할 것이다. 이를테면 프랑스(불어를 사용하는 스위스의 일부 지역도 +동일한 형식을 사용한다)라 하자. + +Java의 클래스 라이브러리는 `Date`와 `DateFormat`과 같은 +강력한 유틸리티 클래스를 가지고 있다. Scala는 Java와 자연스럽게 +서로를 호출 할 수 있으므로, 동일한 역할을 하는 Scala 클래스 라이브러리를 +구현하기 보다는 우리가 원하는 기능을 가진 Java 패키지를 간단히 임포트하여 +이용하자. + + import java.util.{Date, Locale} + import java.text.DateFormat + import java.text.DateFormat._ + + object FrenchDate { + def main(args: Array[String]) { + val now = new Date + val df = getDateInstance(LONG, Locale.FRANCE) + println(df format now) + } + } + +Scala의 임포트 구문은 Java의 그것과 매우 비슷해 보이지만 사실 좀 더 +강력하다. 위 예제의 첫번째 줄과 같이 중괄호를 사용하면 같은 패키지에서 +여러개의 클래스를 선택적으로 불러 올 수 있다. Scala 임포트 구문의 +또 한가지 특징은 패키지나 클래스에 속한 모든 이름들을 불러 올 경우 +별표(`*`) 대신 밑줄(`_`) 을 사용 한다는 것이다. 별표는 Scala에서 +합법적인 식별자(함수명 등에 사용 가능한)로 사용된다. 나중에 자세히 살펴 +볼 것이다. + +따라서 세번째 줄의 임포트 구문은 `DateFormat` 클래스의 모든 멤버를 +불러온다. 이렇게 함으로써 정적 함수 `getDateInstance`와 정적 필드 +`LONG`이 바로 사용 가능하게 된다. + +`main` 함수 안에서 처음 하는 일은 Java 라이브러리에 속한 +`Date` 클래스의 인스턴스를 생성하는 것이다. 이 인스턴스는 기본적으로 +현재의 날짜를 가지고 있다. 다음으로 이전에 불러온 정적 함수 +`getDateInstance`를 통해 날짜 형식을 결정하고, 프랑스에 맞춰진 +`DateFormat` 인스턴스를 사용하여 현재의 날짜를 출력한다. 이 +마지막 줄은 Scala 문법의 재미있는 특성을 보여준다. 오직 하나의 인자를 +갖는 함수는 마치 이항연산자 같은 문법으로 호출 가능하다. 이 이야기는 곧 +아래의 표현식이: + + df format now + +아래 표현식과 동일한 의미를 가진 다는 것이다. 그저 좀 더 간단하게 표현 +되었을 뿐이다. + + df.format(now) + +이러한 특성은 그저 별것 아닌 문법의 일부 인것 처럼 보이지만 여러 곳에서 +중요하게 사용 된다. 그중에 하나가 다음 장에 나와있다. + +이번 장에서는 Java와 Scala가 얼마나 자연스럽게 서로 녹아드는지에 대해 +배웠다. 이번 장에는 나타나지 않았지만, Scala 안에서 Java의 클래스들을 +상속받고 Java의 인터페이스들을 바로 구현하는 것도 가능하다. + +## 모든 것은 객체다 + +Scala는 순수한 객체지향적 언어이다. 이 말은 곧 숫자와 함수를 포함한 +**모든것**이 객체라는 것이다. 이러한 면에서 Scala는 Java와 다르다. +Java에서는 기본적인 타입(`boolean`이나 `int` 따위)과 참조 가능한 +타입이 분리되어 있으며, 함수를 값과 동일하게 다룰 수도 없다. + +### 숫자도 하나의 객체다 + +숫자는 객체이기 때문에 함수들을 포함하고 있다. 사실 아래와 같은 +표현식은: + + 1 + 2 * 3 / x + +오직 함수 호출로만 이루어져 있다. 우리가 이전 장에서 보았듯이, 위의 +표현식은 아래의 표현식과 동일하다. + + (1).+(((2).*(3))./(x)) + +위의 표현식처럼 `+`, `*` 등은 Scala에서 합법적인 식별자이다. + +위의 두번째 표현식에서 괄호는 꼭 필요하다. 왜냐하면 스칼라의 렉서(lexer)는 +토큰들에 대하여 가장 긴 부분을 찾는 방법을 사용하기 때문이다. 아래의 +표현식은: + + 1.+(2) + +세개(`1.`, `+`, `2`)의 토큰들로 분리된다. 이렇게 토큰들이 +분리되는 이유는 미리 정의되어 있는 유효한 토큰 중에 `1.`이 +`1`보다 길기 때문이다. 토큰 `1.`은 리터럴 `1.0`으로 +해석 되어 `Double` 타입이 된다. 실제로 우리는 `Int` 타입을 +의도 했음에도 말이다. 표현식을 아래와 같이 쓰면: + + (1).+(2) + +토큰 `1`이 `Double`로 해석 되는 것을 방지 할 수 있다. + +### 함수마저 객체다 + +Java 프로그래머들에게는 놀라운 일이겠지만 Scala에서는 함수도 +역시 객체이다. 따라서 함수에 함수를 인자로 넘기거나, 함수를 변수에 +저장하거나, 함수가 함수를 리턴하는 것도 가능하다. 이처럼 함수를 값과 +동일하게 다루는 것은 매우 흥미로운 프로그래밍 패러다임인 +**함수형 프로그래밍**의 핵심 요소 중 하나이다. + +함수를 값과 같이 다루는 것이 유용함을 보이기 위해 아주 간단한 예제를 +든다. 어떠한 행동을 매초 수행하는 타이머 함수를 생각해 보자. 수행 할 +행동을 어떻게 넘겨 주어야 할까? 논리적으로 생각한다면 함수를 넘겨 주어야 +한다. 함수를 전달하는 이런 종류의 상황은 많은 프로그래머들에게 익숙 할 +것이다. 바로 유저 인터페이스 코드에서 어떤 이벤트가 발생하였을 때 불릴 +콜백 함수를 등록하는 것 말이다. + +아래 프로그램에서 타이머 함수의 이름은 `oncePerSecond`이다. 이 함수는 +콜백 함수를 인자로 받는다. 인자로 받는 함수의 타입은 `() => Unit` 인데, +이 타입은 인자를 받지 않고 아무 것도 돌려주지 않는 모든 함수를 뜻한다 +(`Unit` 타입은 C/C++에서 `void`와 비슷하다). 이 프로그램의 메인 함수는 +이 타이머 함수를 화면에 문장을 출력하는 간단한 콜백함수를 인자로 호출한다. +결국 이 프로그램이 하는 일은 일초에 한번씩 "time flies like an arrow"를 +화면에 출력하는 것이 된다. + + object Timer { + def oncePerSecond(callback: () => Unit) { + while (true) { callback(); Thread sleep 1000 } + } + def timeFlies() { + println("time flies like an arrow...") + } + def main(args: Array[String]) { + oncePerSecond(timeFlies) + } + } + +우리는 문자열을 화면에 출력하기 위하여 Scala에 정의된 `println`을 사용 +하였다. 이 함수는 Java에서 흔히 사용하는 `System.out`에 정의된 것과 +다르다. + +#### 이름없는 함수 + +이 프로그램은 이해하기 쉽지만 조금 더 다듬을 수도 있다. +함수 `timeFlies`는 오직 함수 `oncePerSecond`에 인자로 +넘겨지기 위해 정의 되었다는 것에 주목하자. 이러한 한번만 사용되는 +함수에 이름을 붙여 준다는 것은 필요 없는 일일 수 있다. 더 행복한 +방법은 `oncePerSecond`에 함수가 전달 되는 그 순간 이 함수를 +생성하는 것이다. Scala에서 제공하는 **무명함수**를 사용하면 +된다. 무명함수란 말 그대로 이름이 없는 함수이다. 함수 `timeFlies` +대신에 무명함수를 사용한 새로운 버전의 타이머 프로그램은 아래와 같다: + + object TimerAnonymous { + def oncePerSecond(callback: () => Unit) { + while (true) { callback(); Thread sleep 1000 } + } + def main(args: Array[String]) { + oncePerSecond(() => + println("time flies like an arrow...")) + } + } + +`main` 함수 안에 오른쪽 화살표 `=>`가 있는 곳이 무명함수이다. +오른쪽 화살표는 함수의 인자와 함수의 내용을 분리 해주는 역할을 한다. 위 +예제에서 인자의 리스트는 비어있다. 화살표의 왼쪽을 보면 빈 괄호를 볼 수 +있다. 함수의 내용은 `timeFlies`와 일치한다. + +## 클래스에 대하여 + +지금까지 보았듯 Scala는 객체지향적 언어이며 클래스의 개념이 존재한다. +(어떤 객체지향 언어는 클래스의 개념이 존재하지 않는다. 당연하게도 +Scala는 이들에 속하지 않는다.) +Scala의 클래스 정의는 Java의 클래스 정의와 유사하다. 한가지 중요한 차이점은 +Scala 클래스의 경우 파라미터들을 가질 수 있다는 것인데 아래 복소수 예제에 +잘 나타나 있다: + + class Complex(real: Double, imaginary: Double) { + def re() = real + def im() = imaginary + } + +이 복소수 클래스는 두개의 인자를 받는다. 하나는 복소수의 실수 부분이고 +다른 하나는 복소수의 허수 부분에 해당하는 값이 된다. 이 인자들은 +`Complex` 클래스의 인스턴스를 생성 할 때 이처럼 반드시 전달 되어야 +한다: `new Complex(1.5, 2.3)`. 클래스는 `re`와 `im`라는 +두 함수를 가지고 있는데 각각의 함수를 통해 복소수를 구성하는 해당 부분의 +값을 얻을 수 있다. + +이 두 함수의 리턴타입은 명시적으로 나타나 있지 않다는 사실에 주목하자. +컴파일러는 이 함수들의 오른편을 보고 둘 다 `Double` 타입을 리턴 +한다고 자동으로 유추해 낸다. + +하지만 컴파일러가 언제나 이렇게 타입을 유추해 낼 수 있는 것은 아니다. +그리고 불행하게도 어떤 경우 이러한 타입 유추가 가능하고 어떤 경우 불가능 +한지에 관한 명확한 규칙도 존재하지 않는다. 일반적으로 이러한 상황은 +별 문제가 되지 않는다. 왜냐하면 명시적으로 주어지지 않은 타입정보를 +컴파일러가 자동으로 유추 해 낼 수 없는 경우 컴파일 시 에러가 발생하기 +때문이다. 초보 Scala 프로그래머들을 위한 한가지 방법은, 주변을 보고 쉽게 +타입을 유추 해 낼 수 있는 경우 일단 타입 선언을 생략하고 컴파일러가 받아 +들이는지 확인하는 것이다. 이렇게 몇번을 반복하고 나면 프로그래머는 언제 +타입을 생략해도 되고 언제 명시적으로 써주어야 하는지 감을 잡게 된다. + +### 인자 없는 함수 + +함수 `re`와 `im`의 사소한 문제는 그들을 호출하기 위해 항상 +뒤에 빈 괄호를 붙여 주어야 한다는 것이다. 아래를 보자: + + object ComplexNumbers { + def main(args: Array[String]) { + val c = new Complex(1.2, 3.4) + println("imaginary part: " + c.im()) + } + } + +실수 부분과 허수 부분에 접근 할 때에 마치 그들이 필드인 것 처럼 함수 +마지막에 빈 괄호를 붙이지 않을 수 있다면 더욱 좋겠다. 놀라지 마시라, +Scala는 이러한 기능을 완벽하게 제공한다. 그저 **인자를 제외**하고 +함수를 정의하면 된다. 이런 종류의 함수는 인자가 0개인 함수와는 다른데, +인자가 0개인 함수는 빈 괄호가 따라 붙는 반면 이 함수는 정의 할 때도 +사용 할 때도 이름 뒤에 괄호를 붙이지 않는다. 우리가 앞서 정의한 +`Complex` 클래스는 아래와 같이 다시 쓸 수 있다: + + class Complex(real: Double, imaginary: Double) { + def re = real + def im = imaginary + } + + +### 상속과 재정의 + +모든 Scala의 클래스들은 항상 상위 클래스로부터 상속된다. 만약 +`Complex` 예제 처럼 상위 클래스가 존재하지 않을 경우는 +묵시적으로 `scala.AnyRef`를 상속한다. + +Scala에서는 물론 상위 클래스에 정의된 함수를 오버라이드 하는 것도 +가능하다. 그러나 의도하지 않는 실수를 방지하기 위하여 다른 함수를 +오버라이드 하는 함수는 `override` 지시자를 꼭 적어주어야 한다. +예를 들면, 우리의 `Complex` 클래스에 대해 `Object`로 부터 +상속된 `toString` 함수를 재정의 하는 법은 아래와 같다: + + class Complex(real: Double, imaginary: Double) { + def re = real + def im = imaginary + override def toString() = + "" + re + (if (im < 0) "" else "+") + im + "i" + } + + +## 케이스 클래스 그리고 패턴 매칭 + +프로그램에 자주 등장하는 데이터 구조 중의 하나는 트리이다. +인터프리터와 컴파일러는 흔히 트리를 사용하여 내부 표현을 저장하고, +XML 문서도 트리이며, 레드블랙 트리와 같은 저장구조 들도 트리에 +기반을 두고 있다. + +작은 계산기 프로그램을 통해 Scala에서 이러한 트리들을 어떻게 +표현하고 다루는지에 대해 알아 보자. 이 프로그램의 목표는 더하기와 +상수인 정수 그리고 변수로 이루어진 간단한 산술 표현식을 다루는 것이다. +예를 들면, `1+2`나 `(x+x)+(7+y)` 같은 식들 말이다. + +처음으로, 우리는 해당 산술 표현식들을 어떻게 표현 할지 결정해야 한다. +가장 자연스러운 방법은 트리를 사용하는 것이다. 노드는 연산(여기서는 +덧셈)이 될 것이고, 리프는 값(여기서는 상수 또는 변수)가 되겠다. + +Java였다면 트리를 나타내기 위해, 트리에 대한 추상 상위 클래스와 +노드와 리프 각각에 대한 실제 하위 클래스들을 정의 했을 것이다. +함수형 언어였다면 같은 목적으로 대수적 데이터 타입을 사용 했을 것이다. +Scala는 **케이스 클래스**라 하는 이 둘 사이의 어디쯤에 놓여 질 수 +있는 장치를 제공한다. 우리 예제의 트리 타입을 정의하기 위해 이 장치가 +어떻게 사용 되는지 아래에서 실제적인 예를 보자: + + abstract class Tree + case class Sum(l: Tree, r: Tree) extends Tree + case class Var(n: String) extends Tree + case class Const(v: Int) extends Tree + +클래스 `Sum`, `Var` 그리고 `Const`가 케이스 클래스로 +선언되었다는 것은 이들이 여러가지 면에서 일반적인 클래스와 다르다는 +의미이다: + +- 인스턴스를 생성 할 때 `new` 키워드를 생략 할 수 있다. + 다른 말로, `new Const(5)`라 쓰는 대신 `Const(5)`라 쓰면 된다. +- 생성자 파라미터들에 대한 getter 함수가 자동으로 정의된다. 다른 말로, + 클래스 `Const`의 인스턴스 `c`에 있는 생성자 파라미터 `v`의 + 값은 `c.v`로 접근 가능하다. +- 함수 `equals`와 `hashCode`도 공짜로 제공된다. 이 함수들은 + 레퍼런스의 동일함 보다 **구조**의 동일함을 확인 하도록 구현되어 있다. + 다른 말로, 생성 된 곳이 다르더라도 각각의 생성자 파라미터 값이 같다면 + 같은 것으로 여긴다. +- 함수 `toString`에 대한 기본적 구현이 제공된다. 이 기본적인 + 구현은 "값이 생성 될 때"의 형태를 출력한다. 예를 들어 `x+1`의 트리 표현 + 을 출력 한다면 `Sum(Var(x),Const(1))`이 된다. +- 케이스 클래스들의 인스턴스는 **패턴 매칭**을 통해 따로 사용 될 + 수 있다. 자세한 내용은 아래에서 다룬다. + +산술 표현식을 나타낼 수 있는 데이터 타입을 정의 했으므로 이제 그것들을 +계산 할 연산자들을 정의 할 차례다. 일단, 어떤 **환경**안에서 표현식을 +계산 해주는 함수부터 시작하자. 환경은 각각의 변수마다 주어진 값들을 저장 +해 두는 곳이다. 컴퓨터에서 메모리의 역할과 비슷 하다고 생각하면 된다. +예를 들어, 변수 `x`에 `5`가 저장된 환경(`{ x -> 5 }`)에서 표현식 +`x+1`을 계산하면 결과로 `6`이 나온다. + +환경은 어떻게 표현하는게 좋을까? 간단히 생각하면, 해쉬 테이블 같은 +두 값을 묶어주는 데이터 구조를 사용 할 수 있겠다. 그러나 우리는 이러한 +데이터를 저장하는 목적으로 함수를 직접 사용 할 수도 있다! 가만 생각해 +보면 환경이라는 것은 변수명에서 값으로 가는 함수에 지나지 않는다. +위에서 사용한 환경 `{ x -> 5 }` 은 Scala로 간단히 아래와 같이 +쓴다: + + { case "x" => 5 } + +이 문법은 함수를 정의한다. 이 함수는 문자열 `"x"`가 인자로 들어 +왔을 때 정수 `5`를 돌려주고, 다른 모든 경우에 예외를 발생시키는 함수이다. + +계산하는 함수를 작성하기 전에 환경 타입에 이름을 붙여 주는 것이 좋겠다. +물론 항상 환경 타입으로 `String => Int`를 사용해도 되지만 보기 좋은 +이름을 붙이는 것은 프로그램을 더 읽기에 명료하고 변경에 유연하게 해 준다. +Scala에서는 아래와 같이 할 수 있다: + + type Environment = String => Int + +이제부터 타입 `Environment`는 `String`에서 `Int`로 가는 +함수 타입의 다른 이름이다. + +지금부터 계산하는 함수를 정의하자. 개념으로 따지면 매우 간단하다: +두 표현식의 합은 각 표현식의 값을 구하여 더한 것이다. 변수의 값은 +환경에서 바로 가져 올 수 있고, 상수의 값은 상수 자체이다. 이것을 +Scala로 나타내는 것은 어렵지 않다: + + def eval(t: Tree, env: Environment): Int = t match { + case Sum(l, r) => eval(l, env) + eval(r, env) + case Var(n) => env(n) + case Const(v) => v + } + +이 계산 함수는 트리 `t`에 대해 **패턴 매칭**을 수행함으로써 +동작한다. 위의 함수 정의는 직관적으로도 이해하기 쉽다: + +1. 처음으로 `t`가 `Sum`인지 확인한다. 만약 맞다면 왼쪽 + 서브트리를 새로운 변수 `l`에 오른쪽 서브트리를 새로운 변수 + `r`에 할당 한다. 그리고 화살표를 따라 화살표의 오른편으로 계산을 + 이어 나간다. 화살표의 오른편에서는 화살표의 왼편에서 할당된 변수 + `l`과 `r`을 사용 한다. +2. 첫번째 확인이 성공하지 못하면 트리는 `Sum`이 아니라는 + 이야기이다. 다음으로는 `t`가 `Var`인지 확인한다. 만약 + 맞다면 `Var` 노드 안에 포함된 이름을 변수 `n`에 할당한다. + 그리고 화살표의 오른쪽으로 진행한다. +3. 두번째 확인 역시 실패하면 `t`는 `Sum`도 `Var`도 + 아니라는 뜻이다. 이제는 `Const`에 대해 확인 해본다. 만약 + 맞다면 `Const` 노드 안의 값을 변수 `v`에 할당하고 화살표의 + 오른쪽으로 진행한다. +4. 마지막으로 모든 확인이 실패하면 패턴 매칭이 실패 했음을 알리는 + 예외가 발생하게 된다. 이러한 상황은 확인 한 것 외에 `Tree`의 + 하위 클래스가 더 존재 할 경우 일어난다. + +패턴 매칭의 기본적인 아이디어는 대상이 되는 값을 여러가지 관심있는 +패턴에 대해 순서대로 맞춰 본 후, 맞는 것이 있으면 맞은 값 중 관심 있는 +부분에 대해 새롭게 이름 붙이고, 그 이름 붙인 부분을 사용하는 어떠한 +작업을 진행하는 것이다. + +객체지향에 숙련된 프로그래머라면 왜 `eval`을 클래스 `Tree`와 +그 하위 클래스에 대한 **멤버 함수**로 정의하지 않았는지 궁금 할 것이다. +사실 그렇게 할 수도 있었다. Scala는 일반적인 클래스 처럼 케이스 클래스에 +대해서도 함수 정의를 허용한다. 패턴 매칭을 사용하느냐 멤버 함수를 +사용하느냐는 사용자의 취향에 달린 문제다. 하지만 확장성에 관해 시사하는 +중요한 점이 있다: + +- 멤버 함수를 사용하면 단지 `Tree`에 대한 하위 클래스를 새롭게 + 정의 함으로 새로운 노드를 추가하기 쉽다. 반면에 트리에 대한 새로운 + 연산을 추가하는 작업이 고되다. 새로운 연산을 추가하기 위해서는 + `Tree`의 모든 하위 클래스를 변경해야 하기 때문이다. +- 패턴 매칭을 사용하면 상황이 반대가 된다. 새로운 노드를 추가하려면 + 트리에 대해 패턴 매칭을 수행하는 모든 함수들을 새로운 노드도 고려하도록 + 변경해야 한다. 반면에 새로운 연산을 추가하는 것은 쉽다. 그냥 새로운 + 독립적인 함수를 만들면 된다. + +패턴 매칭에 대해 좀 더 알아보기 위해, 산술 표현식에 대한 또 다른 연산을 +정의 해보자. 이번 연산은 심볼 추출이다. 트리에서 우리가 원하는 특정 변수만 +1로 표시하는 일이다. 독자는 아래 규칙만 기억하면 된다: + +1. 더하기 표현식에서의 심볼 추출은 좌변과 우변의 심볼을 추출하여 더한 + 것과 같다. +2. 변수 `v`에 대한 심볼 추출은 `v`가 우리가 추출하기 원하는 심볼과 + 관련이 있다면 1이 되고 그 외의 경우 0이 된다. +3. 상수에 대한 심볼 추출 값은 0이다. + +이 규칙들은 거의 그대로 Scala 코드가 된다. + + def derive(t: Tree, v: String): Tree = t match { + case Sum(l, r) => Sum(derive(l, v), derive(r, v)) + case Var(n) if (v == n) => Const(1) + case _ => Const(0) + } + +위의 함수는 패턴 매칭에 관한 두 가지 새로운 기능을 소개한다. +첫 번째로, `case` 표현은 **가드**를 가질 수 있다. 가드란 +`if` 키워드 뒤에 오는 표현식을 뜻하는 말로 패턴 매칭에 추가적인 +조건을 부여한다. 가드가 참이 되지 않으면 패턴 매칭은 성공하지 못한다. +여기서는, 매칭 된 변수의 이름이 우리가 추출하는 심볼 `v`와 같을 +때만 상수 1을 리턴함을 보장하는 용도로 사용된다. 두 번째 새로운 기능은 +**와일드카드**이다. 밑줄 문자 `_`로 쓰며, 모든 값과 매치 되고 +따로 이름을 붙이지 않는다. + +매턴 매칭의 뛰어난 기능들을 모두 살펴보지는 못했지만, 문서를 너무 +지루하게 만들지 않기 위하여 이쯤에서 멈추기로 한다. 이제 위에서 정의한 +두 개의 예제 함수가 실제로 동작하는 모습을 보자. 산술 표현식 +`(x+x)+(7+y)`에 대해 몇가지의 연산을 실행하는 간단한 `main` 함수를 +만들기로 한다. 첫번째로 환경 `{ x -> 5, y -> 7 }`에서 +그 값을 계산 할 것이고, 다음으로 `x`와 `y`에 대한 심볼 추출을 수행 할 +것이다. + + def main(args: Array[String]) { + val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y"))) + val env: Environment = { case "x" => 5 case "y" => 7 } + println("Expression: " + exp) + println("Evaluation with x=5, y=7: " + eval(exp, env)) + println("Derivative relative to x:\n " + derive(exp, "x")) + println("Derivative relative to y:\n " + derive(exp, "y")) + } + +이 프로그램을 실행하면, 예상된 결과를 얻을 수 있다: + + Expression: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y))) + Evaluation with x=5, y=7: 24 + Derivative relative to x: + Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0))) + Derivative relative to y: + Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1))) + +출력을 살펴 보면 심볼 추출의 결과가 사용자에게 좀 복잡하다는 +생각이 든다. 패턴 매칭을 사용하여 이 결과를 단순화 하는 함수를 +정의하는 것은 재미있는 문제이다(생각보다 복잡하기도 하다). +독자들에게 연습문제로 남겨두겠다. + +## 트레잇에 대하여 + +Scala 클래스에서는 상위 클래스에서 코드를 상속 받는 것 뿐만이 아니라, +하나 또는 여러개의 **트레잇(trait)**에서 코드를 불러 올 수 있는 방법도 +있다. + +Java 프로그래머들이 트레잇을 이해하는 가장 쉬운 길은 코드를 가질 수 있는 +인터페이스라고 생각하는 것이다. Scala에서 어떤 클래스가 트레잇을 상속하면, +그 클래스는 트레잇의 인터페이스를 구현해야만 하고 동시에 트레잇이 가진 모든 +코드들을 가져오게 된다. + +트레잇의 유용함을 보이기 위해 객체들에 순서를 붙이는 고전적인 예제 하나를 +들어보기로 하자. 순서가 있는 객체들은 정렬문제 처럼 주로 그들 사이에 비교가 +필요 할 경우 유용하다. Java에서는 비교가능한 객체들이 `Comparable` +인터페이스를 구현하게 된다. Scala에서는 이 `Comparable`을 트레잇으로 +정의하여 더 나은 프로그램 디자인을 제공 할 수 있다. 여기서는 이를 +`Ord`라 부를 것이다. + +객체를 비교 할 때, 여섯개의 서로 다른 관계가 주로 사용 된다: 작다, +작거나 같다, 같다, 같지 않다, 크거나 같다, 크다. 하지만 이 여섯개를 +일일히 구현하는 것은 지루하고 의미 없는 일이 될 것이다. 게다가 이중 두 +가지 관계만 정의 되어도 나머지 네가지 관계를 계산 할 수 있지 않은가. +예를 들어 같다와 작다만 결정 할 수 있어도 나머지 관계의 참 거짓을 쉽게 +판단 할 수 있다. Scala에서는 이러한 논리들을 트레잇의 정의 안에 +우아하게 표현 해 낼 수 있다: + + trait Ord { + def < (that: Any): Boolean + def <=(that: Any): Boolean = (this < that) || (this == that) + def > (that: Any): Boolean = !(this <= that) + def >=(that: Any): Boolean = !(this < that) + } + +위의 정의는 Java의 `Comparable` 인터페이스와 같은 역할을 하는 +`Ord`라고 불리는 새로운 타입을 만든다. 이 새로운 타입에는 +세가지의 관계식이 기본적으로 구현이 되어 있으며 이 구현은 모두 하나의 +추상 함수를 사용하고 있다. 모든 객체에 대해 기본적으로 존재하는 같다와 +같지 않다에 대한 관계식은 빠져 있다. + +위에서 사용된 타입 `Any`는 Scala의 최상위 타입이다. Java의 +`Object` 타입과 같으나, `Int`, `Float`과 같은 기본 타입의 +상위 타입이라는 점에서 좀 더 일반화 된 버전이라 생각 할 수 있다. + +객체를 비교 가능하게 만들기 위해 정의해야 할 것은 같다와 작다 뿐이다. +나머지는 위의 `Ord` 트레잇을 삽입하여 처리한다. 하나의 예로 +그레고리력의 날짜를 나타내는 `Date` 클래스를 만들어 보자. +이 날짜는 정수인 날, 월, 년으로 구성 된다. 일단 아래처럼 만든다: + + class Date(y: Int, m: Int, d: Int) extends Ord { + def year = y + def month = m + def day = d + override def toString(): String = year + "-" + month + "-" + day + +여기서 중요한 부분은 클래스 이름과 파라미터 뒤에 따라오는 +`extends Ord` 선언이다. 이 선언은 `Date` 클래스가 `Ord` +트레잇을 상속함을 뜻한다. + +다음으로 `Object`에서 상속된 `equals` 함수를 재정의 하여 +각각의 일, 월, 년을 비교하여 같음을 올바르게 판단하도록 한다. +`equals`의 기본 정의는 쓸모가 없다. 왜냐하면 Java와 같이 +기본적인 `equals`는 물리적 주소를 비교하기 때문이다. 최종적인 +코드는 다음과 같다: + + override def equals(that: Any): Boolean = + that.isInstanceOf[Date] && { + val o = that.asInstanceOf[Date] + o.day == day && o.month == month && o.year == year + } + +이 함수는 미리 정의된 함수인 `isInstanceOf`와 `asInstanceOf`를 +사용한다. 첫번째 `isInstanceOf`는 Java의 `instanceof` 연산자와 +동일한 일을 한다. 함수가 호출 된 객체가 함수의 인자로 들어온 타입의 +인스턴스이면 참을 리턴한다. 두번째 `asInstanceOf`는 Java의 캐스트 +연산자와 동일하다. 호출 된 객체가 인자로 들어온 타입의 인스턴스이면 그렇게 +여겨지도록 변환하고 아니라면 `ClassCastException`을 발생시킨다. + +아래 마지막으로 정의된 함수는 작음을 판단하는 함수이다. 여기서는 +`error`라는 또 다른 미리 정의된 함수가 쓰였는데, 이 함수는 +주어진 에러 메시지와 함께 예외를 발생 시키는 역할을 한다. + + def <(that: Any): Boolean = { + if (!that.isInstanceOf[Date]) + error("cannot compare " + that + " and a Date") + + val o = that.asInstanceOf[Date] + (year < o.year) || + (year == o.year && (month < o.month || + (month == o.month && day < o.day))) + } + +이걸로 `Date` 클래스의 정의가 완성되었다. 이 클래스의 인스턴스는 +날짜로도 또는 비교가능한 어떤 객체로도 여겨질 수 있다. 이들은 위에서 +언급한 여섯가지 비교연산을 모두 가지고 있는데, `equals`와 `<`는 +`Date` 클래스의 정의 안에 직접 구현되어 있고 나머지는 `Ord` +트레잇에서 상속 받은 것이다. + +트레잇은 여기서 예로 든 경우 외에도 물론 다양하게 사용 될 수 있다. +하지만 다양한 경우들에 대하여 깊게 다루는 일은 이 문서의 범위 밖이다. + +## 제네릭함 + +이 튜토리얼에서 다룰 Scala의 마지막 특징은 제네릭함이다. Java +프로그래머들은 Java의 제네릭 지원이 부족하기 때문에 발생한 여러가지 +문제점들에 대해 잘 알고 있을 것이다. 이 문제점들은 Java 1.5에서 +다뤄졌다. + +제네릭함이란 코드를 타입에 대하여 파라미터화 할 수 있는 능력이다. +이해를 돕기 위해 하나의 예를 들어 보자. 연결 리스트 라이브러리를 작성하는 +프로그래머는 리스트의 원소 타입을 도대체 무엇으로 해야 할지 고민에 +빠지게 된다. 이 연결 리스트는 서로 다른 많은 상황에서 사용 될 수 있기 +때문에 원소의 타입이 반드시 `Int` 또는 반드시 `Double`이 될 +것이라 미리 결정하는 것은 불가능하다. 이렇게 결정해 두는 일은 완전히 +임의적이며 라이브러리의 사용에 있어 필요 이상의 심한 제약으로 작용 +한다. + +Java 프로그래머는 어쩔 수 없이 `Object`를 사용하곤 한다. +`Object`는 모든 객체의 상위 타입이기 때문이다. 하지만 이런 방법은 +이상적이지 않다. `int`, `long`, `float`등과 같은 +기본 타입에 대해 동작하지 않으며, 연결 리스트에서 원소를 가져 올 때마다 +많은 동적 타입 캐스트들을 프로그래머가 직접 삽입해 주어야 하기 때문이다. + +Scala는 이 문제를 해결하기 위한 제네릭 클래스와 제네릭 함수를 지원한다. +예제로 함께 살펴보자. 예제는 레퍼런스라는 간단한 저장구조 클래스이다. +이 클래스는 비어있거나 또는 어떤 타입의 객체를 가리키는 포인터가 된다. + + class Reference[T] { + private var contents: T = _ + def set(value: T) { contents = value } + def get: T = contents + } + +클래스 `Reference`는 타입 `T`에 대해 파라미터화 되어있다. +타입 `T`는 레퍼런스의 원소 타입이다. 이 타입은 클래스 내부 +여러 곳에서 나타나는데, `contents` 변수의 타입으로, `set` +함수의 인자 타입으로, 그리고 `get` 함수의 리턴 타입으로 사용 된다. + +위의 코드 샘플은 Scala에서 필드 변수를 만드는 내용이므로 따로 설명이 +필요 없다. 한가지 흥미로운 점이 있다면 변수의 초기값이 `_`로 주어져 +있다는 것인데, 여기서 `_`는 기본값을 뜻한다. 기본값은 수 타입에 +대해서 0, `Boolean` 타입에 대해서 `false`, `Unit` +타입에 대해 `()`, 그리고 모든 객체 타입에 대해 `null`이다. + +`Reference` 클래스를 사용하려면 타입 파라미터 `T`에 대해 적당한 +타입을 지정해 주어야 한다. 이 타입은 레퍼런스 안에 들어갈 원소의 +타입이 된다. 예를 들어, 정수 값을 저장 할 수 있는 레퍼런스를 생성하고 +사용하기 위해서는 다음과 같이 쓴다: + + object IntegerReference { + def main(args: Array[String]) { + val cell = new Reference[Int] + cell.set(13) + println("Reference contains the half of " + (cell.get * 2)) + } + } + +위 예제에서 보듯 `get` 함수의 리턴값을 정수처럼 사용하기 위해 +따로 캐스팅이 필요하지 않다. 여기서 정의된 레퍼런스는 정수를 포함하도록 +선언이 되어 있으므로 정수 외에 다른 것은 넣을 수 없다. + +## 마치며 + +우리는 지금까지 Scala 언어의 간략한 소개와 몇가지의 예제를 살펴 +보았다. 흥미가 생겼다면 *Scala By Example*도 함께 읽어보자. 더 수준 +높고 다양한 예제를 만날 수 있다. 필요 할 때마다 *Scala Langauge +Specification*을 참고하는 것도 좋다. + diff --git a/resources/css/glossary.css b/resources/css/glossary.css new file mode 100644 index 000000000..700432551 --- /dev/null +++ b/resources/css/glossary.css @@ -0,0 +1,53 @@ +.sidebar-inner-noscroll { + width: 320px; + padding: 30px; + padding-top: 18px; +} + +#glossary > ul { + margin: 0; +} + +#glossary > ul > li { + list-style: none none; +} + +.filterbar { + line-height:1.3; + position: relative; + padding: 8px 9px 5px; + margin-bottom: 20px; + color: #FFFFFF; + background-color: #859900; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + border-color: #bcbcbc #bcbcbc #808080; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + text-shadow: 1px 1px 0px rgba(0, 43, 54, 0.15); + border-width: 1px; + border-style: solid; + border-radius: 4px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25); +} + +.filterbar input{ + background-color:#ffffff; + background-color:rgba(255, 255, 255, 1); + font-size:normal; + font-weight:13px; + line-height:1; + padding:4px 9px; + margin-bottom: 4px; + margin-right: 10px; + color:#404040; + border:1px solid #808080; + border-radius:4px; + box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255,0.4); + transition:none; +} + +.filterbar .title { + font-size: 16px; + font-weight: bold; + text-shadow: 1px 1px 0px rgba(0, 43, 54, 0.15); + margin-right: 10px; +} \ No newline at end of file diff --git a/resources/js/glossary.js b/resources/js/glossary.js new file mode 100644 index 000000000..525440167 --- /dev/null +++ b/resources/js/glossary.js @@ -0,0 +1,39 @@ +/***************************** + * Text Filtering (Glossary) * + *****************************/ +$(window).load(function(){ + $('#filter').focus(); + $("#filter").keydown(function(){ + // Retrieve the input field text and reset the count to zero + var filter = $(this).val(), count = 0; + // Loop through the comment list + $("#glossary ul li").each(function(){ + // If the name of the glossary term does not contain the text phrase fade it out + if ( jQuery(this).find("h4").text().search(new RegExp(filter, "i")) < 0) { + $(this).fadeOut(); + // Show the list item if the phrase matches and increase the count by 1 + } else { + $(this).show(); + count++; + } + }); + + // Update the count + var numberItems = count; + $("#filter-count").text("Found "+count+" occurrences."); + }); +}); + +jQuery(document).ready(function($) { + // Scroll to glossary term specified by hash on page load + hash = window.location.hash; + if (hash != '') { + $('html,body').animate({scrollTop:$('li '+hash).offset().top}, 500); + } + // Set scroll animation for glossary term links within page + $("#glossary a[href^='#']").click(function(event) { + event.preventDefault(); + $('html,body').animate({scrollTop:$('li '+this.hash).offset().top}, 500); + window.location.hash = this.hash; + }); +});