sexta-feira, 5 de abril de 2013

Scala para programadores Java

Você é um programador Java experiente, está sempre buscando conhecimento e novas formas de encontrar soluções. Uma forma de atingir este objetivo é aprender uma nova linguagem, preferencialmente com um paradigma diferente. Scala te chama atenção, por funcionar dentro da JVM, usar classes existentes do Java e por ser funcional, um paradigma que você ainda não conhece.

Então caro leitor temos muito em comum, na saga de estudar a linguagem e também o paradigma funcional, tive a oportunidade de receber a ajuda de um hacker amigo, @JonasAbreu. O coach do Jonas está sendo fundamental. Fui à minha primeira reunião dos ScalaDores, o grupo é bem avançado, portanto se você conhece bem Scala será um prato cheio, se está iniciando, também não tem problema, você acaba tendo um bom aproveitamento.

Uma grande questão é que você não gostaria de reaprender tudo que já sabe sobre programação, orientação a objetos e etc. Seria interessante se tivesse uma forma de aprender reaproveitando sua experiência, focando apenas nas novidades e de forma bem prática.

Pensando nisso, começo a partir deste post, fazer uma série para programadores Java interessados em aprender Scala. Abordarei tudo de forma muito prática e bem baseada em coisas que acho importante ou código que usei para alguma solução, MUITO DO CÓDIGO SERÁ AUTO EXPLICATIVO. Explicarei a teoria e detalhes quando o código não for tão obvio assim.

Para começar sugiro usar o interpretador de Scala no terminal. Instalar, iniciar o interpretador, tudo isso é bem fácil e já existe bons materiais, portanto não serão abordados aqui, ao menos nesse primeiro momento.

Vamos começar!

Variáveis
Para declarar uma variável basta fazer:

var nomeDaVariavel = valor


Note que diferente do Java não precisamos declarar o tipo da variável, isso porquê Scala consegue, muitas vezes, inferir o tipo declarado. Mas caso quisermos declarar o tipo, por questões de legibilidade por exemplo, podemos fazer:

var nomeDaVariavel : TipoDaVariavel = valor

Também podemos criar uma variável "final" como em Java, para isso declaramos:

Assim se você tentar atribuir um novo valor à variável idadeFinal receberá um erro:

error: reassignment to val

A variável "nome" é do tipo String, Scala não tem uma classe String então ela usa classe java.lang.String do Java. Já "idade" é do tipo Int (scala.Int) que é correspondente ao tipo primitivo int, que temos no Java. Scala tem tipos correspondentes para os tipos primitivos do Java, por exemplo scala.Float para float, scala.Char para char. Quando seu código é compilado em bytecodes o compilador tenta usar os tipos primitivos do Java por questões de performance.

Funções
Funções requerem uma atenção especial, pois podemos encontrar a mesma função declarada de várias formas, o que pode assustar de início, mas depois que aprendemos fica bem fácil.

Para declarar uma função:
def funcao(param : TipoParam) : TipoRetorno = {
  // corpo
}


Uma função que soma dois números:

Temos sempre de declarar o tipo dos parâmetros, a função recebe dois parâmetros do tipo Int e retorna também um tipo Int. Note que após a declaração do tipo de retorno vem um sinal de igualdade "=" e então as chaves "{}" que é onde deve ficar o corpo do método.

Em alguns casos* Scala consegue inferir o tipo do retorno da função, como é o nosso caso. Então podemos declarar a mesma função omitindo o tipo de retorno:

Como nossa função possui apenas uma linha podemos também omitir as chaves:

* Se nossa função for recursiva temos de explicitar o tipo de retorno.

Podemos declarar funções sem retorno também:

Neste caso Unit é o equivalente ao void do Java. Você pode omitir o retorno neste caso também:

Um pouquinho de características funcionais
Uma das principais características de linguagens funcionais é poder passar funções como parâmetros. Vamos a um exemplo bem prático disso, vamos criar uma classe Array e forneceremos uma maneira de executar um "processamento" em cada elemento do array.

Para isso precisamos definir nossa interface Funcao<T> que possui o método executaEm:


Agora podemos usar nosso Array. Vamos supor que temos um Array de String, com nomes de pessoas e queremos apenas imprimir o nome das pessoas em maiúsculo.

Ficou bacana. Mas repare que precisamos de uma interface classe Funcao<T> que possui apenas um método. Depois precisamos de uma implementar essa interface (no nosso caso por uma classe anônima), tudo para executar o processamento do método, podemos resumir tudo isso. Em Scala temos o recurso de funções anônimas ou "function literal" que tornam as coisas bem interessantes, o mesmo código acima pode ser escrito como:

nomes.foreach(nome => println(nome)) // existem outras formas de escrever essa linha, abordaremos futuramente
Imagine quantas APIs poderiam se beneficiar dessa abordagem. Lembre-se da API do AWT/Swing. Era muito improdutivo desenvolver listeners para nossos elementos de tela (botões por exemplo). Ao invés de escrever uma classe anônima, implementar um método e etc, se reproduzirmos a API em uma linguagem funcional,  podemos apenas passar uma função anônima como citado anteriormente.


Não se preocupe com relação ao código acima, voltaremos à essas características futuramente.