Vés al contingut

Scala

De Viki.cat

<templatestyles src="Metacaixa enllaç de desambiguació/styles.css" />

Aquest article tracta sobre el llenguatge de programació. Si cerqueu l teatre d'òpera, vegeu La Scala.

Scala és un llenguatge de programació modern multi-paradigma dissenyat per a expressar patrons de programació generals d'una manera concisa, elegant i segura respecte els tipus. Integra característiques de orientació a objectes i de llenguatges funcionals.

Scala és orientat a objectes

Scala és un llenguatge pur O.O. (orientat a objectes) en el sentit que cada valor és un objecte. Els tipus i comportaments dels objectes són descrits mitjançant classes i 'trets'. L'abstracció classe s'estén mitjançant subclasses i també amb un mecanisme flexible basat en classes 'mixins' (barrejables: similars als interface de Java però amb def. de tipus, variables i implementació de mètodes) anomenades trets com a substitució neta de l' 'herència múltiple'.

Scala és funcional

Scala també és un llenguatge funcional en el sentit que cada funció és un valor. Scala proveeix una sintaxi fàcil per a la definició de funcions anònimes, suporta funcions d'ordre superior, permet l'aniuament de funcions i suporta el currying. Les classes per cas (ang.: case classes) i el suport que inclou de reconeixement de patrons, serveix per a modelar tipus algebraics, emprats en molts llenguatges de programació funcional.

A més a més, la noció de reconeixement de patrons estén de manera natural el procés de dades XML amb l'ajuda de seqüències de patrons ignorant el que hi ha a la dreta (ang.:right-ignoring). En aquest context, les comprehensions de seqüències (iteració sobre Generadors-Filtres-Mapeig) són útils per a formular consultes. Aquestes característiques fan de Scala l'ideal per a desenvolupar aplicacions com a serveis web.

Scala té tipus estàtics

Scala està equipat amb un sistema de tipus expressiu que assegura estàticament que les abstraccions s'utilitzin de manera coherent i segura. En particular el sistema de tipus suporta:

  • classes genèriques,
  • anotacions de variació,
  • acotacions de tipus per dalt i per baix,
  • classes internes i tipus abstractes com a membres de l'objecte,
  • tipus compostos,
  • auto referències tipificades explícitament,
  • vistes, i
  • mètodes polimòrfics.

Un mecanisme d'inferència de tipus permet que l'usuari no hagi d'anotar els tipus de manera redundant. En combinació, aquestes característiques proporcionen una base potent per a la reutilització segura de les abstraccions de programació i també per a l'extensió de programari amb tipus de dades segurs.

Scala és extensible

El disseny de Scala reconeix el fet que, a la pràctica, el desenvolupament d'aplicacions d'un domini específic requereix extensions de llenguatge igualment específiques. Scala proporciona una combinació única de mecanismes de llenguatge que fan fàcil afegir noves construccions al llenguatge, amb suavitat , en forma de biblioteques:

  • qualsevol mètode pot ser emprat com a operador infix o postfix, i
  • els tancaments es construeixen automàticament depenent del tipus esperat.

Un ús conjunt d'ambdues característiques facilita la definició de noves instruccions sense estendre la sintaxi i sense emprar tècniques de meta-programació com ara macros.

Scala interopera amb Java i .NET

Scala està dissenyat per a interoperar bé amb entorns populars de programació com Java 2 (JRE) i el marc .NET (CLR). En particular, la interacció amb llenguatges orientats a objectes de gran acceptació com Java i C# és força suau. Scala té el mateix model de compilació (compilació separada, càrrega dinàmica de classes) que Java i C#, permetent accedir a milers de biblioteques d'alta qualitat.

Exemple: Hola món

Per començar:

Al Linux el podeu instal·lar pels paquets de la distribució. Altrament el compilador es pot descarregar d'aquí[1] o com endollable en un entorn IDE aquí[2]

El programa Hola món en Scala: <source lang="scala">

// fitxer test/hola-mon.scala
package test
object Principal {
   def main(args: Array[String]) = Console.println("Hola món!")
}

</source> alternativa <source lang="scala">

// fitxer test/hola-mon.scala
package test
object Principal extends Application { // Application defineix main
   Console.println("Hola món!")        // la inicialització de l'objecte executa les expressions del cos.
}

</source>

  • Compilació i execució a consola de comandes:[3]
cd objdir
scalac ../src/test/hola-mon.scala

scala test.Principal          # execució pel nom de l'objecte que conté el mètode ''main''

