Depois do talk não acontecer (veja posts anteriores), resolvi disponibilizar no Slideshare toda a apresentação que seria utilizada no evento, e que provavelmente usarei numa próxima oportunidade:

Por enquanto é isso. Ainda devo continuar em estudos profundo so bre SOA Security por mais tempo, uma demanda do trabalho. Mas falou em estudar, é comigo mesmo!!! :)

Espero voltar em breve falando de Scala já na versão 2.8, agora com Continuations e Named Arguments, o que vai deixar essa linguagem simplesmente imbatível de uma vez por todas. Até a próxima!

Update: Se você não consegue ver os slides no seu leitor de feeds, clique aqui.

É pessoal, o talk não aconteceu por alguns motivos particulares na empresa. Mas ainda temos a esperança de conseguir agendar uma data para o evento.

No final, a possibilidade do talk me rendeu material para apresentação sobre a linguagem (Scala) numa próxima oportunidade :)

Tenho estado sumido ultimamente pois algumas atividades no trabalho exigiram um estudo mais focado sobre o tema (SSO, SAML, WSS). Por isso pisei um pouco no freio na minha vertente de estudo de novas tendências. 

Ainda assim consegui ler bastante sobre RabbitMQ (implementação do Advanced Message Queue Protocol – AMQP), e fiquei realmente interessado.  A propósito o RabbitMQ foi o broker utilizado no Twitter por um tempo, e por conta de uma necessidade particuliar, eles acabaram desistindo do uso. Mas o RabbitMQ não vai ficar atrás, e nas próximas versões disponibilizará a feature. Veja a discussão entre Alex Payne (Twitter) e Alexis (RabbitMQ) aqui, e veja aqui o que o Robey (Twitter) fez pra atender as necessidades deles.

Detalhe: o Lift sempre deu suporte ao Rabbit e eu não sabia o.O!

Dediquei um pouco (pouco mesmo) de tempo a uma outra linguagem funcional chamada Clojure. A brincadeira começou justamente enquanto preparava os slides para o talk (#fail) e tive que ler bastante sobre Lambda Calculus (de onde vem a FP). O gostoso do Clojure é a encarnação do Lambda Calculus como ele é, numa syntax Lisp. Aqui você pode brincar um pouco com a linguagem; um “console” on line. Ah! E dá pra brincar com outras linguagens também como Scala e até OCaml :)  

Bom, no final vi um pouco sobre Compojure, um framework web pra Clojure muito irado.

Por enquanto é só. Estou pensando em abordar mais tópicos sobre Scala, pois ainda há muito o que falar sobre os recursos e características da linguagem com Actors, Extractors, Pattern Matching, Lists e mais. Aguardem!

 

AccurTalkEm breve, eu e alguns colegas de trabalho faremos um talk na empresa.
O objetivo é apresentar ao restante da companhia, as algumas inovações tecnológicas que cada um vem estudando nos últimos meses.
Dentre elas, Groovy/Grails, CEP, SOA, Terracotta e um talk sobre Scala apresentado por mim.
Para o exemplo usado, Scala X-Ray vai ajudar a ilustrar o uso da linguagem: http://is.gd/tmFg

Acompanhe! ;)

obs: logo não oficial.

No último Post, confesso que estava bem extasiado com o CouchDB. Acho que deu pra perceber. Então veio a brilhante ideia:

Vou fazer algo pra mapear JSON – Objetos – JSON em Scala e junto com isso, fazer uma forma mais transparente de interagir com o Couch.

