Escolar Documentos
Profissional Documentos
Cultura Documentos
ScalaTutorial-pt BR PDF
ScalaTutorial-pt BR PDF
ScalaTutorial-pt BR PDF
Verso 1.2
18 de setembro de 2008
Michel Schinz
Philipp Haller
Traduo:
Marcelo Castellani
Thiago Rocha
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
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-definido 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.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.
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 especfico, que no nosso
exemplo ser a Frana 1 .
A biblioteca de classes Java define 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
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 identificador 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 definimos 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 fixa. Desta forma, a 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.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)))
Note que, para imprimir esta sentena, ns precisamos usar o mtodo println sem
a necessidade do uso de System.out.
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 flecha. 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 definio 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 mo2
Para evitar chateaes: sabemos que algumas linguagens orientadas a objeto no possuem o
conceito de classes, mas Scala no uma dessas.
5.1
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 especificado explicitamente. Ele ser definido 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.
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 definio de mtodos sem argumentos. Nossa classe Complex
pode ser reescrita como abaixo:
class Complex(real: Double, imaginary: Double) {
def re = real
def im = imaginary
}
obrigatrio especificar que o mtodo est sendo sobrescrito atravs do uso do modificador override, para evitar sobrescritas acidentais. Por exemplo, nosso cdigo da
classe Complex pode ser ampliado com a redefinio 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"
}
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)),
Esta notao define 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
simplificaria o programa se ns introduzirmos um nome para este tipo, o que permite modificaes 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 definir 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
11
uma nova operao fcil, precisando apenar defin-la como uma funo independente.
Para explorar bastante buscas de padres, vamos definir 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 definio:
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
Examinando a sada, ns podemos ver que o resultado da derivada deve ser simplificada antes de ser apresentada ao usurio. Definir uma funo de simplificao
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, definindo 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, definindo 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 definio 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 suficiente apenas definir os predicados que testam igualdade e inferioridade, e ento misturar o
cdigo de Ord classe. Como um exemplo, definiremos 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 definio da classe
Date como o seguinte:
class
def
def
def
14
Assim completamos a definio da classe Date. Instncias dessa classe podem ser
vistas como datas ou como objetos comparveis. Alm do mais, elas todas definem
os seis predicados de comparao mencionados acima: equals e <, pois eles aparecem diretamente na definio 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
9 Concluso
15
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 Specification 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