Hola món!
  • A l'avaluador d'expressions (bucle Read-Eval-Print)
scala

scala> println( "Hola món")
Hola món

scala>

Característiques

Degut a ésser un llenguatge dissenyat inicialment per a la màquina virtual JVM, hereta del Java les característiques del lèxic i els tipus bàsics i les seves operacions així com una sintaxi molt similar.

Els punt-i-coma a final de línia es poden ometre (des de la versió 2).

tipus Unit

Equival al tipus buit (void en Java) de les instruccions que no retornen res, habitualment assignacions i altres efectes laterals.

El seu únic valor és: ()       // no-op : no fer res (element neutre de les operacions)

altres tipus especials

Vegeu ref.[4]

Any
generalització d'un tipus qualsevol
AnyVal
generalització dels tipus bàsics que es passen per valor.
AnyRef
generalització dels tipus que es passen per referència. Correspon a Java.lang.Object
ScalaObject
base per als objectes de Scala
Null
es considera subtipus de qualsevol classe o objecte, així el seu valor null pot pertànyer a totes elles.
Nothing
subtipus de tots els tipus.

restriccions en els tipus

Els tipus poden parametritzar funcions, classes, objectes i trets. Admeten a més restriccions especials.

En el següent exemple Tipus ha d'ésser subtipus de TCotaSuperior.[5]

type Tipus <: TCotaSuperior

en el següent exemple Tipus ha d'ésser superclasse de TCotaInferior.[6]

type Tipus >: TCotaInferior

Convertibilitat

type A <% T // indica que A ha de ser convertible en T mitjançant una conversió implícita. Vegeu Scala Views[7]

<source lang="scala"> trait Set[A <% Ordered[A]] ... class EmptySet[A <% Ordered[A]] ... class NonEmptySet[A <% Ordered[A]] ... </source>

encaix segons el valor o el tipus

Primer valors, després tipus

<source lang="scala"> package test ;

object Main extends Application {

 val llista: List[Any] = List(true, 'c', 8:Byte, 270:Short, 300, 200000000000L, 2.5F, 3.12345678, "abc") ;
 for (elem <- llista) {
   elem match {
          case 2 | 3 => print( "dos o tres") ;
          case v :Char => printf("%c u\\%04x", v, v.toInt ) ;  // caràcter i hexadecimal
          case v :Byte => printf("és un byte: %d", v) ;
          case v :Short => printf("és un short: %d", v) ;
          case v :Int  => printf("és un int: %d 0%o x%08x", v, v, v) ;     // decimal, octal i hexad.
          case v :Long => printf("%d", v) ;
          case v :Float => printf("%.2f", v) ;
          case v :Double => printf("%.8f", v) ;
          case v :String => printf("%s", v) ;
          case v :AnyRef => print( v.toString) ;  
          case v => print( v) ;                       
   }
   println("") 
 }

} </source>

dóna

true
c u\0063
és un byte: 8
és un short: 270
és un int: 300 0454 x0000012c
200000000000
2,50
3,12345678
abc

polimorfisme paramètric

A més del polimorfisme per especialització dels objectes, les funcions es poden parametritzar per Tipus <source lang="scala">

def nom_funció[VariableDeTipus](param1: VariableDeTipus, ..) = ...

</source> exemple: <source lang="scala"> object Main extends Application {

 def imprimeix[T]( dada: T) = 
   dada match {
     case v: String => println( v) ;
     case v => println (v.toString) ;
   }
 imprimeix[Int]( 5) ;
 imprimeix[String]( "abc") ;
 imprimeix( 2) ;              // si no s'explicita el tipus es dedueix dels paràmetres actuals.
 imprimeix( "def") ;

} </source>

classes "per cas" per implementar tipus "suma" algebraics

El que en altres lleng. funcionals es descriu com a unió de tipus discriminats per etiquetes anomenades constructors, aquí es parteix de la classe que identifica el tipus i se'n deriven classes per cada cas de la unió discriminada, amb el constructor per nom i paràmetres corresponents als components del cas.


<source lang="scala"> abstract class Arbre[T] // val al paràmetre el fa consultable externament (és membre de la classe) case class Fulla[T]( val dada: T) extends Arbre[T] case class Branca[T]( val dada: T, val esquerra: Arbre[T], val dreta: Arbre[T]) extends Arbre[T]

object Main extends Application {