Acontece é que eu e umas 8 mil pessoas tivemos esta mesma idéia, claro. :(

Antes de constatar que outros estavam fazendo o mesmo, e enquanto tentava construir algo, me veio uma questão:

Is CouchDB best suited for dynamic languages?

Na verdade eu deveria ter perguntado: Are dynamic languages best suited for CouchDB? Enfim… de qualquer forma me entenderam e tive o prazer de receber a resposta do Jorge Ortiz, que fez uma grande contribuição pra nós Scaladores. esta semana. Ortiz criou um conjunto de classes e funções utilitárias para tornar a programação Java/Scala ainda mais  fácil.

Em sua resposta, Ortiz  dizia não só que linguagens estaticamente tipadas – como Scala – são perfeitamente candidatas a trabalhar como um banco de dados schema-free, mas também me mostrou alguns materiais.  Lá, estava  o blog do @n8han, o Coderspiel, onde n8han (criador do Wichet Databinder) mostra sua habilidade com Scala, CouchDB, Twitter API, além de fazer exatamente o que eu tinha proclamado fazer no meu post anterior.

Nathan (n8han), criou uma pequena API chamada Dispatch que facilita iterações sobre Http, agindo como um Wrapper para o Apache HttpClient, facilita a iteração com o CouchDB, e de maneira inusitada e muito interessante, utiliza Symbols e Extractors em Scala para fazer o mapeamento JSON – Objeto – JSON. Breve postarei uns exemplos utilizando Couch + Scala + o Dispatch.

Um ponto negativo da API do @n8han é que ele até agora forneceu pouco, ou quase nenhum exemplo prático/real de como usar sua API. E como ele construiu tudo utilizando recursos como Extractors e muito Pattern Matching em Scala, deu um grande trabalho pra entender como as coisas funcionavam, pois as funções implementadas por ele quase nunca declaram o tipo de dados retornado. Daí o trabalho de ler e tentar entender o código das funções pra detectar que tipo de objeto ela pode retornar. Se não fosse pelo eclipse, eu estaria até agora tentando entender. :P

Ainda assim, o Dispatch do n8han me permitiu bons momentos de diversão com o SBT (Simples Build Tool) e com o GIT. Depois pretendo falar sobre isso.

Outros caras como o @frank06 e Debasish Ghosh também estão engajados em temas desse tipo, e aqui você pode ver uma palavrinha dos dois neste post – super atual, por sinal – do Alexander Lag.

Alexander até  postou no Slideshade, sua apresentação no  Scotland on Rails, onde ele mostrou alguns frameworks em Ruby para trabalhar com o CouchDB. E para me desanimar de vez, ele não mostrou um, mas meia-dúzia de frameworks pra Ruby com objetivo de facilitar mapeamento JSON – Objeto – JSON e interagir com o CouchDB. Ou seja, por que estou gastando meu tempo tentando fazer algo assim? :) Se gastar, terei que fazer algo muito melhor e revolucionário.

Dos frameworks mostrados, o Active Couch realmente me surpreendeu, e vai surpreender muita gente que trabalha com Ruby on Rails, permitindo um modelo de dados mais uniforme entre objetos persistidos em uma base relacional e no Couch. De certa forma foi bom pra dar umas boas ideias.

Mas foi aí que o Debasish Ghosh entrou no circuito, complementando o que o Alex Lang vem pregando.
Debasish falou sobre Convenience over Correctness. A prerrogativa é que o Active Couch fornece uma forma tão semelhante de trabalhar com mapeamento de dados em relação ao Active Record que, pra Debasish, programar assim é usar a conveniência. A conveniência do programador conviver com o Framework de estimação sempre.

Debasish fala ainda que consequencia disso é a inércia que o uso de frameworks nos traz, nos deixando comodamente casados com ele (o framework), tal que nos colocamos cegos diante de novos paradigmas e abordagens que fazem o nosso bom e velho parceiro/framework de estimação parecer irrelevante.

Debasish se pronunciou, e com muita propriedade no que disse, pois o Active Couch tenta colocar no uso do CouchDB algo que ele não é: relação entre registros de entidades/tabelas diferentes como se os dados tivesse sido armazenados numa base relacional. Por isso a conveniência do Active Record e a forma “não correta” de tabalhar com o CouchDB, que é schema-free por natureza.

Debasish cita o CouchRest, que permite construções utilizando a mesma semântica do CouchDB: Views com funções do tipo Map-Reduce, e não operações find, find-by para iteragir com os documentos do Couch. Esta sim é uma forma que me inspirou, talvez um port pra Scala seja uma boa saída.

Aproveitando a visão do Debasish sobre deixar a conveniência de lado e procurar a “corretude”, eu penso que trabalhar de forma mais livre com objetos de domínio no CouchDB (em Scala) talvez seja uma alternativa a se considerar. Forma mais livre pode significar não ter propriedade statica alguma no objeto em tempo de desenvolvimento, e sempre obtê-las com um:


get[T]("propertyName")
//ou ainda:
with[T]('propertyName) { //doSomething }
//E mais além, onde m seria um map,
//ou objeto json detentor dos valores:
 def -:[T](s: Symbol)(op: T => Unit) = { op(m(s).asInstanceOf[T])}
// o uso poderia ser:
-:[Int]('age){ n => println("the age is " + n )}
//the age is 26
//Mas ainda dá pra fazer melhor
//se extendermos o Dispatch.
//Estou trabalhando em exemplos com o Dispatch.

Exato, pode soar como um grande Map, ou com o Delphi, mas sem ser exatamente um Map, tão pouco programar em Delphi.

É isso! Este post é como um resumo do que tenho lido, pensado e discutindo com pessoas ao redor do mundo.

Para complementar, tenho analisado com um amigo sobre a possibilidade do uso do CouchDB ou o MongoDB para armazenar logs/auditoria na empresa em que ele trabalha. Outra base não relacional na mira é o Voldemort.

Este final de semana não postei nada por ter utilizado ele pra estudar Erlang ;) e recrusos avançados de Pattern Matching em Scala.

Vamos vendo o que acontece daqui pra frente.

Muito se tem falado em bases de dados não relacionas. Então, desde que comecei a ler sobre o Dynamo da Amazon e o Big Table do Google me interessei pelo tema.

De fato, uma Base de Dados Relacional não é a bala de prata da persistência de dados. Existem muitas situações onde uma abordagem livre de schema, orientada a documentos ou chave-valor é mais conveniente.

A verdade é que ultimamente eu e muitos amigos discutimos bastante sobre o por quê de certas coisas dentro da tecnologia de desenvolvimento de software, e uma delas é a “obrigatoriedade” de persistir dados no que se tornou padrão pra aplicações corporativas: Bases de Dados Relacionais. Existem outros questionamentos sobre a natureza estatica da web e a escravidão que nos sujeitamos ao usar certas tecnologias. Mas isso é outro tema.

O post de Dion Hinchcliffe foi o que faltava motivação para estudar uma base não-relacional. A escolhida foi o Apache CouchDB, depois que Ted Neward opinou sobre o Book of JOSH, que compartilhei no meu Reader esta semana. Ted sugeriu o Couch como mecanismo de persistência na pilha Json Osgi Scala e Http.

CouchDB

O CouchDB é orientado a documentos expressos no formato JSON, e o mais interessante é que ele é acessado via HTTP por uma API REST. A princípio também soou estranho pra mim.

O CouchDB conta com algumas libs (construídas por terceiros) que evitam invocações HTTP “manualmente” para diversas linguagens. Dentre as linguagens encontramos Java, Ruby, PHP, Erlang, e até Javascript. Que tal persistir direto do seus formulário HTML usando Javascript? Não vejo mal algum. Alias, as receita de bolo 3 e 4 camadas para a construção de aplicações tendem a se tronar mais raras com o fortalecimento do SOA, das próprias bases de dados não-relacionais dentre outros fatores. Veja o post do Dion.

Instalei o Couch no meu Ubuntu 8.04 com sucesso seguindo este passo-a-passo (observe um comentário no final do post, é o que faz funcionar corretamente) e comecei a brincar usando CouchDB4J e o Futon, uma especie de console Web muito legal.

Obviamente iniciei meus teste com um objeto Person de todos os meus posts :) . Que em JSON vira:

{"_id":"4b32206602c372304530a69813a7a0ae","_rev":"741003815","name":"Paulo","age":"26","type":"Person"}

O Couch não possui tabelas, ou seja, todos os documentos são tratados igualmente, por isso adicionei uma propriedade type pra facilitar a criação de Views no Couch. O _id foi fornecido pelo próprio Couch, nos livrando da preocupação de um identificador único, _rev é a revisão do documento, que se alterado ganha um novo valor neste campo junto com as alterações. As revisões permitem enchergarmos um mesmo documento em pontos distintos no tempo.

As Views são o recurso mais interessante do Couch, e permitem a aplicação de funções Map/Reduce nos documentos. O que isso quer dizer? Quer dizer que é possível construir consultas e relatórios com os documentos e até mesmo junções. Views são armazenadas em documentos, que devem possuir no seu identificador o valor _design/ como prefixo . As Views são então armazenadas no campo views deste documento.

Aqui um documento que define três Views de exemplo:

{"_id":"_design\/pview",
 "_rev":"713212252",
 "views":{
       "by-name":{
           "map":"function(doc) { if (doc.type == 'Person') emit(doc.name, null) }"},
       "by-age":{
           "map":"function(doc) { if (doc.type == 'Person') emit(doc.age, null) }"},
       "teens":{
           "map":"function(doc) { if (doc.type == 'Person' && doc.age <= 18) emit (doc.name, null) }"}
  },
 "language":"javascript"}

