Você está na página 1de 15

Um tutorial de Scala

para programadores Java

Verso 1.2 18 de setembro de 2008

Michel Schinz Philipp Haller Traduo: Marcelo Castellani Thiago Rocha

P ROGRAMMING M ETHODS L ABORATORY EPFL S WITZERLAND

Introduo

Este documento visa dar uma rpida introduo a linguagem Scala e seu compilador. Ele dirigido a pessoas que realmente possuem alguma experincia em programao e desejam uma viso geral da linguagem Scala. Assumimos que voc possui conhecimento bsico em conceitos de orientao a objeto, especialmente em Java.

Um primeiro exemplo

Como primeiro exemplo usaremos o clssico Hello world. Ele no um programa fascinante, mas com ele ca simples de demonstrar o uso de ferramentas Scala sem falar muito da linguagem. Ele car como abaixo:
object HelloWorld { def main(args: Array[String]) { println("Hello, world!") } }

A estrutura deste programa deve ser familiar para programadores Java: ela consiste de um mtodo chamado main que recebe os argumentos da linha de comando, um array de string, como parmetro; o corpo deste mtodo consiste de uma chamada nica ao mtodo pr-denido println que recebe nossa amigvel saudao como argumento. O cdigo de main no retorna um valor, dessa forma no necessrio declarar um valor de retorno. O que no to familiar assim para programadores Java a declarao object que contm o mtodo main. Essa declarao introduz o que comumente chamado de objeto singleton, que uma classe que possuir apenas uma nica instncia. A declarao acima contri tanto a classe chamada HelloWorld quanto sua intncia, tambm chamada de HelloWorld. Esta instncia criada sob demanda, no momento do seu primeiro uso. O leitor mais astuto pode ter percebido que o cdigo do mtodo main no declarado como static aqui. Isso ocorre por que membros estticos (mtodos ou campos) no existem em Scala. Ao invs de usar mtodos estticos, o programador Scala declara esses membros como objetos singleton.

2.1 Compilando o exemplo


Para compilar nosso cdigo voc deve usar scalac, o compilador Scala. scalac funciona como a maioria dos compiladores: ele recebe um fonte como argumento e talvez algumas opes, e produz um ou mais arquivos objeto. Os arquivos objetos aqui produzidos so arquivos .class padro Java.

2.2

Rodando o exemplo

Se voc salvar o cdigo acima num arquivo chamado HelloWorld.scala, voc pode o compilar usando o comando abaixo (o sinal de maior > representa o prompt de comando e no deve ser digitado):
> scalac HelloWorld.scala

Isso ir gerar uma srie de classes no diretrio corrente. Uma dessas classes ser chamada de HelloWorld.class, e contm a classe que deve ser diretamente executada pelo comando scala, como ser mostrado a seguir.

2.2 Rodando o exemplo


Uma vez compilado, um programa Scala pode ser facilmente executado atravs do comando scala. Seu uso bem parecido com o do comando java, que usado para executar programas Java, e aceita as mesmas opes. O exemplo acima pode ser executado com o comando a seguir, que produz a sada esperada:
> scala -classpath . HelloWorld Hello, world!

Integrando com o Java

Um dos maiores poderes da Scala sua capacidade de integrao fcil com o Java. Todas as classes do pacote java.lang so importadas por padro, enquanto que todas as outras podem ser importadas explicitamente. Vamos ver um exemplo que demonstra isso. Ns precisamos obter e formatar a data corrente de acordo com a conveno usada num pas especco, que no nosso exemplo ser a Frana 1 . A biblioteca de classes Java dene um poderoso conjunto de classes utilitrias, como Date e DateFormat. Como Scala interage diretamente com Java, no existem classes equivalentes na biblioteca de classes Scala: ns simplesmente importamos os pacotes Java correspondentes:
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)
1

Outras regies como os falantes de francs em parte da Suia usam a mesma conveno

println(df format now) } }

O import da Scala bem parecido com o seu equivalente em Java, mas ainda mais poderoso. Multiplas classes podem ser importadas de um mesmo pacote atravs do uso de chaves, como na primeira linha. Outra diferena que quando desejamos importar todas as classes de um pacote usamos o sublinhado (underscore) (_) ao invs do asterisco (*). Isso ocorre por que o asterisco um identicador vlido em Scala (por exemplo, o nome de um mtodo), como veremos mais a frente. O import na terceira linha traz todos os membros da classe DateFormat. Isso faz o mtodo esttico getDateInstance e o campo esttico LONG diretamente visiveis. Dentro do mtodo main ns primeiro criamos uma instncia da classe Date do Java, que por padro contm a data atual. A seguir, ns denimos o formato da data usando o mtodo esttico getDateInstance, que importamos anteriormente. Finalmente, ns imprimimos a data atual formatada de acordo com a instncia localizada de DateFormat. Esta ltima linha mostra uma propriedade interessante da linguagem Scala: mtodos que recebem apenas um argumento podem ser usados com uma sintaxe no xa. Desta forma, a expresso
df format now

apenas outra forma menos extensa de escrever esta expresso


df.format(now)

Isto pode ser um detalhe menor da sintaxe, mas possui consequncias importantes, as quais sero exploradas com mais detalhes na prxima seo. Para concluir esta seo sobre integrao com Java, voc deve notar que possvel herdar a partir de classes Java e implementar interfaces Java diretamente em Scala.

Tudo um objeto

Scala uma linguagem orientada a objetos pura, no sentido de que tudo um objeto, incluindo nmeros e funes. Isso difere de Java, j que Java distingue tipos primitivos (como Boolean e Int) de tipos de referncia, e no permite que sejam manipulados funes como valores.

4.1 Nmeros so objetos


Como nmeros so objetos, eles podem ter mtodos. E, de fato, uma expresso aritimtica como a abaixo:
1 + 2 * 3 / x

4.2

Funes so objetos

consiste exclusivamente de chamadas de mtodos, por que ela equivalente a expresso abaixo, como vimos na seo anterior:
1.+(2.*(3./(x)))

Isso quer dizer que +, *, etc. so identicadores vlidos em Scala.

4.2 Funes so objetos


Por mais surpreendente que possa parecer para um programador Java, funes tambm so objetos em Scala. Isso possibilita passar funes como argumentos e outras funcionalidades interessantes. A possibilidade de manipular funes como valores um dos mais interessantes paradigmas da chamada programao funcional. Um exemplo muito simples de como isso pode ser til o uso de funes como valores, para isso vamos considerar uma funo do tipo timer que deve executar uma ao a cada segundo. De que forma passamos a ao para execuo? De maneira simples, atravs de uma funo. Esse simples uso de "passar uma funo" deve ser familiar para muitos programadores: usado em cdigos de interface de usurio, para registrar as funes de callback que devem ser chamadas quando algum evento ocorre. No exemplo a seguir, a funo de timer nomeada oncePerSecond, e recebe uma funo de callback como argumento. O tipo desta funo escrito como () => unit e este o tipo de todas as funes que no recebem argumentos e no retornam nada (o tipo unit similar ao void do C/C++). A funo main deste programa simplesmente chama essa funo de timer com uma callback que imprime uma sentena no terminal. Em outras palavras esse programa ir imprimir eternamente a sentena o tempo corre como um raio a cada novo segundo:
object Timer { def oncePerSecond(callback: () => unit) { while (true) { callback(); Thread sleep 1000 } } def timeFlies() { println("o tempo corre como um raio...") } def main(args: Array[String]) { oncePerSecond(timeFlies) } }

Note que, para imprimir esta sentena, ns precisamos usar o mtodo println sem a necessidade do uso de System.out.

4.2.1 Funes annimas