 def imprimeixArbre[T]( arbre: Arbre[T]):Unit = 
   arbre match {
           case Fulla( d) => println ("fulla: " ++ d.toString)
           case Branca( d, esq, dreta) => { imprimeixArbre( esq) ;
                                            println("branca: " ++ d.toString) ;
                                            imprimeixArbre( dreta) ;
                                          }
   }
 val arbre1 = new Fulla( 1) ;   // si s'omet el paràmetre de tipus [T], es pren el del literal.   
 val arbre2 = new Branca[Int]( 2, arbre1, arbre1) ;
 imprimeixArbre( arbre2) ;

} </source>

Equivalència en ML Estàndard:

datatype 't Arbre = Fulla of 't | Branca of ('t * 't Arbre * 't Arbre)

Equivalència en Haskell:

data Arbre t = Fulla t | Branca t (Arbre t) (Arbre t)

Vegeu exemple #Encaixos de patrons.

Llistes

<source lang="scala"> object Main extends Application {

 val llista = List( 1, 2, 3) ;
 def descriuLlista[T]( llista: List[T]) = 
   llista match {

case Nil => println ("llista buida") ;

case ll @ _::_ => // as-pattern (variable @ patró): unifica variable i terme encaixat

                         println ("llista no buida: " + ll.toString) ;
   }
 descriuLlista( llista )

}</source>

Llistes per comprensió

La clàusula for admet una primera part amb generadors i filtres (clàusula if), i una segona part de mapeig que pot ésser o bé un bloc imperatiu d'efectes laterals, o bé una clàusula yield amb una expressió o bloc que retorna una llista resultant de l'aplicació del bloc a la llista del generador.

// retorna la llista dels dobles dels parells de l'interval

for (i <- Iterator.range( des_de, topall_exclòs) if i % 2 == 0) yield 2 * i

Variables

El tipus de les declaracions es pot ometre si es dedueix de la seva inicialització de manera inequívoca, altrament el compilador avisarà.

val nom_var :tipus = ..     // amb val: variable assignable un sol cop
var nom_var :tipus = ..     // amb var: variable assignable més d'un cop

Operadors

Els operadors són mètodes definits amb símbols. <source lang="scala"> class Q {

         def ##(that:Q) = this != that
       }

</source> La precedència la determina el primer dels símbols. (Vegeu apartat 'Infix operators' al manual de ref. del llenguatge).

(all letters)
|
^
&
< >
= !
:
+ -
* / %
(all other special characters)

L'associativitat la determina el darrer símbol, que si és ':' llavors és associatiu per la dreta, altrament associatiu per l'esquerra.

Tuples

Definides les classes Tuple2, Tuple3, .., Tuple22.
Pair equival a Tuple2, Triple a Tuple3

<source lang="scala">

object Main extends Application {

 val parell = new Pair( 10, "abc") ;
 val parell2 = Pair( 10, "abc") ; // alternativa amb el mètode fàbrica d'instàncies 
                                  // (ang: factory method) a l'objecte Pair.
 val Pair(primer, segon) = parell ;  // encaix de la tupla
 println( primer) ;
 println( segon) ;

} </source>

Classes i mòduls Object

En Scala se separen les parts dinàmica i estàtica de les classes del Java en class i object (mòdul no instanciable que conté els membres estàtics), com a l'OCaml.

Extensibilitat. Els mòduls object tenen un tractament unificat amb les classes respecte a l'extensibilitat com si fossin classes d'una sola instància (singleton) que els permet implementar interfaces i estendre'ls amb altres object i traits com a l'exemple amb l' object Application.

Grafia. Els identificadors dels mòduls object comencen per majúscula segons el llibre d'estil.

La inicialització dels mòduls object i també de les classes, es produeix seqüencialment processant definicions i instruccions executables, com a l'ML Estàndard i l'OCaml.

<source lang="scala"> // Application és l' object d'engegada que conté el mètode main

object ProvaFiltratge extends Application {

 def filtrar(xs: List[Int], llindar: Int) = {
   def processa( ys: List[Int]): List[Int] =    // funció a l'interior d'una altra funció
     if (ys.isEmpty) ys
     else if (ys.head >= llindar) ys.head :: processa( ys.tail)
     else processa( ys.tail)
   processa( xs)
 }
 println( filtrar( List(1, 9, 2, 8, 3, 7, 4), 5))

} </source>

En importar una classe de Java, l'identificador designa la classe equivalent en Scala amb els mètodes dinàmics, així com l' Object que conté els mètodes, variables i constants estàtics.

<source lang="scala"> import java.lang.{Color} val vermell = new Color( 0xFF, 0, 0) ; // constructor de la classe val componentRoigDelBlanc = Color.getRed( Color.WHITE) ; // membres estàtics de l' Object </source>

override
els mètodes que es redefineixen han de dur el qualificatiu override per distingir-los dels que es volen nous, per evitar que si algú afegeix un mètode amb el mateix nom i signatura a alguna de les superclasses o trets que s'hereten el comportament esdevingui diferent del que se n'espera.

Trets: variables, operacions i tipus, incorporables a classes i mòduls object

Assimilables als interface del Java, però amb el potencial d'una classe abstracta.

Els trets poden contenir definició de tipus, variables i mètodes, i també implementacions dels mètodes, però no són instanciables per si mateixos, ni poden tenir paràmetres de valor.

<source lang="scala"> import java.awt.{Color} ;

trait Acoloriment { var color:Color ; def pinta( nouColor: Color): Unit = { color = nouColor} def imprimeixColor: Unit = { print( "color: ") ; println( color) } }

trait Cloneable extends java.lang.Cloneable {

 override def clone(): Cloneable = { super.clone(); this }

}

trait Resetable {

 def reset: Unit

}

def cloneAndReset(obj: Cloneable with Resetable): Cloneable = {

 val cloned = obj.clone()
 obj.reset
 cloned

} </source>

herència múltiple

L'herència múltiple es basa en la incorporació de trets.

<source lang="scala"> import java.awt.{Color} ;

class Punt(xInicial:Int) { var x: Double = xInicial.toDouble ; def desplaça( dx: Double): Unit = { x = x + dx} def imprimeixPosició: Unit = { print( "posició: ") ; println( x) } }

trait Acoloriment { var color: Color ; def pinta( nouColor: Color): Unit = { color = nouColor} def imprimeixColor: Unit = { print( "color: ") ; println( color) } }

class PuntAcolorit( xInicial:Int, colorInicial: Color) extends Punt( xInicial) with Acoloriment {

var color = colorInicial ;

def desplaçaIPinta( dx: Double, nouColor: Color) = {

super.desplaça(dx) ; super.pinta(nouColor) ; } }

object Main extends Application {

 val punt = new PuntAcolorit( 0, Color.WHITE) {   // extensió en instanciar
                                     // només aquesta instància incorpora l'extensió

def desplaçaRàpid( dx: Double) = { x = x + 10.0 * dx }

 }
 punt.desplaçaIPinta(2, Color.BLUE) ;
 punt.desplaçaRàpid( 3.5)
 punt.imprimeixPosició ;
 punt.imprimeixColor ;

} </source> dóna el resultat:

posició: 37.0
color: java.awt.Color[r=0,g=0,b=255]

funcions anònimes com a expressió

exemple:

(x: Int, y:Int) => x + y         // el tipus del resultat és deduït per inferència en aquest cas

En l'exemple següent el compilador dedueix els tipus dels paràmetres de la funció sobre la qual s'aplica.

<source lang="scala"> object Main extends Application {

 val llista = List(1,2,3,4) ;  // pels literals infereix tipus List[Int]
 // aplica la funció a un acumulador i cada valor de la llista
 // els tipus dels paràmetres els dedueix de l'aplicació parcial (funció ometent paràmetres) precedent.
 //     tipus de llista.foldleft( 0) : (Int * Int) => Int
 val result = llista.foldLeft( 0) { (x,y) => x+y } ; 
 Console.print("resultat: ") ;
 Console.println( result);

} </source> dóna l'esperat

resultat: 10

funcions d'ordre superior

Amb funcions als paràmetres o al resultat. <source lang="scala">

// en aquest cas, funció que pren una funció d'argument i en retorna una altra

def sum(f: Int => Int): (Int, Int) => Int = {

 def sumF(a: Int, b: Int): Int =             // suma f(x), x <- [a..b]
   if (a > b) 0 else f(a) + sumF(a + 1, b)
 &sumF

}

def sumaDobles = &sum( x => 2 * x) def sumaQuadrats = &sum( x => x * x) </source>

Assercions

Vegeu Assercions[8] i Opció de compilació -enableassertions[3]

assert( predicat [,missatge])
especifica un predicat que cal provar i dispara l'excepció java.lang.AssertionError: assertion failed: missatge
assume( axioma [,missatge])
especifica un axioma. Dispara l'excepció java.lang.AssertionError: assumption failed: missatge
require( predicat [,missatge])
com assert però blasma la funció que el crida,[8] llançant l'excepció IllegalArgumentException: requirement failed
error( missatge)

XML al codi

Vegeu [9] <source lang="scala"> object Main extends Application {

 val idioma = "ca" ;
 val títol = "El meu títol" ;
 val xml_títol = <title> {títol} </title> ;    // entre claus '{' <expr> '}' substitució d'expressions.
 val xml_capsalera = <head> {xml_títol} </head>
 // substitució a l'atribut, hi afegeix les cometes.
 val xml_pàgina = <html lang={idioma}>  
                    {xml_capsalera} 
                    <body> Aquesta pàgina porta el títol {títol} </body>
                  </html> ;
 val capsal_xml ="<?xml version='1.0' encoding='UTF-8' ?>\n" ;
 val doctype = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" " +
          " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" ;
 println( capsal_xml + doctype + xml_pàgina) ;

} </source>

Genèrics mitjançant mòduls implícits (implicit object)

Classes genèriques (parametritzades en tipus) per agrupar funcions. Les implementacions d'aquestes classes per a tipus concrets, constitueixen mòduls de instància única (singleton) que es passaran de manera implícita (implicit object).

La obtenció de la instància adequada al tipus de la crida és automàtica, mitjançant un paràmetre implícit (absent en la crida) del tipus del genèric. Permeten diversificar el tipus retornat per una funció.

A l'exemple el paràmetre (implicit m: Monoid[A]), m obtindrà el valor de la instància específica del genèric Monoid[A] per al tipus de A emprat en la crida a la funció def suma[A](xs: List[A])(implicit m: Monoid[A]). <source lang="scala">

   abstract class SemiGroup[A] {
     def add(x: A, y: A): A
   }
   abstract class Monoid[A] extends SemiGroup[A] {
     def unit: A
   }
   object ImplicitTest extends Application {
     // mòdul instància de Monoid per al tipus String
     implicit object StringMonoid extends Monoid[String] {
       def add(x: String, y: String): String = x concat y
       def unit: String = ""
     }
     // mòdul instància de Monoid per al tipus Int
     implicit object IntMonoid extends Monoid[Int] {
       def add(x: Int, y: Int): Int = x + y
       def unit: Int = 0
     }
     // param. implícit selecciona instància segons param. de tipus
     // entre els implícit objects visibles en l'àmbit.
     def suma[A](xs: List[A])(implicit m: Monoid[A]): A =
       if (xs.isEmpty) m.unit
       else m.add(xs.head, suma(xs.tail))
     println(suma(List(1, 2, 3)))
     println(suma(List("a", "b", "c")))
   }

</source>

Parametrització de tipus amb cota superior

Admetre tipus més especialitzats que un tipus determinat.

<source lang="scala"> trait Similar {

 def isSimilar(x: Any): Boolean

}

case class MyInt(x: Int) extends Similar {

 def isSimilar(m: Any): Boolean =
   m.isInstanceOf[MyInt] &&
   m.asInstanceOf[MyInt].x == x

}

object UpperBoundTest extends Application {

 def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean =
   if (xs.isEmpty) false
   else if (e.isSimilar(xs.head)) true
   else findSimilar[T](e, xs.tail)
 val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
 println(findSimilar[MyInt](MyInt(4), list))
 println(findSimilar[MyInt](MyInt(2), list))

} </source>

La API de Scala

Scala té una llarga biblioteca per facilitar la feina amb varietat de col·leccions immutables i mudables així com tractament de XML i altres que trobareu aquí.[10]

L'especificació oficial del llenguatge és aquí.[11]

Els elements predefinits són a l' object Predef[12]

Entorns de desenvolupament

La millor manera de treballar amb Scala és descarregant d'aquí[2] l'endollable per a l'Eclipse (o altres entorns de desenvolupament Java) que ja incorpora el compilador i les biblioteques de les quals, clicant, se'n pot examinar el codi font.

Scala a l'Eclipse

A l'Eclipse[13], un cop incorporat l'endollable al menú Help->Install new software podrem crear un "Projecte Scala" que incorporarà automàticament les biblioteques de Scala al projecte si ho fem amb el menú de context de la barra lateral esquerre a l'opció "New -> Project -> Scala Wizards -> Scala Project" del menú de context de la barra lateral de projectes.

Scala segueix la mateixa estructura de mòduls (package) que el Java. Tantmateix podem posar diversos objects, classes i traits al mateix fitxer de codi font.

És habitual crear primer sobre el directori src, abreviació de source (codi font), un Package amb nom on crear els fonts, si volem facilitar l'estructuració modular o la inter-operabilitat amb paquets d'altres projectes.

Després podrem triar, al menú de context del package, els assistents (ang:wizards) de generació d'esquelets Scala Application, Scala Object, Scala Class o Scala Trait

Execució: per cada projecte cal crear una configuració d'engegada que podrem desar, especificant projecte, nom de l'objecte que conté el mètode main i possibles paràmetres de l'aplicació. Clicant el menú de context del projecte, opcions "RunAs -> Run configurations -> especificar la configuració o seleccionar-la -> botó Run"

Exemples

Encaixos de patrons

<source lang="scala"> package test // fitxer: test/LaMevaApp.scala

abstract class Llista ;

trait Imprimible { // en Java seria un interface

                                           // admet definició de tipus i implementació de mètodes.
 def imprimeix: Unit ;                     // tipus Unit: equival al void de Java i C

}

trait Igualable {

 def igual_que( aquell: Any): Boolean ;
 def desigual_que( aquell:Any): Boolean = ! igual_que( aquell) ;  // amb implementació inclosa

}

// herència múltiple basada en mixins (cat: barrejables): traits

class LlistaImprimible extends Llista with Imprimible with Igualable {

 def imprimeix: Unit = this match {        // this es refereix a la instància
   case LlistaCons( cap, cua) => {         // patró LlistaCons
     cap match {                           // encaix segons el tipus
       case v:Int => printf("%d", v) ;
       case v:Float => printf("%.2f", v) ; 
       case _ => () ;                      // valor () de tipus Unit equival a no-op (no fer res)
     }
     
     print( " ") ;
     cua.imprimeix ;
     }
   case LlistaNil () => println ("Fi")     // patró LlistaNil
   }
 def igual_que( aquell:Any): Boolean = 
         // refinament amb guarda: comprova la subclasse (isInstanceOf)
         //   i, si té èxit, en caracteritza el tipus (asInstanceOf)
         aquell.isInstanceOf[LlistaImprimible] &&
             aquell.asInstanceOf[LlistaImprimible] match {
                     case LlistaNil () => this match {
                                                 case LlistaNil () => true
                                                 case _ => false
                                                 }
                     case LlistaCons (aquell_cap, aquella_cua) => this match {
                                                 case LlistaCons (aquest_cap, aquesta_cua) =>
                                                        aquest_cap == aquell_cap &&
                                                            aquesta_cua.igual_que( aquella_cua) ;
                                                 case _ => false
                                                 }   
                     }
         

}

// definició dels patrons // // en lleng. SML seria: // datatype 'tip_elem Llista = LlistaNil | LlistaCons of ('tip_elem * 'tip_elem Llista) // // en lleng. Haskell seria: // data Llista tip_elem = LlistaNil | LlistaCons tip_elem (Llista tip_elem) // class Imprimible a where // imprimeix :: a -> Unit // instance Imprimible (Llista tip_elem) where ... (implementació)

case class LlistaNil() extends LlistaImprimible ; case class LlistaCons[Tip_elem](cap: Tip_elem, cua: LlistaImprimible ) extends LlistaImprimible ;


object LaMevaApp extends Application {

 override def main(args : Array[String]) : Unit = {
   
   val llista1 = new LlistaNil() ;                           // val: assignable un sol cop
   val llista2 = new LlistaCons[AnyVal](1, llista1) ;        // AnyVal: qualsevol valor escalar (String exclòs)
                                                             // AnyRef: qualsevol per referència (inclou String)
   var llista = new LlistaCons[AnyVal](2.5F, llista2) ;      // var: assignable més d'un cop


   for (val v <- Iterator.range(4,9)) {       // de 4 a 9 exclòs el darrer
     llista = new LlistaCons[AnyVal]( v, llista)
   }
   llista.imprimeix ;
 }

}

</source>
# compilació a l'Eclipse: clicar al menú de context RunAs -> Run configurations 
#  -> doble-clic a Scala application -> New Configuration 
#  -> Ajustar el nom de l'objecte d'engegada (el que deriva de Application o conté el mètode main) 
#  -> prémer botó Run
 
# compilació en consola de comandes
cd objdir
scalac ../src/test/LaMevaApp.scala

# execució i resultat (cal cridar el nom de l'objecte que conté el mètode main o que deriva l'objecte Application).
scala test.LaMevaApp

8 7 6 5 4 2.50 1 Fi

Exemples a LiteratePrograms.org

Referències

Enllaços externs

Guies:

Exemples:

Recursos:

Articles: