Naar inhoud springen

Scala (programmeertaal)

Uit Wikipedia, de vrije encyclopedie
Scala
Scala
Paradigma Multi-paradigma: functioneel, imperatief, concurrent
Verschenen 2004
Ontwerper Martin Odersky
Ontwikkelaar EPFL - LAMP (École Polytechnique Fédérale de Lausanne - Laboratoire de Méthodes de Programmation)
Huidige versie 3.5.0[1] Bewerken op Wikidata
22 augustus 2024
Typesysteem statisch, sterk met type‑inferentie.
Implementaties scalac[2] (JVM, LAMP-EPFL), scalacompiler.exe (.NET, LAMP-EPFL)
Dialecten Kotlin
Beïnvloed door Eiffel, Erlang
Invloed op Fantom, Ceylon, Kotlin
Besturings­systeem JVM, .Net CLR, LLVM
Licentie BSD-achtig[3]
Bestands­extensies scala, sc
Website https://www.scala-lang.org/]
Portaal  Portaalicoon   Informatica

Scala is een object-functionele programmeer- en scripttaal voor algemene toepassingen. Het is statisch getypeerd, ontworpen om oplossingen bondig uit te drukken, op een type-veilige, elegante[4] en lichtgewichte wijze. Het integreert de voordelen van objectgeoriënteerde en functionele principes. Moderne software-constructies (closures, monaden[5], staartrecursie etc.) kunnen opgezet worden met bijvoorbeeld genericiteit, hogere-ordefuncties, patroonvergelijking, meervoudige overerving, call-by-name-evaluatie etc. Scala draait op Java's virtual machine (JVM) en kan enkele tekortkomingen van Java wegnemen (bijvoorbeeld meervoudige-overerving van klassen).[bron?]

De opensourcetaal is ontwikkeld op en wordt onderhouden door het EPFL (École Polytechnique Fédérale de Lausanne) in Zwitserland, Typesafe Inc./Typesafe Switzerland Sàrl en bijdragers onder leiding van hoogleraar Martin Odersky.[bron?]

In regels code worden Java-programma's meestal met een factor twee of meer gereduceerd[6][7]. Verder is de plaats van de code in de bronbestanden niet rigide waardoor er een efficiëntere structuur kan worden gebruikt en deze bestanden in aantal kunnen worden teruggebracht. Het gebruik van veel herhaalde boilerplate code wordt in Scala veelal voorkomen. Javaprogrammeurs kunnen dit oplossen door editors te gebruiken die automatisch boilerplate code toevoegen, maar dit maakt de broncode minder overzichtelijk.

Scala is een statisch getypeerde taal. Het typesysteem is een van de meest geavanceerde van alle programmeertalen, deels omdat het de uitgebreide ideeën van functioneel programmeren en objectgeoriënteerd programmeren combineert. Het typesysteem probeert alomvattend logisch, volledig en consistent te zijn. Door het wetenschappelijk gebaseerde ontwerp overschrijdt het de beperkingen van het Java-typesysteem. Het typesysteem kan intimiderend zijn, vooral voor de programmeurs voornamelijk bekend met een dynamisch getypeerde taal. De type-inferentie verbergt echter het grootste deel van de complexiteit en is de vriend van de programmeur.

De werking in een Integrated Development Environment (IDE) kan door de ingebouwde 'Scala Presentation Compiler' als proactief ervaren worden. Deze compiler controleert de broncode automatisch na elke wijziging en heeft een aantal inferentiemechanismen. Deze mechanismen trekken gevolg aan de code, bijvoorbeeld waar het einde van een statement is of over het resulterende type (type-inferentie). Een eenvoudig voorbeeld van type-inferentie; een initialisatie met 42 geeft die variabele het statische type Int (integer), een initialisatie met "Hello World!" is automatisch java.lang.String getypeerd. Dito de variabele die een functie een resultaat teruggeeft; daardoor krijgt de functie het type van die variabele.

Type-inferentie ontlast de programmeur van het nagaan en herhaaldelijk opnieuw specificeren van typen, Scala voelt daarom aan als een dynamisch getypeerde taal met als groot voordeel: typen worden tijdens compile-time eenmalig in de ontwikkelomgeving en niet meerdere malen tijdens run-time geëvalueerd waardoor de executable snel is.

Bekende Java-ontwikkeltools, zoals Eclipse[8], IntelliJ IDEA[9] of NetBeans IDE[10], bieden ook ondersteuning voor Scala. Alhoewel de byte-code interoperabel is met (bestaande) Java code, draagt Scala niet zoals Java de last van vroegere ongelukkige keuzes.[11]

Tijd-as Concept Deployment
Technologie Design-time Compile-time Runtime
Conventioneel

statisch type

Bewerken

Syntax-checking

Executie

Error checking

Type checking

Scala IDE Bewerken
Syntax-checking
Type checking Executie

Middels tooling wordt edit, compile en run-time ten opzichte van een conventionele fase naar een eerdere fase verschoven. Bijvoorbeeld error-checking tijdens editing, type-checking, nooit na de compileerfase. Dit levert een sneller en betrouwbaarder uitvoerbaar bestand op.

De naam is een samenstelling van 'scalable language' en drukt de zeer compact gehouden universele taalkern uit welke de mogelijkheid biedt om veelgebruikte taalelementen, zoals extra operators of extra control-statements in gebruikersklassen te implementeren, en daarmee de taal uit te breiden. Met andere woorden: de taal is niet hardgecodeerd in de compiler. Er bestaat bijvoorbeeld ook de mogelijkheid een eigen domein-specifieke taal te creëren.

Schaalbaar kan uitgelegd worden in de volgende domeinen:

  1. Scala is geschikt voor parallelle uitvoering en is schaalbaar in productieomgevingen met een groeiend aantal processors. Niet alleen het feit dat het mogelijk is om in Scala functioneel te programmeren maakt Scala geschikt voor parallelle programma's; Scala heeft ook een beter alternatief voor multithreading met Java: Actors;
  2. Op de taalkern kan een taaluitbreiding gemaakt worden, bijvoorbeeld in bibliotheken (bijv. het break statement).
  3. Scala kan zowel imperatief en/of functioneel gebruikt worden;
  4. De taal kan zowel als broncode voor compiler maar ook door z'n compactheid als scripttaal voor de interpreter gebruikt worden, bijvoorbeeld tijdens het programmeren of het testen.
  5. Er kan Scala gecompileerde code gemaakt worden variërend voor smartphones tot grote multicore-of multiprocessor-platforms;
  6. En dat op verschillende platforms: JVM, CLR (CLR de mobiele apps uitgezonderd) en LLVM[12][13];
  7. Rijke uitbreidingen op JVM en/of CLR-bibliotheken;
  8. Met Scala kan een interpreter voor een domein-specifieke taal (DSL) ingebed worden;