As views foram escritas em Javascript, mas podem ser escritas em Ruby e Erlang também. Ao acessar http://localhost:5984/mydb/_view/pview/teens, que retorna o nome dos documentos de type Person menores de 18 anos, o resultado é:

{"total_rows":1,"offset":0,"rows":[
{"id":"1f8630284bbe5912a32990908933f00b","key":"Gabriel","value":null}
]}

Bem, a intenção do post não é mesmo fazer uma mega introdução, nem um tutorial sobre o CouchDB, mas sim  anunciar que a partir de agora você não vai encontrar apenas posts sobre Scala, mas também sobre essa maravilha criada por Damien Katz

Como pontapé inicial, comecei a escrever uma pequena lib pra facilitar o mapeamento de um objeto em scala
para documentos JSON, para então fazer comunicação com o Couch. Você pode dizer, por que não usar o
CouchDB4J? A princípio para que Scala possua um lib para este fim construída em Scala.

Aqui vai uma prévia. Mas comecei a escrever de uma forma desordenada e sem muito planejamento e devo recomeçar.
Os primeiros testes já funcionam, mas não achei muito bonito:


class JSONPerson(n: String, a : Int) extends Person(n, a) with JSONifier {

  property("name"){
    mapsTo (name) (name = _)}

  property("age") {
    mapsTo (age.toString)( (n) => age = Integer.parseInt(n))
  }

  metaProperty("type", "Person")

}

Lembrando que Person possui apenas dois atributos (name, age), a propriedade type se comporta como uma meta-propriedade que ajuda na hora das Views. Ou seja, a função property recebe a chave da propriedade e  um objeto que deve conhecer como ler  e gravar a propriedade, respectivamente. Pra isso a função mapsTo foi usada pra gerar este objeto, recebendo como parâmetro as duas funções de leitura/escrita.

Para gerar um Document (do CouchDB4J) basta usar a função json da trait  JSONifier e então usar o CouchDB4J (por enquanto) para salvar o documento. É um misto de DSL que permite mapear Objetcts2JSON/JSON2Object em Scala com a criação de uma lib para se comunicar com o Couch. De repente não vai ser necessário criar uma forma de mapear os objetos pra JSON, e sim uma forma mais conveniente de usar o proprio XStream, ou o JSON-lib.

É isso. Estou avaliando a viabilidade disso e o quanto vale a pena fazer tal coisa, enquanto isso aguarde mais coisas sobre CouchDB e Scala, e claro, relaxe.

Isso, mais uma vez vamos falar do Scala, Scala, Scala. Este post rendeu. E rende até hoje pequenas discussões interessantes com amigos.

A diferença agora é que resolvi fazer a mesma coisa usando Java 1.5 com o auxílio da API Functional Java, que promete deixar o Java 7 com uma cara bem característica de Scala. Isso por conta da adição de Closure e outras características funcionais.

A API Functional Java vem sendo criada por Tony Morris, e pelo pouco que pude fuçar, está ficando bem interessante.

Eu não quero parecer tão ingrato com Java, afinal é a linguagem/Plataforma que garante o pão nosso de cada dia. Por isso vamos aos mesmo exemplo com esta tão querida linguagem que está tentando acompanhar a onda funcional:

1. Obter o quadrado de cada elemento em um List de 1 a 5.


import static fj.data.List.list;
import fj.F;
import fj.data.List;
//Observe os imports

private static final List&amp;lt;Integer&amp;gt; numbers = list(1, 2, 3, 4, 5);
//... aqui começa nosso método main

		List<Integer> c = numbers.map(new F<Integer, Integer>() {

			public Integer f(Integer arg) {

				return arg * arg;

			}

		});

		System.out.println(makeString(c, ",")); // {1,4,9,16,25}

A função map também está disponível na API, o que facilita muito. Note que o código é identico, o que muda é a verborágica syntax Java. ;) (Também é possível fazer com foreach de List que é outra opção quando não se quer criar uma segunda lista com os resultados).

2. Imprimir os elementos maiores que 3.


		List<Integer> gt3 = numbers.filter(new F<Integer, Boolean>() {

			public Boolean f(Integer arg) {

				return arg > 3;

			}

		});

		System.out.println(makeString(gt3, ",")); // 4,5