O cdigo anterior foi simples de entender, e podemos o renar ainda mais. Primeiro de tudo necessrio entender que a funo timeFlies denida apenas para ser passada como parmetro para a funo oncePerSecond. Nomear uma funo com esta caractersticas desnecessrio, sendo mais interessante construir essa funo no momento em que a passamos para a oncePerSecond. Isso possvel em Scala atravs do uso do conceito de funes annimas, que so exatamente o que parecem: funes sem nome. Uma verso atualiada de nosso programa de timer que usa uma funo annima no lugar de timeFlies pareceria com o abaixo:
object TimerAnonymous { def oncePerSecond(callback: () => unit) { while (true) { callback(); Thread sleep 1000 } } def main(args: Array[String]) { oncePerSecond(() => println("o tempo corre como um raio...")) } }

A presena de uma funo annima neste exemplo revelada pelo smbodo de => que separa os argumentos da funo de seu corpo. Neste exemplo, a lista de argumentos est vazia, o que pode ser visto pelo par de parenteses sem nada dentro a esquerda da echa. O corpo da funo o mesmo que tinhamos na extinta timeFlies, do exemplo acima.

Classes

Como vimos acima, Scala uma linguagem orientada a objetos, e dessa forma possui o conceito de classes.2 Essas classes, em Scala, so declaradas usando uma sintaxe muito parecida com a do Java. Uma das diferenas mais marcantes que classes em Scala podem ter parmetros. Isso ilustrado com a denio abaixo de uma classe para nmeros complexos:
class Complex(real: Double, imaginary: Double) { def re() = real def im() = imaginary }

Essa classe Complex recebe dois argumentos, que so a parte real e a parte imaginria de um nmero complexo. Estes argumentos devem ser passados no moPara evitar chateaes: sabemos que algumas linguagens orientadas a objeto no possuem o conceito de classes, mas Scala no uma dessas.
2

5.1

Mtodos sem argumentos

mento da criao de uma instncia da classe Complex, da seguinte maneira:


new Complex(1.5, 2.3)

A classe contm dois mtodos, chamados re e im, que do acesso a ambas as partes do nmero. Repare que o tipo de retorno desses dois mtodos no especicado explicitamente. Ele ser denido automaticamente pelo compilador, que olha os mtodos e deduz que o valor de retorno de ambos um Double. O compilador, porm, pode no estar sempre apto a saber qual o tipo de retorno, e no h uma regra simples para saber qual o tipo que ele efetivamente usou. Na prtica isso no um problema visto que o compilador sabe que s pode mudar o tipo que no foi explicitamente passado. Como uma dica, o programador iniciante em Scala devem tentar omitir tipos quando esses forem fceis de perceber no contexto, e ver como o compilador se comporta. Aps algum tempo o programador ter um bom feeling sobre que tipo pode ou no omitir.

5.1 Mtodos sem argumentos


Um pequeno problema dos mtodos re e im que, para os chamar, deve-se usar um par de parenteses vazios ao lado de seu nome, como pode ser visto abaixo:
object ComplexNumbers { def main(args: Array[String]) { val c = new Complex(1.2, 3.4) println("imaginary part: " + c.im()) } }

Seria interessante acessar a parte real e a parte imaginria como campos, sem a necessidade de colocar esse par de parenteses ao lado do nome. Isso pode ser feito em Scala atravs da denio de mtodos sem argumentos. Nossa classe Complex pode ser reescrita como abaixo:
class Complex(real: Double, imaginary: Double) { def re = real def im = imaginary }

5.2 Herana e polimorsmo


Todas as classes em Scala herdam de uma super-classe. Quando no informada de qual super-classe dever herdar, como no nosso exemplo Complex, usado por padro scala.Object. Desta forma possvel sobrescrever mtodos herdados da super-classe. Em Scala

obrigatrio especicar que o mtodo est sendo sobrescrito atravs do uso do modicador override, para evitar sobrescritas acidentais. Por exemplo, nosso cdigo da classe Complex pode ser ampliado com a redenio do mtodo toString, herdado da classe Object.
class Complex(real: Double, imaginary: Double) { def re = real def im = imaginary override def toString() = "" + re + (if (im < 0) "" else "+") + im + "i" }

Classes case e localizao de padres

Um tipo de estrutura de dados que costuma aparecer em softwares a rvore. Por exemplo, interpretadores e compiladores usualmente representam programas internamente como rvores; documentos XML so rvores; e diversos tipos de contineres so baseados em rvores. Ns agora iremos examinar como rvores so representadas e manipuladas em Scala atravs de um programa simples que simula uma calculadora. O objetivo deste programa manipular expresses aritmticas simples, compostas de somas, constantes do tipo inteiro e variveis. Dois exemplos dessas expresses so 1 + 2 e (x + x) + (7 + y). Ns precisamos primeiro decidir qual a representao que usaremos para as expresses. A mais natural uma rvores, onde os ns so as operaes (no nosso caso, adio) e o restante so os valores (no caso constantes e variveis). Em Java, uma rvore pode ser representada usando uma super-classe abstrata, e uma sub-classe concreta por sub-classes concretas. Em linguagens de programao funcionais ns podemos usar um tipo algbrico para o mesmo propsito. Scala possui o conceito de classes case que um meio termo entre ambos. Abaixo voc pode ver um exemplo onde denimos a rvore para nossa calculadora:
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

Perceba que, pelo fato das classes Sum, Var e Const serem declaradas como classes case, elas diferem de classes padro em vrios aspectos: a palavra chave new no necessria para criar instncias dessas classes (quer dizer que podemos escrever simplesmente Const(5) ao invs de new Const(5)),

6 Classes case e localizao de padres

funes do tipo getter so automaticamente denidas para os parmetros do construtor (por exemplo, possvel pegar o valor do parmetro v de uma instncia chamada c da classe Const apenas com c.v), a denio padro dos mtodos equals e hashCode so disponibilizadas, trabalhando com a structure das instncias e no com sua identidade. uma denio padro para o mtodo toString tambm disponibilizada, e imprime o valor na sua forma padro (por exemplo, a expresso x + 1 imprime Sum(Var(x),Const(1))), instncias dessas classes podem ser decompostas atravs de busca por padro como veremos mais a frente. Agora que ns temos denidos os tipos de dados que representam nossa expresso aritmtica ns podemos iniciar a denir os operadores para manipul-las. Nossas expresses iro iniciar com uma funo que ir avaliar a expresso em um ambiente. O objetivo do ambiente dar valores as variveis. Por exemplo, a expresso x + 1 avaliada em um ambiente que associa o valor 5 a varivel x, escreve {x 5}, dando 6 como resultado. Dessa forma temos que encontrar um jeito de representar ambientes. Ns podemos, claro, usar algumas estruturas de dados associativas, como uma tabela hash, mas ns podemos usar diretamente funes! Um ambiente nada mais do que uma funo que associad um valor a uma varivel. O ambiente {x 5} mostrado acima pode ser escrito como abaixo em Scala:
{ case "x" => 5 }

Esta notao dene uma funo que, quando recebe a string x como um argumento, retorna o inteiro 5, e gera uma exceo se for diferente disso. Antes de escrever a funo de avaliao deixe-me dar um nome ao tipo dos ambientes. Ns podemos, claro, sempre usar o tipo String => Int para ambientes, mas simplicaria o programa se ns introduzirmos um nome para este tipo, o que permite modicaes simples no futuro. Isso pode ser feito em Scala como mostrado abaixo:
type Environment = String => Int