Een meegeleverd voorbeeld van flexibiliteit in taaluitbreiding is de XML-integratie. Op het gebied van architectuur heeft het de volgende vier taalmechanismen die schaalbare samenstelling van systemen bevorderen: expliciete selftypes, abstracte type members en genericiteit, geneste klassen en mixin-compositie met behulp van traits.

James Gosling, medebedenker van de programmeertaal Java, werd gevraagd welke JVM-taal uitgezonderd Java hij zou kiezen; "Scala", antwoordde hij prompt.[14]

James Strachan, die Groovy heeft gecreëerd, beschrijft Scala als mogelijke opvolger van Java[15]: "Ik kan eerlijk zeggen dat als iemand me het "Programming in Scala"[16]-boek van Martin Odersky, Lex Spoon & Bill Venners in 2003 had laten zien, ik waarschijnlijk nooit Groovy zou hebben gemaakt."

Hello World, commandline

[bewerken | brontekst bewerken]

Een Hello, world!-programma in Scala:

object HelloWorld extends App {
 println("Hello, world!")
}

In tegenstelling met het Java-voorbeeldprogramma is er geen klassedeclaratie nodig en niets hoeft als static gedeclareerd te worden[17], in plaats daarvan wordt er een singleton-object gebruikt. Het entrypoint main wordt via de trait App ingebracht.

Hello World als een Scala-shellscript[18]

[bewerken | brontekst bewerken]
Unix Windows
#!/bin/sh
exec scala "$0" "$@"
!#
// Hier het Scala-script
println("Hello, world!")
// Print de eventuele argumenten
args.toList foreach println
::#!
@echo off
call scala %0 %*
goto :eof
::!#
println("Hello, world!")
args.toList foreach println

Hello World in een grafische gebruikersomgeving

[bewerken | brontekst bewerken]

Een Hello, World!-GUI-programma in Scala:

Scala REPL HelloWorld als GUI
import swing._

object HelloWorld extends SimpleSwingApplication {
 def top = new MainFrame {
 title = "Hello, world!"
 contents = new Button {
 text = "Click Me!"
 }
 }
}

Hello World, .Net-versie

[bewerken | brontekst bewerken]

Een Hello, World!-.Net-programma in Scala:

Scala HelloWorld als .Net-dialoog
import swing._

object HelloDotNetWorld {
 def main(args: Array[String]) {
 System.Windows.Forms.MessageBox.Show("Hello, .net world!")
 }
}

Illustratie van de verschillen tussen syntaxis van Java en Scala

[bewerken | brontekst bewerken]
// Java:

int moelijkeFunctieMetDerdeMachtsEnLog(int num) {
 int numSquare = num*num;
 return (int) (Math.cbrt(numSquare) +
 Math.log(numSquare));
}
// Scala: Een taaleigen versie
// Gebruikt type-inferentie, geen 'return'-statement,
// gebruikt 'toInt()'-methode, zonder haakjes

import math._
def moelijkeFunctieMetDerdeMachtsEnLog(num: Int) = {
 val numSquare = num * num
 (cbrt(numSquare) + log(numSquare)) toInt
}

Hier zijn de volgende verschillen tussen de syntaxis zichtbaar:

  • In Scala zijn puntkomma's niet altijd vereist;
  • Hoofdletter voor datatypen: Int, Double, Boolean in plaats van respectievelijk int, double, boolean.
  • Datatype van een variabele, parameter of functie staat achter de identifier, zoals in Pascal, in plaats van vooraan;
  • Procedure of functie worden voorafgegaan met het def sleutelwoord;
  • Een functie of methode heeft een =-teken, anders is het een procedure (geeft object Unit terug);
  • Scala kent voor variabelen het onderscheid tussen wijzigbare variabelen (mutable) en variabelen met een vaste waarde (immutable). Lokale of klassevariabelen moeten voorafgegaan worden met het val- voor een onveranderlijke of var-sleutelwoord voor een muteerbare variabele;
  • De return-operator is niet verplicht maar wel toegestaan; de waarde van het laatst uitgevoerde statement is de return waarde en definieert het type van de functie (type-inferentie);
  • In plaats van de Java-cast-operator (Type) foo, gebruikt Scala foo.asInstanceOf[Type], maar meestal een gespecialiseerde conversiefunctie zoals toDouble of toInt;
  • In plaats van de Java's import math.*; gebruikt Scala import math._. De underscore is Scala's jokerteken;
  • Infix-notatie: Een functie of methode def foo() kan op de eenvoudig wijze worden aangeroepen als foo. Methode thread.send(signo) kan worden aangeroepen als thread send signo; en methode foo.toString() kan gebruikt worden met foo toString. Deze vrijheid staat gebruik als Domain-Specific Language toe.

Enkele andere basisverschillen in de syntaxis:

  • Array-elementen worden geadresseerd als functie aanroepen, bijvoorbeeld array(i) in plaats van array[i];
  • Generieke typen worden aangeduid tussen vierkante haken in plaats van Java's vishaken: List<String>;
  • In plaats van de pseudotype void heeft Scala het actuele singleton-object Unit.

Geschiedenis van Scala

[bewerken | brontekst bewerken]

Scala is het geesteskind van Martin Odersky, hoogleraar aan de École Polytechnique Fédérale de Lausanne. Zijn doel was om wetenschappelijk onderzoek op het gebied van programmeertalen aan te wenden om Java te verbeteren. Hij had vanwege zijn academische achtergrond een voorliefde voor het functioneel programmeren. Een van zijn bijdragen, na een poging tot ontwikkeling van Pizza (een super-set van Java met enkele features van functional programming), was Java Generics in Java 1.5.[19] (Odersky is in 2011 uitgeroepen tot Top Java Ambassador.[20]) Tijdens het werken aan die uitbreiding, voelde hij de grote beperkingen van Java die zijn ideeën dwarsboomden. Vanaf dat moment heeft hij een stap teruggenomen en is met een schone lei aan iets nieuws begonnen. Dit echter zonder de bestaande infrastructuur – JVM en de Java-library's – overboord te zetten. Door een te radicale aanpak mondde dit uit in een puur theoretische en daardoor onpraktische taal, Funnel genaamd. Uiteindelijk werd pragmatisch met Scala opnieuw begonnen aan een taal die het midden moest houden tussen academisch en praktisch.

Odersky zag het belang van functioneel programmeren voor de Javagemeenschap al vroeg in (bijvoorbeeld beter voorspelbare werking, concurrency, bewijsbaarheid van programmacorrectheid), maar wist in die tijd geen belangstelling te krijgen. Langzamerhand begint dit inzicht zich wijder te verspreiden onder andere door het bereiken van technologische grenzen. De eerste werkende versie van Scala dateert uit 2001, in 2003 is de taal vrijgegeven. Na een flinke herziening in 2006 is Scala stabiel en volwassen geworden. Dit was de versie 2.8. Bekende toepassingen die allang in productie zijn Twitter en LinkedIn.

Platformen en licenties

[bewerken | brontekst bewerken]

Scala draait zowel op de Java- als de .NET-platformen. Het doet zijn naam eer aan als "scalalable language" om op smartphones tot cloudomgevingen te kunnen draaien. Alhoewel er een traditionele hang is naar de JVM is er geen reden toe. Vrij snel is er met beperkte middelen een succesvolle implementatie op het toen (juni 2004) jonge .NET-platform gemaakt. Het is juist een uitdaging op meer platformen te kunnen draaien. Dan krijgt het "Write once, run anywhere"-adagio een diepere betekenis, men wordt met Scala ook virtuelemachineonafhankelijk.

De middelen zijn echter beperkt en men moet hier keuzes maken. Belangrijk is hoe Microsoft - ze hebben een vergelijkbare taal F# - hier mee omgaat. Zullen ze deze opensourcesoftware dulden naast hun intellectuele eigendommen?

De Scala-distributie[21] is, inclusief compiler en Scala Standard Library vrijgegeven onder BSD-achtige voorwaarden met slechts drie clausules[3].

Java-interoperabiliteit

[bewerken | brontekst bewerken]

Bestaande Java-code en programmeerervaring zijn herbruikbaar. Scala-programma's draaien ook op de diverse Java VM's, en zijn byte-code (classfile)-compatibel met Java, zodat er volledig gebruikgemaakt kan worden van de bestaande Java-bibliotheken of bestaande applicatie-code (JavaBeans incluis). Ook met Google Android voor het ontwikkelen van mobiele apps voor mobiele telefoons. Vanuit Scala-code kunnen de Java-klassen geïnstantieerd worden en hun respectievelijke methoden aangeroepen worden en vanuit Java kunnen de Scala-klassen en objecten vaak gebruikt worden met hun methoden. De integratie is vaak naadloos. Een goed voorbeeld hiervan is het String object dat in Java altijd immutable en daardoor type-veilig is geweest. Door deze eigenschappen is het niet geherdefinieerd in de Scala-bibliotheek en wordt er onmiddellijk verwezen naar java.lang.String. Met Java kan echter geen Scala-gedefinieerde traits worden gebruikt omdat Java dat niet kent.

JVM-ontwikkelomgevingen

[bewerken | brontekst bewerken]

Een verscheidenheid aan ontwikkelingsmogelijkheden bestaan, van eenvoudig tot geavanceerd. Ze kunnen op de computer worden geïnstalleerd op voorwaarde dat er al een Java-JDK geïnstalleerd is.

Scala Interactieve Interpreter (REPL)
[bewerken | brontekst bewerken]

De REPL is command-line-interface-gebaseerde eenvoudige, interactieve standaardtool om bijvoorbeeld verkennend te programmeren. Het is handig om code te testen maar ook om te zien wat de resulterende types worden.
Wanneer de Scala Distribution van Scala-lang.com[22] is geïnstalleerd, dan kan door scala in een command-line-interface, de REPL gestart worden. Een REPL is een eenvoudige, interactieve computerprogrammeeromgeving en hiermee is het mogelijk Scala als scripttaal te gebruiken. Het heeft met de tabtoets een completion-functie voor pakketten, klassen en methoden. In zo'n interactieve Scalasessie wordt na een enter de expressie geëvalueerd en indien compleet en valide, de resultaten getoond.

Simply Scala is een online REPL. Bedoeld voor een snelle kennismaking met Scala.

De Scala Interactieve Interpreter of Scala REPL komt ook voor in de diverse IDE's en de SBT. In de IDE heet het "Scala Interpreter" en in de SBT kan het geopend worden door het commando console.

Eclipse for Scala IDE
[bewerken | brontekst bewerken]

Sinds 2011 is de plug-inontwikkeling ter hand genomen als een EPFL/Typesafe-project. Daarvoor werd de ontwikkeling door een enkeling van Electricité de France Trading gedaan.

Op typesafe.com kan een compleet voorgeconfigureerde "Scala IDE for Eclipse"[23] gedownload worden.

.NET-integratie

[bewerken | brontekst bewerken]

Scala is primair ontwikkeld voor de Java Virtual Machine, inmiddels zijn er ook implementaties voor .NET[24][25][26][27].

Kenmerkende taalconcepten

[bewerken | brontekst bewerken]

Scala is objectgeoriënteerd, in de zin dat elk waarde een object is. De taal is ook een functionele programmeertaal, in de zin dat iedere functie ook een waarde is. Scala is statisch en sterk getypeerd, net als de programmeertaal Java. Enkele andere talen die ook op de JVM-infrastructuur werken, zoals Clojure, Ruby en Groovy, maar ook Python, JavaScript en Smalltalk zijn daarentegen dynamisch getypeerd. Sinds Scala versie 2.10 is er voor de onoverkomelijke gevallen ook een dynamisch type beschikbaar.

Lichtgewicht syntaxis en uitdrukkingskracht

[bewerken | brontekst bewerken]

Er is een onderzoek gedaan naar de zeggingskracht van talen,[28] Scala was in de top als 18e gekwalificeerd. Hieronder een oplossing van een probleem in Java (43e).

import java.util.Iterator;
import java.util.Map;

public class gistfile1 {
 public static String convertPathArgsHashToString(Map pathArgs) {
 StringBuffer pathArgsString = new StringBuffer();
 String argumentValue;
 boolean firstRun = true;
 if (pathArgs != null) {
 for (Iterator argumentIterator = pathArgs.keySet().iterator();
 argumentIterator.hasNext();) {
 String argument = (String) argumentIterator.next();
 if (firstRun) {
 firstRun = false;
 pathArgsString.append("?");
 } else {
 pathArgsString.append("&");
 }

 argumentValue = (String) pathArgs.get(argument);
 pathArgsString.append(argument);
 if (argumentValue != null) {
 pathArgsString.append("=");
 pathArgsString.append(argumentValue);
 }
 }
 }

 return pathArgsString.toString();
 }

 /**
 * @param args
 */
 public static void main(String[] args) {
 // TODO Auto-generated method stub

 }

}

En hetzelfde probleem opgelost in Scala:

object gistfile1a extends App {
 def convertPathArgsHashToString(pathArgs: Map[String, String]) = {
 (if (pathArgs.isEmpty) "" else "?") +
 pathArgs.map(kv => kv._1 + "=" + kv._2).mkString("&")
 }
 println(convertPathArgsHashToString(Map()))
}

Puntkomma-inferentie

[bewerken | brontekst bewerken]

De puntkomma om het einde van een statement aan te geven, is in Scala vaak overbodig. Met meerdere statements op een regel kan het van belang zijn, maar dit is een ongewenste lay-out. De precieze regels voor de statementscheiding zijn eenvoudig.

Een regeleinde wordt geïnterpreteerd als een puntkomma als niet aan een van de volgende voorwaarden wordt voldaan:

  • De onderhavige lijn eindigt met een woord wat niet geldig kan zijn als het einde van een statement, zoals een punt of een infix-operator.
  • De volgende regel begint met een woord dat geen begin van een statement kan zijn.
  • In het geval van een statement met haakjes (…) of […] de regel ertussen eindigt.

Een programmeur hoeft dit niet te weten, in de IDE is er een knopje voor het tonen van de inferentie-puntkomma's.

Voor het afbreken van een lang statement het is handig een operator op de vorige regel te laten staan.

Type-inferentie

[bewerken | brontekst bewerken]
Zie Type-inferentie voor het hoofdartikel over dit onderwerp.

Type-inferentie of impliciete typering is de mogelijkheid van een programmeertaal als Scala om automatisch het type van een expressie te deduceren.

Notatie infix-operator

[bewerken | brontekst bewerken]

Met Scala bestaat de mogelijkheid de starre objectinstantienaam.methode(par1, ...)-notatie te verlaten en een relaxte infixnotatie te gebruiken. De infixnotatie wil zeggen dat de methode een operator wordt omdat hij tussen de operanden komt te staan.

x foo /*is infixnotatie voor*/ x.foo();
x foo y /*is infixnotatie voor*/ x.foo(y);
y :: x /*is infixnotatie voor*/ x.::(y); // dubbelepunt verwisselt de operanden onderling
s indexOf ('o', 5) /*is infixnotatie voor*/ s.indexOf('o', 5)
// maar ook
7 + 2 /*is infixnotatie voor*/ 7.+(2) // Waarbij + een methode is

Zodoende zijn de gebruikelijke operators (+, -, *, /, etc.) in de standaardbibliotheek gedefinieerd in plaats van hard gecodeerd in de compiler waardoor zowel de taal als de compiler lichter worden. Naast dat de objectinstantienaam.methode(par1, ...) notatie nog steeds gebruikt kan worden, heeft de infixnotatie de volgende voordelen:

  • De broncode wordt duidelijker omdat de "ruis" van punten en haakjes verdwijnt.
  • Het is opeens mogelijk zelf operators te (her)definiëren.
  • Met programmacode gedefinieerde operators is het mogelijk een nieuwe (DSL-)taal te maken.
  • De operators zijn geen taalelement meer maar verhuizen naar de standaardbibliotheek. Dit maakt de compiler lichter.

For-iteraties (For-comprehension)

[bewerken | brontekst bewerken]

Het for-loop-statement is een essentiële softwareconstructie. In de toepassing is de efficiëntie belangrijk omdat de verwerkingstijd door de veelvuldige repetitie worden uitvergroot. Scala voorziet in de zogenaamde for-comprehension waarbij for-loops worden omgeschreven naar een functionele versie. Behalve een vrij efficiënte constructie met hogere-ordefuncties met staartrecursie, kan er nog een snelheidswinst ontstaan door parallelle verwerking.

For-comprehension (een variant van lijstcomprehensie) is een belangrijke bewerking door de compiler om als for-loops geschreven statements om te vormen tot een constructie waarbij uiteindelijk een nieuwe collectie wordt gegenereerd, gedreven door een collectie. De for-loop wordt dus omgevormd naar een gegenereerde lijst (lijstgenerator), eventueel een filterfunctie en een collectie-naar-collectie-functie:

// Scala origineel:
for {
 i <- 1 until n
 j <- 1 until i // ^
 if isPrime(i + j) // | Blok A
} yield (i, j) // |
// Door de compiler omgevormd 1e slag:
//
//
(1 until n) flatMap (i =>
 for (j <- (1 until i) if isPrime(i + j)) yield (i, j))
// <--------- Blok A --------->
// Door de compiler omgevormd 2e slag:
//
 (1 until n) flatMap (i =>
 (1 until i).withFilter(j =>
 isPrime(i + j))
 .map(j => (i, j)))

In werkelijkheid drukt de Scala-compiler de for-expressies uit in termen van map, flatMap en een luie variant van een filterfunctie. Door deze versie met hogere-ordefuncties kan de klassieke teller variabele(n) - die een neveneffect zou geven - verdwijnen en is het daarom mogelijk om diverse optimalisaties te gebruiken, bijvoorbeeld parallelle verwerking. Voor de programmeurs is het vaak een voordeel dat zij de gewenste verwerking nog steeds een for-loop kunnen uitdrukken; het ziet er begrijpelijker uit door de analogie met de wiskundige notatie, zoiets als ∀ n ∈ ℕ: n2 is even. Ook kan gesteld worden dat dit een (SQL-)query-achtige presentatie is. Kort samengevat biedt het for-taalelement een alternatieve en praktischer manier om iets te schrijven met behulp van een bekende notatie. Dit wordt syntactische suiker genoemd.

Het uniforme type-systeem

[bewerken | brontekst bewerken]
Scala Unified Types Hierachy

In een non-unified typesysteem-taal zoals bijvoorbeeld Java wordt duidelijk onderscheid gemaakt tussen primitieve types (zoals int, char en boolean) en referentietypes (elke klasse). Alleen referentietypes kunnen deel uitmaken van een hiërarchische klassenstructuur. In Scala, echter, waar alles een object is, erven alle typen van een top-levelklasse Any, wiens onmiddellijke kinderen AnyVal (waardetypes, zoals Byte, Short, Int, Long, Double, Float en Unit, Boolean, Char) en AnyRef (referentietypes, bijvoorbeeld: String, dit is alias java.lang.String en alle andere (Java)klassen) zijn. Dit betekent dat het Java's onderscheid tussen primitieve types en boxed types (bijvoorbeeld int versus Integer) in Scala niet aanwezig zijn, boxing en unboxing is volledig transparant voor de gebruiker en door de compiler wordt er geoptimaliseerd naar JVM-primitieven.

Unit is Scala's void, het is een singleton-type, dus met slechts een geïnstantieerd object. Met Scala 2.10 zal het mogelijk zijn nieuwe waardetypes te definiëren. (Dit was voorheen niet mogelijk omdat het sealed sleutelwoord in de runtime-library gebruikt is.) Uiteindelijk is Nothing subtype van alle klassen echter zonder overerving. Nothing is altijd het resultaat van een exception.

Option-object

[bewerken | brontekst bewerken]

Wanneer in Scala bekend is dat de methode soms geen waarde zal retourneren, kan gebruikgemaakt worden van object Option, die de klasse Some of object None kan teruggeven. (Objecten zijn eenmalige instanties van een klas.) Bijvoorbeeld:

def computeFoo: Optie [Foo] = {...}

Let op de "Option van Foo"-returntype.

computeFoo wedstrijd {
 case Some(foo) => ... // heeft een Foo, doe er iets mee
 case None => ... // kreeg geen Foo, deal with it
}

Hiermee wordt de ongelukkige keuze[29] met null-waarden en ook defensief programmeren vermeden. Overigens zijn alle Scalaklassen subklassen van Any en is Nothing een subtype van alle Scalaklassen. De null-waarde is nog noodzakelijk voor de Java- en .NET-integratie. Het is van type scala.Null en daardoor verenigbaar met elke refentietype.

Objectoriëntatie

[bewerken | brontekst bewerken]

Scala is een zuiver objectgeoriënteerde taal in de zin dat elke waarde een object is. Gegevenstypen en gedrag van objecten worden beschreven door klassen en traits. Klassen kunnen worden uitgebreid met klas-abstracties en door een flexibele en probleemloze mixin-gebaseerde compositiemechanisme met meervoudige overerving.

Klassen en objecten

[bewerken | brontekst bewerken]

Scala heeft geen statische (aangeduid met static) variabelen of methoden. In plaats daarvan heeft het singleton-objecten, wat in essentie klassen zijn met slechts een eenmalige instantie. Singletons zijn gedeclareerd met object in plaats van class. Het is algemeen gebruik een class met dezelfde naam te maken en de methoden en statische variabelen in het zogenaamde companion-object te zetten. Een class heeft toegangsrechten over alle variabelen en methoden van het companion-object ook al zijn deze private en andersom.

Dependency Injection

[bewerken | brontekst bewerken]

Meervoudige overerving met Traits

[bewerken | brontekst bewerken]

Traits zijn Scala's vervanger voor Java-interfaces. Interfaces in Java zijn zeer beperkt, daarin kunnen enkel abstracte functies gedeclareerd worden. Ook moeten dezelfde methoden opnieuw worden geïmplementeerd bij toepassing. Traits zijn vergelijkbaar met mixin-klassen in die zin dat ze bijna alle mogelijkheden hebben van gewone concrete klassen, echter zonder klasse parameters (Scala's equivalent met Java-constructorparameters), omdat traits nu eenmaal altijd worden verbonden met een concrete klas. De super-operator gedraagt zich bijzonder in traits, waardoor traits kunnen worden verbonden met behulp van compositie in aanvulling op overerving.

SpaceShip Bewapend Pantsering Medic
Slagschip Afgevinkt Afgevinkt Afgevinkt
Commandoschip Afgevinkt Afgevinkt
Gevechtsschip Afgevinkt
Ondersteuningsschip Afgevinkt Afgevinkt
object StarWars {

 class Ship(var health: Int = 0) {
 def hit = health -= 2
 def repaired(howGood: Int) { health += howGood }
 }

 trait Gun {
 def fireAt(s: Ship) = s.hit
 }

 trait Medic {
 }

 trait Shield {
 self: Ship =>
 override def hit = self.health -= 1
 }

 trait Repair {
 def repairTool(s: Ship, quality: Int) = s.repaired(quality)
 }

 val imperialFighter = new Ship(10) with Gun
 val imperialRepairShip = new Ship(10) with Repair with Medic

 val rebelFighter = new Ship(10) with Gun

 imperialFighter.fireAt(rebelFighter)
 println(rebelFighter.health)
}

Vaak wordt door traits eenvoudig krachtige (generieke) methoden overgeërfd. Een voorbeeld hiervan is de methode scala.collection.Traversable.mkString voor snelle geformatteerde output. Deze werkt namelijk op een hele reeks van structuren uit de Collections-bibliotheek.

Functioneel programmeren

[bewerken | brontekst bewerken]

In het functioneel programmeren worden de programma's uitgevoerd door het evalueren van expressies, in tegenstelling tot imperatief programmeren, waar programma's worden samengesteld uit statements die globale toestand veranderen wanneer het uitgevoerd wordt. Functioneel programmeren vermijdt het gebruik van muteerbare variabelen en destructieve re-assigments ook bekend als neveneffecten. Scala voorziet in totale ondersteuning van functioneel programmeren door de faciliteiten currying, pattern matching, algebraic data types, lazy evaluation, tail recursion, immutability etc. In Scala zijn functies "eerste klas", dit wil zeggen: iedere functie is een waarde. Hierdoor kunnen ze hetzelfde gebruikt worden als waarden: als argumenten voor andere functies of worden geretourneerd als resultaat van een functie. Deze uitwisselbaarheid staat bekend als referentieel transparantie en vereist tevens dat de functies geen neveneffecten hebben. Het gebruik van functies als argument is beter bekend als hogere-ordefuncties en het retourneren van functies maakt onder andere functie-currying mogelijk. Scala heeft een eenvoudige syntaxis voor het definiëren van anonymous functions, het ondersteunt hogere-ordefuncties en currying en het staat geneste functies toe. Het ondersteunt patroonherkenning oftewel patroonvergelijking. Patroonvergelijking kan gebruikt worden in XML-verwerking, dat ook in Scala ondersteund wordt.

Alles is een expressie. In tegenstelling tot C of Java, maar vergelijkbaar met talen zoals Lisp, maakt Scala geen onderscheid tussen statements en expressies. Alle statements zijn in feite expressies die tot een waarde evalueren. Functies die zouden kunnen worden gedeclareerd als void in C of Java en expressies die geen waarde teruggeven (bijvoorbeeld een toekenning val waarde = 42) resulteren in Scala tot het type Unit. Functies en operators die logischerwijs niets terug zouden kunnen geven (bijvoorbeeld de throw-operator of een functie die door een exception niet-lokaal opgevangen wordt) krijgen het alsnog het return type Nothing, een speciaal type dat geen subobjecten heeft en het absolute bodemtype is, dat wil zeggen een subklasse van alle mogelijke typen. Zodoende is Nothing compatibel met elk type. Hierdoor kan het type-inferentie-mechanisme volledig blijven functioneren.

Ook een if-then-else-statement is eigenlijk een expressie met een waarde als resultaat, dat wil zeggen het resultaat van de evaluatie van een van de twee takken:

// Java:
int hexDigit = x > 10 ? x + 'A' : x + '0';
// Scala:
val hexDigit = if (x > 10) x + 'A' else x + '0'

Dit betekent dat een dergelijk blok code overal kan worden ingevoegd waar een expressie gewenst is. Vanwege dezelfde redenen zijn return-statements onnodig in Scala en het gebruik ervan wordt zelfs ontmoedigd. Net als in Lisp is de laatste expressie in een codeblok de waarde van dat blok en als dat blok de body van de functie dan is het deze waarde die wordt teruggegeven.

Voor functies die Unit teruggeven, wordt vanwege dat ze een neveneffect hebben met bepaalde conventie genoteerd:

def printValue(x: String) {
 println("I ate a %s".format(x))
}

Merk op dat een =-teken hier ongewenst is omdat de functie met =-teken bijna onopgemerkt zou kunnen veranderen van return-type. Dit kan voorkomen worden bij deze expliciete notatie:

def printValue(x: String): Unit = {
 println("I ate a %s".format(x))
}

Patroonvergelijking

[bewerken | brontekst bewerken]

Een implementatie van het Quicksort-algoritme (illustratief omdat sortering ook in de Scala Standard Library-API kan worden aangeroepen):

// Sjabloon voor generieke sortering mits het sorteerbaar "[A <% Ordered[A]]" is
def quickSort[A <% Ordered[A]](xs: List[A]): List[A] = xs match {
 case Nil => xs // lege lijst, geef lege lijst terug
 case pivot :: lijst_zonder_kop => // ontbonden lijst met de fragmenten kop en staart
 lijst_zonder_kop partition (_ < pivot) // splits de lijst in twee lijsten
 match { case (onder, boven) => quickSort(onder) ++ (pivot :: quickSort(boven)) }
}

Parallel programmeren

[bewerken | brontekst bewerken]
Basis traits overerving Scala Collections

Scala komt met een rijke native of run-time-standaardbibliotheek waarin ook een goed ontworpen Collectionsframework is opgenomen.

Mutable en Immutable Collections
[bewerken | brontekst bewerken]

Er wordt systematisch onderscheid gemaakt tussen wijzigbare (mutable) en onveranderlijke (immutable) collections.[30] Een muteerbare collectie kan worden bijgewerkt of uitgebreid. Onmuteerbare collecties kunnen daarentegen niét worden gewijzigd, er zijn wel operaties die toevoegen, wissen of bijwerken maar deze operaties zullen altijd een nieuwe collectie opleveren terwijl de oude collectie ongewijzigd blijft. De respectieve pakketten van de collecties zijn scala.collection.mutable en scala.collection.immutable. Bij ontstentenis van deze aanduiding wordt vaak de immutable versie gebruikt. Er zijn ook collecties van het pakket scala.collection, maar die kunnen sommige operaties overgeërfd hebben van scala.collection.mutable, hetgeen een neveneffect kan veroorzaken. De scala.collection.immutable-versies geven de garantie hier geen last van te hebben.

Met de komst van multicoreprocessors wordt concurrent programming steeds onmisbaar. Scala's primaire concurrency-oplossing is met Actors. Actors zijn in principe gelijktijdige processen die communiceren door berichten uit te wisselen. Actoren kunnen ook worden gezien als een vorm van actieve objecten waarbij het uitvoeren van een methode veroorzaakt is door verzenden van een bericht.

API-verfijning en -overbrugging

[bewerken | brontekst bewerken]

Een veelgebruikte techniek in Scala, in kleurrijk taalgebruik bekend als "Pimp my Library"[31], maakt het mogelijk nieuwe methoden te gebruiken alsof ze werden toegevoegd aan bestaande typen. Dit is conceptueel vergelijkbaar met het C#-begrip extension methods maar krachtiger, omdat de techniek niet is beperkt tot het toevoegen van methoden, maar kan bijvoorbeeld ook worden gebruikt om nieuwe interfaces implementeren. In Scala, waarbij deze technisch een impliciete conversie wordt van het ontvangende type en de methode voor een nieuw type (gewoonlijk een klasse) de oorspronkelijke type omwikkelt voorzien van bijkomende methoden. Als een methode niet kan worden gevonden voor een bepaald type, zal de compiler automatisch zoeken naar toepasselijke impliciete conversies voor dat geval. Deze techniek maakt het mogelijk dat nieuwe methoden kunnen worden toegevoegd aan een bestaande klasse met behulp van een add-on-bibliotheek, zodat alleen code die de add-on-bibliotheek importeert de nieuwe functionaliteit geeft en alle andere code niet wordt aangetast.

Impliciete typeconversie

[bewerken | brontekst bewerken]

Impliciete typeconversie is een operatie van de compiler die een gegeven van een bepaald gegevenstype automatisch converteert naar een ander gegevenstype. In Scala worden de conversiefunctie voorzien van het sleutelwoord implicit. Hierdoor ontstaat er een functie die bijvoorbeeld type A omzet naar type B. Als er in een expressie een gegeven type A is terwijl een type B zonder expliciete methode gevraagd wordt dan zal voordat de compiler een foutmelding geeft, gezocht worden naar met implicit gelabelde functies die de functie heeft om A naar B om te zetten. Is de functie niet gevonden dan meldt de compiler alsnog de fout. Het zoeken naar de functie gebeurd in een beperkt kader. Bijvoorbeeld:

object MeasurementUnit {
 val miFactor = .254
 trait Distance

 implicit def inch2meter(x: Inch) = new Meter(x.value * miFactor)
 implicit def meter2inch(x: Meter) = new Inch(x.value / miFactor)

 case class Meter(val value: Double) extends Distance {
 // Presentatie als een String met eenheidsymbool
 override def toString = value.toString + 'm'
 // Hiermee kunnen de lengtes opgeteld worden
 def +(m: Meter) = new Meter(value + m.value)
 }

 case class Inch(val value: Double) extends Distance {
 // Presentatie als een String
 override def toString = value.toString + '"'
 def +(m: Inch) = new Inch(value + m.value)
 }

 def main(args: Array[String]): Unit = {
 // Engelse duim gegeven, meter gevraagd
 val meter: Meter = Inch(1) // Aut. conversie met inch2meter
 // Meter gegeven, Engelse duim gevraagd
 val inch: Inch = Meter(1) // Aut. conversie met meter2inch
 val totaal: Meter = inch + meter
 println(Inch(1) + " = " + meter)
 println(Meter(1) + " = " + inch)
 }
}

Er zijn verschillende mogelijkheden om in Scala te testen:

  • ScalaTest ondersteunt meerdere teststijlen en kan geïntegreerd worden met Java-gebaseerde frameworks (bijv. JUnit4).
  • ScalaCheck, een bibliotheek gelijk aan Haskell's QuickCheck
  • specs2, een bibliotheek voor executable-softwarespecificaties.
  • ScalaMock voorziet in een mogelijkheid hogereorde en curried functions te testen.
  • JUnit of TestNG, de populaire test-raamwerken in Java.

Zakelijke aspecten

[bewerken | brontekst bewerken]

Businessmodel

[bewerken | brontekst bewerken]

De ontwikkeling van de taal werd onder leiding van Martin Oderski gedaan op de EPFL met zijn programmeeronderzoeksgroep LAMP (Laboratoire de Méthodes de Programmation). Omdat het opensourcesoftware is, kan in principe hier ieder aan meewerken. Het werk is voor een deel wetenschappelijk met name de syntaxis en compilerbouw. Ook wordt er universitair onderricht meegegeven op zijn faculteit. Promovendi nemen deel aan aanpalende onderzoeken voor hun proefschrift.

  • Begin 2011 kon Odersky door een vijfjarige subsidie van de European Research Council, groot 2.3 miljoen euro,[32][33] zijn plannen grootser uitvoeren. Dit was ook aanleiding de commerciële activiteiten onder te brengen in een nieuwe onderneming: Typesafe Inc. als opvolger van Scala Solutions.[34] Dit bedrijf is opgericht door Martin Odersky, voor zijn Scalabelang, samen met de Zweed Jonas Bonér, bedenker van de middleware Akka voor distributed computing.[35] Tezamen met het Franse web-framework Play! hebben ze een commercieel platform dat het ook mogelijk maakt geld van investeerders aan te trekken. Het is een strategische keuze geweest om met deze combinatie van opensourceaanbieders samen te werken, alleen valt de Liftweb-aanbieder David Pollak, die Scala sinds 2006 al Scala beoefent, hierdoor buiten de boot. Waarschijnlijk omdat voor hem geen Europees geld gegund wordt.[bron?]
  • Ook in hetzelfde jaar investeert Microsoft ontwikkelingsgeld om Scala op het .NET-platform te kunnen gebruiken.
  • In mei 2011 investeert Greylock Partners (Reid Hoffmann (LinkedIn, Airbnb), Chamath Palihapitiya (Facebook); Diane Greene en Mendel Rosenblum (VMWare-oprichters); Francois Stieger (voormalig Verisign-executive); en Jeff Huber (Google)) $ 3 miljoen in het bedrijf.
  • In 2012 maakte Typesafe een financiering rond van $ 14 miljoen. Geldschieters zijn Shasta Ventures en Juniper Networks samen met Greylock Partners.

Door een betere bemensing, als gevolg van een betere financiële basis, kon ook de verdere ontwikkeling van aanpalende software serieus ter hand worden genomen, de Integrated Development Environment kon verbeterd worden: er kwam een stabiele versie.

Als adviseurs van Typesafe Inc. zijn toegetreden:

  • James Gosling, ontwerper van Java;
  • Doug Lea, onder andere voorzitter van de Javacommissie die het "Fork/Join Framework" (JSR-166) heeft geïmplementeerd;
  • Willy Zwaenepoel, hoogleraar op het EPFL;
  • Guillaume Bort, voormalig J2EE-expert en leider van het Play!-opensourceproject.

Op 30 september 2012 treedt Rod Johnson toe tot de directie van Typesafe,[36] auteur van Expert One-on-one J2EE Development[37], die het Spring Framework heeft geëntameerd.

Populariteit van Scala

[bewerken | brontekst bewerken]

Volgens Indeed Job Trends, neemt voor Scala de arbeidsvraag snel toe sinds 2010.[38]

RedMonk Programming Language classificering

[bewerken | brontekst bewerken]

In de RedMonk Programming Language-classificering - die gebruikmaakt van populariteit in Stack Overflow en GitHub - blijft Scala duidelijk achter op een eersterangsgroep van 11 talen (waaronder Java, C, Python, PHP en Ruby), maar leidt de tweede echelongroep, met een voorsprong op Haskell, Groovy, Clojure, Erlang, Prolog, Scheme en Smalltalk.

De ThoughtWorks Technology Advisory Board heeft Scala in haar Radarrapport van oktober 2012 van de Trial- naar de Adopt-ring geadviseerd.[39] Dit betekent dat Scala als een betrouwbaar volwassen taal beschouwd mag worden en heden ten dage gebruikt kan worden.

Rangvolgorde sinds 2006.