A API não possui a função reduceLeft nem reduceRight, mas podemos alcançar um resultado semelhante usando uma função que compõe as funções de reduce: folding. Aqui temos o foldLeft, uma função aplicada da esqueda para a direita para cada resultado esquerda operação direita. ou seja: 1 + 2 = 3 + 3 = 6 + 4 = 10 + 5 = 15 + 0, zero é o segundo argumento de fold. Mas sinceramente, fazer isso sem a promessa do Java 7 chega a ser cansativo. :(

Continuando com o último exemplo temos:

3. Soma de todos os elementos.


		final int b = numbers.foldLeft(new F<Integer, F<Integer, Integer>>() {

			public F<Integer, Integer> f(final Integer i) {

				return new F<Integer, Integer>() {

					public Integer f(final Integer j) {

						return i + j; 

					}

				};

			}

		}, 0);

		System.out.println(b); // 15

Filter e os métodos de 1 e 2 recebem um objeto do tipo F, que é uma interface com um único método chamado f, cuja implementação é por nossa conta.

Ah! o makeString é só um método statico para adicionar uma ‘,’ entre os elementos do list. Na listagem completa deste post você pode conferir este método que foi feito usando recursividade de uma forma bem exagerada pra fazer essa simples tarefa. Mas mostra como declarar funções dentro de funções faz muita falta em Java. Digo isso por que a função subMakeString não faz sentido algum sem a função printipal makeString, tornando nossa classe de exemplo com métodos sem muito nexo. A verdade é que fica bem ruim pra fazer certas coisas.

Construções desse tipo (com classes anônimas) já vem sendo usada há muito tempo, e eu particularmente gosto muito e uso, mas é cansativo de escrever tanta coisa, sem falar que em muitas situações é complicado para ler e entender o que se passa.

Resumindo, podemos construir uma ou outra coisa funcional com Java, e com auxílio de APIs como estas a coisa se torna mais interessante. Mas a syntax sempre vai nos surpreender negativamente como a grande vilã e o grande impecílio para o comportamento funcional em Java puro.  Além disso, note que os exemplos não são identicos, pois se fossem identicos, teriam muuuuuuuuito mais código. E afinal, vale a pena? Até que ponto esta linguagem suporta programação funcional se ela não se tornar de fato uma linguagem hibrida OO/Funcional?

O pessoal do Java tem que correr, pois muito se tem questionado a respeito da linguagem Java, do quanto ela já evoluiu e do quanto ela ainda poderá (?) evolir. Talvez, transformando a liguagem, ela ainda permaneça outa década no mercado, caso contrário, vamos continuar a assistir grandes sistemas sendo construídos em outras linguagens.

Dê uma olhada nesta API, os métodos para manipulação de lista com um pensamento funcional podem ajudar muitosuas  soluções no dia-a-dia.

Post curto outra vez enquanto nos recuperarmos de um outro mais longo que fiz duas semanas atrás.

O título Igualdade foi uma referência ao inglês Iquality, que traduzindo pra programação, é um ponto de falha extremamente comum entre programadores Java, sejam principiantes, sejam veteranos.

Voltemos à nossa classe Person, dessa vez em Java:


public class Person {

	private String name;

	public Person(String name) {
		this.name = name;
	}

	public String getName() {
		return this.name;
	}

	@Override
	public boolean equals(Object obj) {
		return this.name.equals(((Person) obj).getName());
	}

	public static void main(String[] args) {
		Person p1 = new Person("Yo mismo");
		Person p2 = new Person("Yo mismo");
		System.out.println(p1 == p2); //false
		System.out.println(p1.equals(p2)); //true
	}
}

O método equals foi sobrescrito em Person para permitir comparações entre dois objetos do tipo Person. Assim, se dois objetos Person com um mesmo valor para nome forem comparados, a invocação de equals deve ser verdadedeira. Mas note que ao fazermos o uso do operador ==, temos um resultado negativo.

Tudo bem, já sabemos que o operador == da linguagem Java irá comparar as referências, e não seus valores, ainda que sobreescrevamos o método equals. É por isso que sempre que desejarmos comparar a igualdade de dois Person, temos uma forma não intuitiva de comparação utilizando equals, humanamente falando. É verdade que temos que ficar bastante atentos para evitar grandes dores de cabeça por conta de equals/==.

E como Scala resolve esta questão? Vamos à mesma classe Person, agora em Scala:


//A gigante classe person
class Person(val name: String) {
	override def equals(that: Any) = name == that.asInstanceOf[Person].name
}
//Objeto que usa a classe Person
object Main{
	def main(args: Array[String]) = {
		val p1 = new Person("Yo mismo")
		val p2 = new Person("Yo mismo")
		println(p1 == p2) //true
		println(p1 equals p2) //true
                println(p1 eq p2) //false
	}

Calma, não tem trecho de código faltando, esta classe é equivalente à escrita logo acima em Java. Exceto pelo uso de parametric fields, que por hora vamos entender como um parâmetro de uma classe, que ao ser definido com um val ou var, se torna membro público desta classe. Ver post longo para mais sobre classes parametrizadas.

O modificador override é utilizado de forma semelhante à annotation @Override para equals. Aqui, o compilador infere que o tipo de retorno do método deve ser Boolean, pois a última operação (e única) do método é uma comparação entre o name da instância alvo e o nome de that. Veja também um cast de that para Person, permitindo-nos alcançar a propriedade name.

Abaixo, temos o nosso método main invocando a mesma sequencia de operações que o trecho Java além de uma invocação a um méto chamado eq. A grande diferença a ser notada na realidade é a invocação do método == de p1 que retorna TRUE. Este método é  originado de AnyRef, a classe mãe de todas as referências em Scala (semelhante a Object em Java).

Além de não ser um operador nativo, o que dá uma cara mais orientada à biblioteca para a linguagem, o método == é um alias à invocação x.equals(arg0), construído sob o conceito de relação de equivalência matemática. Ao fornecermos uma implementação customizada para equals como neste caso, devemos garantir que este métodos se comporte como uma equivalência matemática para então compararmos nossos próprios objetos Person de mesmo nome com o método == e obter um retorno verdadeiro ao invés do surpreendente e intrigante false.

Note que a comparação entre dois objetos do tipo Person é delegada para a comparação entre seus nomes, que são do tipo String. Diferente de java, duas Strings ou qualquer outra coisa com mesmos valores tem retorno verdadeiro para invocações de ==. E isso garante a nossa igualdade entre p1 e p2.

O código em Scala ainda traz a invocação de um terceiro método, o método eq. Este se destina exclusivamente a comparar referências. Logo, temos uma opção clara, à prova de equívocos e sob nosso controle para comparação de valores ou de referências. O método eq, além de obedecer ao conceito de relação de equivalência, adiciona três outras características ao seu comportamento que são:

  • Para toda instância diferente de null de x e y do tipo AnyRef, multiplas invocações de x.eq(y), devem retornar consistêntemente true, ou consistêntemente false.
  • Para toda instância diferente de null de x do tipo AnyRef, x.eq(null) e null.eq(x) devem retornar false.
  • null.eq(null) retorna true.

De fato, é muito natural entender que dois objetos iguais possam ser comparados com ==, evitando qualquer dúvida. Tudo agora vai depender da necessidade em questão. Quer comparar o conteúdo lógico, valores, etc, use o ==. Quer comparar referências, use eq.

Se quiser matar a curiosidade sobre comparações numéricas, as chamadas Value Classes, clique aqui.

O fonte da classe Java você encontra aqui, e o da classe Person aqui. Boa diversão!

Obs: Este post não cobre todas as características de Any, AnyRef, ou AnyVal. Além disso é importante observar sempre as questões envolvendo hashCode quando fazemos nossa própria implementação  de comparação.

Acessando a principal fonte sobre a linguagem.
E quer começar a brincar de verdade? Instale o Scala Plugin para a IDE de sua preferência. Eu particularmente me dei muito bem com o plugin para NetBeans, até por que achei a parte de debug um mais completa.

Faça um teste! Nada melhor que um código bem colorido e code completation para começar.

Seguindo o classico, vamos ao básico de XML com Scala.

O objetivo deste post é apresentar o básico do uso de XML em Scala, e aproveito o ensejo para falar sobre algumas outas características muito úteis da linguagem como traits e for comprehensions.

Scala integra na linguagem á syntax XML, ou seja, para construirmos um elemento XML conforme listagem abaixo, não é preciso mais que atribuir este mesmo bloco XML a uma variável:


<person>
     <name>Caro</name>
     <age>21</age>
</person>

val person =
<person>
           <name>Caro</name>
           <age>21</age>
      </person>

Este código atribui um scala.xml.Elem à variável person. Mas, muito comumente a intenção é produzir um xml a partir de um objeto.

Considere a classe Person:


class Person(n: String, a: Int) {
   val name = n; val age = a
   def this(n: String) = this(n, 18)
}

Aqui, vamos aproveitar e observar o “;” no código. Neste caso, existem duas atribuições  numa única linha, e por val age = a ser uma atribuição, esta deve ser separada da atribuição anterior. Scala define algumas regras pra o uso, ou não, de ponto e vírgula(;).

A classe Person define 2 parâmetros, n e a, que representam os valores para o nome e a idade de Person. Parâmetros por que Scala considera uma classe parametrizável desse jeito. Os valores de n e a estão disponíveis no scopo da classe, mas como iremos acessar estes valores externamente, atribuimos os parâmetros n e a para dois atributos públicos: name e age, de tipos String e Int respectivamente, devidamente inferidos pelo compilador a partir dos tipos de n e a. Esse pequeno detalhe já deixa o código mais limpo e menos repetitivo.

E como sabia que a maioria vai se pensar : e se quisermos um construtor que só recebe o nome, e para a idade um padrão seja assumido?

A resposta está na linha 3. Esta é a notação de scala para um construtor que recebe um único parâmetro. Novamente utilizo this para invocar o “construtor padrão”, ou seja, a inicialização da classe com os valores n e 18.

Agora, pra tornar as coisas mais interessantes, vamos definir uma trait que possui duas funções:  xml e toString.


//importe do pacote xml.
//em java seria import scala.xml.*
import scala.xml._
//nossa trait
trait Xmlable {  

	def xml : NodeSeq 

	override def toString () = new PrettyPrinter(80,5).formatNodes(xml)

} 

//instanciando um Person com a trait
val p = new Person(n,a) with Xmlable {
    def xml =
<person><name>{name}</name><age>{age}</age></person> } 

println (p) /* imprime o resultado:
<person><name>Caro</name><age>21</age></person> */

Uma trait é um misto de Inferface e Abstract Class, pois nela definimos uma função abstrata (xml) e sobrescrevemos a função toString, que assim como em Java, todo objeto em Scala possui. Esta função é definida em AnyRef. Uma trait também possibilita um comportamento semelhar a herança múltipla, pois podemos tranquiliamente instanciar um Person with Xmlable with OtherTrait with EvenAnotherOneTrait, etc.

A função toString faz o uso da classe utilitária PrettyPrinter para formatar o xml.

A intenção é não embarcar estaticamente na classe alvo (Person), o comportamento de se transformar em xml. Logo, ao instanciarmos uma pessoa, informamos que aquele objeto será um Xmlable. A partir deste ponto o objeto Person passa a ter um comportamento de Person e de Xmlable, mesmo que nossa hierarquia inicial não tenha indicado Person como descendente de Xmlable.

A função xml da trait é como um método abstrato numa classe ou interface em java. A diferença é que, em Scala, se não informamos a implementação para um método numa trait, o compilador infere que aquilo é um método abstrato e deve ser implementado na subclasse, sem que tenhamos que indicar modificadores do tipo abstract na classe ou no método. Nossa implementação do método xml fica no ato de instanciar Person with Xmlable.

Ainda na listagem anterior, invocamos uma função xml em person que nos dá o resultado de um Person convertido em xml. Simples?

Bom, ao  instanciarmos um Person, não seria uma boa ideia informar o xml toda vez. Scala fornece um tipo especial de objeto, que é um singleton por natureza. E quando usamos um singleton em conjunto com a classe (utilizando inclusive o mesmo nome), estamos fazendo o uso de Companion Objects.

Com esta técnica podemos criar uma espécie de factory que servirá de atalho para instanciar um Person Xmlable:


object Person {
   def xmlPerson(n: String, a: Int)  = new Person(n,a) with
	Xmlable {
		def xml =
<person><name>{name}</name><age>{age}</age></person>
	}  }
//importamos a função
import Person.xmlPerson

val p = xmlPerson("Caro", 21) //atalho.
println(p.xml) //produz o xml de person.

Scala possui bibliotecas que funcionam de modo semelhante ao jax-b do Java. Mas a intenção aqui é mostrar as habilidades da linguágem no uso de XML.

Agora que sabemos produzir um XML de person a partir de um objeto Person, vamos ensaiar produzir um objeto Person a partir de um XML de Person. Para isso vamos definir uma nova função no object Person. Esta função retornará um Array de Persons, pois ela pode receber mais de um elemento do tipo <person>. Vamos ao código:


object Person {  
   def xmlPerson(n: String, a: Int)  = new Person(n,a) with 
      Xmlable {  
           def xml =
<person><name>{name}</name><age>{age}</age></person>  
      }

   def fromXml(xml: NodeSeq) = {
      for { p <- xml \\ "person"
             name <- p \ "name"
             age <- p \"age"
             nameText = name.text
             ageText = Integer.parseInt(age.text) } yield xmlPerson(nameText, ageText)
    }

}
//instanciando uma pessoa a partir de um xml
val persons = fromXml (person)
println(persons(0).name)
println(persons(0).age)

//documento com muitos
<person>
val document =
<persons>
<person><name>Paulo</name><age>26</age></person>
<person><name>Caro</name><age>18</age></person>
	  </persons>
val persons2 = fromXml (document)

println(persons2(1).name)

A função fromXml recebe uma sequencia de nós <person> (definida no início do post) e executa um código com o mesmo poder de uma  XQuery, com a diferença da notação “/” e “//” do XQuery ser substituída por métodos cujo nome são “\” e “\\”. Essa consulta extrai os valores para o nome e idade, devolvendo uma lista de objetos Person.

A lista que este método retorna vem do for, que em Scala pode retornar valor, usando o formato for (x <- e) yield e’. Assim, podemos fazer consultas não só em XML, mas uma lista de objetos, por exemplo.
Este código ainda exibe um exemplo onde um documento cujo elemento raiz <persons> engloba dois elementos <person>. O resultado é uma lista de Person.

Falando em XQuery, podemos consultar este document sem a necessidade de instanciar um objeto do tipo Person. O código abaixo mostra duas consultas, a primeira buscando Person com idade superior a 18 e a segunda devolvendo a média da idade das Persons contidas no documento.


//pessoas maiores de 18
for { p <- document \\ "person"
        name <- p \ "name"
	age <- p \"age"
	nameText = name.text
	if Integer.parseInt(age.text) > 18} println(nameText) // Paulo

//media das idades
val ages = for { a <- document \\ "age" } yield Integer.parseInt(a.text)
println(ages.reduceLeft ((x : Int, y : Int) => x+y) / ages.length) // 22

A habilidade de trabalhar diretamente no código com XML, permite uma flexibilidade que não conseguimos tão naturalmente em Java, por exemplo. Você pode encontrar um comparativo aqui.

Existem situações onde esse tipo de recurso é muito vantajoso, imagine serviços REST, scripts de dumping, backup, build, servlets, integração, etc. O Lift se vale desta possibilidade para construir um Framework MVC Web muito poderoso.

Obs: Os exemplos expostos aqui poderiam ter sido construído de outras formas. São apenas exemplos para forçar a demonstração de algumas features.

Todo o script usado neste post você encontra aqui.

Como tudo, eu também venho evoluindo em escala nos últimos mêses.

Hoje resolvi re-ler um post chamado Scala, Scala, Scala publicado em Janeiro, e me senti un tanto quanto envergonhado com o que vi. Então resolvi re-escrever os três exemplos assim:

1. Novo: numbers foreach (x => println(x*x))

1. Velho: List[Int](1,2,3,4,5) map (x => Console.println(x*x))

A função map retorna uma lista, e meu interesse é apenas imprimir o resultado. Por isso o uso do foreach.

2. Novo: (for (i <- numbers if i > 3) yield i) foreach println

2. Velho: for (i <- numbers if i > 3) yield Console.println(i)

O resultado produzido, também é o mesmo. A diferença é que no caso do modelo antigo, na verdade não necessitaria de um yield que permite um for retornar um valor relavante. Então para dar uma utilidade ao yield, resolvi aplicar um foreach na lista retornada pelo for e então imprimir cada valor, semelhante ao primeiro exemplo.

3. Novo: println( numbers reduceLeft(_ + _) )

3. Velho: numbers.reduceLeft((x,y) => x + y)

O resultado do modelo velho, na verdade não imprimia o valor da soma entre os membros da minha lista. Agora imprime, e usa placeholder syntax, ou seja, uso o wildcard _ para me referir ao primeiro e segundo argumento pasado para minha literal function _ + _. Para entender melhor, seria importante verificar um pouco da API Scala.

No final, temos um código ainda mais reduzido e mais elegante. Menos repetitivo (e acredite, eu poderia me repetir ainda menos neste código) e mais claro. Aqui sim o estilo funcional foi materializado.

OBS: Oficialmente _ é considerado como um valor em branco que deve ser preenchido, a designação wildcard foi usada neste post para facilitar o entendimento.

Linkedin

View Paulo Suzart's profile on LinkedIn

Categorias

Twitter Updates

Páginas

 

Julho 2009
S T Q Q S S D
« Jun    
 12345
6789101112
13141516171819
20212223242526
2728293031