A partir de agora o tipo Environment (ambiente) pode ser usado como um apelido para funes que vo de um String para um Int. Ns podemos agora denir a funo de avaliao. Conceitualmente ela muito simples: o valor de uma soma de duas expresses simplesmente o valor da soma dessas expresses; o valor da varivel obtido diretamente pelo ambiente e o valor da constante o valor da constante por s s. Expressar isso em Scala no mais difcil:

10

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 }

Essa funo de avaliao funciona realizando uma busca de padro na rvore t. Intuitivamente o signicado de algumas dessas denies pode car mais claro: 1. a primeira vericao da rvore t o Sum, ento criada uma sub-rvore auxiliar a esquerda numa varivel chamada l e uma sub-rvores numa varivel r, e ento segue com a avalio da expresso que est aps a echa; esta expresso pode (e faz) uso das variveis seguidas pelo padro que aparece antesda echa, l e r, 2. se a primeiraq vericao no for bem sucedida ento a rvore no um Sum, ento vericado se t um Var; se o ento ele anexa o nome contido em Var para uma varivel n e continua com a avaliao na expresso, 3. se a segunda vericao falha ento t no nem um Sum e nem um Var, ento ele verica se um Const, e se o for, ento ele anexa o valor contido no n em Const na varivel v e continua a vericao, 4. nalmente, se todas as vericaes falharem, uma exceo lanada para sinalizar a falha da busca por um padro; isso aconteceria aqui apenas se mais de uma sub-classe de Tree fosse declarada. Ns vericamos que a idia bsica da busca de padro tentar achar um valor numa srie de padres, e quando o padro encontrado, extrair e nomear as vrias partes do mesmo para, nalmente, avaliar um cdigo que tipicamente faz uso dessas partes nomeadas. Um programador experiente em orientaes a objetos pode car supreso por que no denimos eval como um mtodo da classe Tree e suas subclasses. Ns poderamos fazer isso sem problemas, visto que Scala possibilita a denio de mtodos em classes case assim como em classes normais. Decidir usar a busca por padro ou mtodos uma questo de gosto, mas isso possui implicaes importantes em relao a extensibilidade da aplicao: quando usamos mtodos ca fcil de adicionar um novo tipo de n, bastando para isto apenas den-lo em uma sub-classe da Tree; Em contrapartida, adicionar uma nova operao para manipular a rvore uma tarefa tediosa, pois isto requer modicaes em todas as subclasses de Tree quando usamos busca por padro a situao invertida: adicionar um novo tipo de n requer que modicao em todas as funes nas quais a busca por pado atua, para ter o novo n devidamente; Em contrapartida, adicionar

6 Classes case e localizao de padres

11

uma nova operao fcil, precisando apenar den-la como uma funo independente. Para explorar bastante buscas de padres, vamos denir outra operao com expresses aritmticas: derivao simblica. O leitor deve lembrar as seguintes regras referentes a esta operao: 1. a derivada de uma soma a soma de suas derivadas, 2. a derivada de qualquer varivel v um se v a varivel relativa na qual a derivao ocorre seno ser zero, 3. a derivada de uma constante zero. Estas regras podem ser traduzidas quase que literalmente para cdigo Scala, para obter a seguinte denio:
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) }

Esta funo introduz dois novos conceitos relacionados busca de padres. Primeiramente, a expresso case para as variveis possui uma proteo, uma expresso que segue a palavra-chave if. Esta proteo previne que a busca de padres tenha sucesso a no ser que esta expresso seja verdadeira. Aqui usado para ter certeza que retornaremos a constante 1 apenas se o nome da varivel que est sendo derivada o mesmo o mesmo da varivel de derivao v. A segunda nova funcionalidade da busca de padres usada aqui o caractere curinga, escrito como underline, no qual uma busca de padres de qualquer valor, sem precisar nome-lo. Ns ainda no exploramos todo o poder da busca de padres, mas iremos parar por aqui para manter este documento resumido. Ainda queremos ver como as duas funes acima funciona num exemplo real. Para este propsito vamos escrever uma simples funo main, na qual realiza vrias operaes sobre a expresso (x + x) + (7 + x): primeiro computado seu valor no ambiente {x 5, y 7}, para ento computar sua derivada relativa a x e ento 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")) }

12

Executando esse programa ns temos a sada esperada:


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)))

Examinando a sada, ns podemos ver que o resultado da derivada deve ser simplicada antes de ser apresentada ao usurio. Denir uma funo de simplicao bsica, usando busca de padres, uma problema interessante(mas surpreendentemente capcioso) e deixado como um exerccio para o leitor.

Mixins

Alm da herana de cdigo de uma superclasse, uma classe Scala tambm pode importar cdigo de um ou vrios mixins. Talvez a forma mais fcil para um programador java entender o que so mixins v-los como interfaces na qual podem tambm conter cdigo. Em Scala, quando uma classe sub-classe de mixin, ela implementa aquela interface mixin e herda todo o cdigo contido no nele. Para ver a utilidade dos mixins, veremos um exemplo clssico: objetos ordenados. Geralmente til ser capaz de comparar objetos de uma dada classe atravs delas mesmas, como por exemplo para orden-las. Em Java, objetos nos quais so comparveis implementam a interface Comparable. Em Scala ns podemos fazer um pouco melhor do que em Java, denindo nosso equivalente de Comparable como um mixin, no qual ns chamaremos de Ord Ao comparar objetos, seis diferentes predicados podem ser teis: menor, menor ou igual, igual, no igual, maior ou igual e maior. Contudo, denindo todos ele trabalhoso, especialmente considerando que quatro desses seis podem ser expressos usando os dois remanescentes, isto , dado os predicados igual e menor (por exemplo), um pode expressar os outros. Em Scala, todas estas observaes podem ser facilmente capturadas pela seguinte declarao do mixin:
trait def def def def } Ord { < (that: <=(that: > (that: >=(that: Any): Any): Any): Any): Boolean Boolean = (this < that) || (this == that) Boolean = !(this <= that) Boolean = !(this < that)

7 Mixins

13

Esta denio cria um novo tipo chamado Ord, no qual atua o mesmo papel da interface Comparable em Java e padroniza as implementaes dos trs predicados em termos de um quarto abstrato. Os predicados para igualdade e diferena no aparecem aqui pelo motivo de que so padres presentes em todos os objetos. O tipo Any que usado acima, um super-tipo de todos os outros tipos em Scala. Ele pode ser visto como uma verso mais geral do tipo Object em Java, mas tambm um super-tipo dos tipos bsicos como Int, Float, etc. Para fazer objetos de uma classe serem comparveis, mais do que suciente apenas denir os predicados que testam igualdade e inferioridade, e ento misturar o cdigo de Ord classe. Como um exemplo, deniremos uma classe Date, representando datas no calendrio gregoriano. As datas so compostas por um dia, um ms e um ano e so representados como inteiros. Comearemos a denio da classe Date como o seguinte:
class def def def Date(y: Int, m: Int, d: Int) extends Ord { year = y month = m day = d

override def toString(): String = year + "-" + month + "-" + day

A parte importante aqui a declarao de extends Ord que segue do nome da classe e dos parmetros. Isto declara que a classe Date uma sub-classe da classe Ord como mixin. Ns redenimos o mtodo equals que foi herdado de Object, ento ele comparar corretamente as datas, comparando seus campos individualmente. A implementao padro de equals no deve ser usada, pois como em Java ele compara os mtodos sicamente. Ns chegamos na seguinte denio:
override def equals(that: Any): Boolean = that.isInstanceOf[Date] && { val o = that.asInstanceOf[Date] o.day == day && o.month == month && o.year == year }

Este mtodo faz o uso dos mtodos j predenidos isInstanceOf e asInstanceOf. O primeiro, isInstanceOf, corresponde ao operador instanceof do Java e retorna verdadeiro se, e apenas se, o objeto no qual foi aplicado, uma instncia do tipo dado. O segundo, asInstanceOf, corresponde ao operador de cast do Java: se o objeto uma instncia do tipo dado, ele visto como tal, seno uma exceo ClassCastException lanada. Finalmente, o ltimo mtodo para denir o predicado no qual testa a inferioridade, como a seguir. Este faz uso de outro mtodo pr-denido, error, que lana uma exceo junto a dada mensagem de erro.

14

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))) }