In april 2013 zette de programmeertaalpopulariteitsindex TIOBE Scala op de 29e plaats met 0,336% van de totale programmeertalen, terwijl daarvoor lange tijd Scala nog rond de 45 lag. Scala kwam zo in de buurt van Scheme (27e) en voorbij Erlang (31e), Prolog (30e) en Haskell (32e). Scala heeft een ruime voorsprong op zowel Groovy en Clojure, de andere twee JVM-gebaseerde talen die vaak met Scala wordt vergeleken, maar die vallen beiden beneden de 50e plaats.

Transparent Language populariteitsindex

[bewerken | brontekst bewerken]

Evenzo zet de Transparent Language-populariteitsindex Scala op positie 34, na Haskell en vóór ML en Erlang.

Enkele bedrijven die Scala gebruiken

[bewerken | brontekst bewerken]

Veel bestaande bedrijven die van Java afhankelijk zijn voor bedrijfskritische applicaties wenden Scala aan om hun ontwikkelingsproductiviteit, applicatieschaalbaarheid en betrouwbaarheid te verhogen. Met reactief programmeren worden zware claims op het gebied van responsiviteit, veerkracht, elasticiteit en berichtgedrevenheid toch gerealiseerd.

Website in productie Back-end

Appjet heeft voor het succesvolle EtherPad het onderliggende Appjet web raamwerk in Scala ontwikkeld. Appjet is overgenomen voor het Google Wave project wat op zijn beurt deels is opgegaan in het Google Drive project. Google Drive heeft ongeveer de enige web-gebaseerde woordprocessor waarbij meerdere personen tegelijkertijd een document kunnen bewerken waarbij de veranderingen voor iedereen zichtbaar zijn. Een knap staaltje Functioneel Reactief Programmeren.
In april 2009 maakte Twitter bekend dat het belangrijke delen van Ruby naar Scala had omgeschreven en van plan was dat ook met de rest te doen.[64][65]
LinkedIn gebruikt het Scalatra microframework om hun Signal API aan te sturen.[48]
GridGain biedt Scala-based DSL for cloud computing aan.[45]
Foursquare gebruikt Scala en Lift Web Framework.[43]
Meetup gebruikt Unfiltered toolkit voor real-time APIs.[55][56]
In april 2011 maakte The Guardian (guardian.co.uk) bekend dat het overschakelde van Java naar Scala, met als eerste project de Content API voor het selecteren en verzamelen van nieuws content[62][63]. Deze website heeft de meeste lezers op The New York Times na.[78]
De Zwitserse bank UBS heeft Scala goedgekeurd voor gebruik in algemene productie.[76]
Remember the Milk gebruikt Unfiltered toolkit, Scala and Akka voor hun publieke API en real time updates.[61]
Op 31 augustus 2013 wordt bekendgemaakt dat Intel een gloednieuw gedistribueerd platform bouwt op Scala gebaseerd om zodoende gebruik te maken van de krachtige functies om elegante API's te bouwen. Intel maakt hevig gebruik van instrumenten zoals de Akka concurrency toolkit, die helpt bij het oplossen van een aantal van de inherente problemen met gedistribueerde systemen.[70]

Kritiek op Scala

[bewerken | brontekst bewerken]

Stephen Colebourne - de ontwikkelaar van de alom geroemde Joda-Time-Java-bibliotheek en hoofdontwikkelaar van de JSR-310 Date and Time-API - is de prominente criticus van Scala. Op 29 november 2011 schreef hij over een uitgelekt mailtje tussen een Yammer-personeelslid en mensen van Typesafe dat Yammer weer terug zou switchen naar Java.[79][80] Hijzelf en het bedrijf haastte zich om nadere uitleg te geven.[81][82] Het bleek een misverstand. Yammer had een performance-probleem en werd niet onmiddellijk op haar wenken bediend met een "quick fix". Typesafe stond op het standpunt de bug structureel op te lossen en niet ad hoc, verder gaven ze een serieus en inhoudelijk antwoord.[83]

  • Scala is Italiaans voor trap. In het aanvankelijke en huidige logo is de rode wenteltrap verwerkt van de faculteit LAMP van de EPFL. Mogelijk is deze trap eveneens de aanleiding voor de naam Scala.
  • Martin Odersky was tot in het voorjaar van 2011 een fervent Emacsgebruiker. Hij is overgestapt na het uitkomen van een stabiele Eclipse-IDE voor Scala.
  • Op 18 september 2012 begon de eerste 7-weekse MOOC "Functional Programming Principles in Scala" van Coursera.org[84] met circa 50.000 inschrijvingen waarvan 9593 al hun opdrachten hebben ingestuurd. Op een afsluitende enquête waren er 166 respondenten uit Nederland en 113 uit België. Naar schatting zijn er zo'n 230 studenten in Nederland en 160 in België die al hun opdrachten hebben ingestuurd en beloond zijn met een certificaat.
  • De resultaten van de enquête[85] zijn in een GitHub-repository opgeborgen, samen met het analyserende programma in Scala.[86]

Categorie:Software geschreven in Scala

[bewerken | brontekst bewerken]
Officiële website
  • (en) Introducing Scala. The Scala Programming Language. Geraadpleegd op 11 maart 2013.
Typesafe, het commerciële Scala instituut
Cheat sheets
  • (en) O'Connor, Brendan, Scalacheat. Scala Documentation. Geraadpleegd op 6 januari 2013.
  • (en) Rytz, Lukas, Scala Cheat Sheet. Github Repository. Geraadpleegd op 29 januari 2013.
  • (en) Spiewak, Daniel; David Copeland, Scala Style Guide. Scala Documentation. Geraadpleegd op 8 februari 2013.
Gratis Scalacursussen
  • Stuurman, Sylvia, Opener cursus Scala. Open Universiteit (21 juli 2011). Geraadpleegd op 15 december 2012.
  • (de) Paggen, Marcel, ScalaTutorial.de (28 februari 2013). Geraadpleegd op 11 maart 2013.
  • (de) Schäfer, Simon, Scala Tutorial. Scala Tutorial (6 april 2012). Geraadpleegd op 28 januari 2013.
  • (en) Jenson, Steve; Marius a. Eriksen, Larry Hosken, Scala School!. Geraadpleegd op 17 december 2012.
  • (fr) Einstein++, Apprenez la programmation avec Scala. Le Site du Zéro (8 januari 2013). Geraadpleegd op 16 december 2012.