Assim completamos a denio da classe Date. Instncias dessa classe podem ser vistas como datas ou como objetos comparveis. Alm do mais, elas todas denem os seis predicados de comparao mencionados acima: equals e <, pois eles aparecem diretamente na denio da classe Date, e os outros por causa da herana do mixin Ord. Mixins so teis em outras situaes a mais do que as mostradas aqui, com certeza, mas discutir todas as suas aplicaes est fora do escopo deste documento.

Generalizao

A ltima caracterstica de Scala que exploraremos neste tutorial a generalizao. Programadores Java devem estar bem prevenidos sobre os problemas causados pela falta de generalizao em sua linguagem, uma decincia que abordada no Java 1.5. Generalizao a habilidade de escrever cdigo parametrizado por tipos. Como exemplo, um programador escrevendo uma biblioteca para listas encadeadas encontra o problema de decidir qual tipo dar para os elementos da lista. Desde que esta lista foi concebida para ser usada em diferentes contextos, no possvel decidir que o tipo dos elementos tero de ser, por exemplo, Int. Isto pode ser totalmente arbitrrio e muito restritivo. Programadores Java contornam isto usando Object, que o super-tipo de todos os objetos. Contudo, esta soluo est longe da ideal, desde que no funcionar para os tipos bsicos (Int, Long, Float, etc.) e implicando que vrios type casts tero de ser inseridos pelo programador. Scala torna possvel denir classes (e mtodos) genricos para resolver este problema. Vamos examinar isto com um exemplo do container de classe mais simples possvel: uma referncia na qual pode ser vazia ou apontar para um objeto de algum tipo.
class Reference[a] { private var contents: a = _ def set(value: a) { contents = value }

9 Concluso

15

def get: a = contents }

A classe Reference parametrizada por um tipo, chamado a, que o tipo do seu elemento. Este tipo usado no corpo da classe como o tipo da varivel contents, do argumento do mtodo set e do tipo de retorno do mtodo get. O exemplo do cdigo acima mostra variveis em Scala que no precisamos explicar mais. Contudo interessante ver qua o valor dado inicialmente para a varivel _, que representa o valor padro. Este valor padro 0 para os tipos numricos, false para o tipo booleano, () para o tipo unit e null para todos os tipos de objetos. Para usar esta classe Reference, alguem precisa especicar qual o tipo para se usar no parmetro de tipo a no qual o tipo contido pela clula. Como exemplo, ao criar e usar uma clula guardando um inteiro, algum deve escrever assim:
object IntegerReference { def main(args: Array[String]) { val cell = new Reference[Int] cell.set(13) println("Reference contains the half of " + (cell.get * 2)) } }

Como pode ser visto no exemplo, no necessrio fazer cast no valor retornado pelo mtodo get antes de us-lo como um inteiro. Tambm no ser possvel guardar nada alm de um inteiro naquela clula particularmente, pois foi declarada para guardar um inteiro.

Concluso

Este documento apresenta uma rpida viso geral da linguagem Scala com alguns poucos exemplos. Caso deseje aprofundar-se mais recomendamos que leia o Scala By Example, que possui muito mais exemplos, e consulte a Scala Language Specication quando necessrio.

10

Sobre a traduo

Este documento foi traduzido por Marcelo Castellani e Thiago Rocha, membros da lista de discusso Scala-Br. Para participar visite a pgina a seguir:
http://groups.google.com/group/scala-br

Você também pode gostar