Programação, Scala

Por que o foreach não funciona nos templates Play Framework

Como todos sabem, a partir do Play Framework 2.0, o antigo sistema de template foi substituido por uma solução muito mais limpa e poderosa. Basicamente usa-se o caractere “mágico” @ para tudo. No entanto, para aqueles que vem de outros sistemas de templates, podem haver alguns contratempos.

Um dos erros mais comuns é o de implementar idiomas imperativos no sistema de template. O exemplo mais claro é o fato do foreach não funcionar. Vejamos por que.

Primeiro um exemplo de uma solução imperativa:

@(artigos: Vector[models.Artigo])

<h3>@artigos.length Artigos Cientificos</h3>
<ul>
@artigos.foreach{ artigo => 		
		<li>
			<a href="/artigo/@artigo.codigo/">
				@artigo.titulo
			</a>
		</li>	
	 }
</ul>

O template recebe o parâmetro artigos, imprime um cabeçalho dizendo quantos artigos temos, e logo abrimos uma lista não ordenada UL. Usamos o caractere mágico @ para iniciar a iteração: para cada item imprimimos o respectivo link, sintaxe que deve estar clara até para quem está tendo o primeiro contato com esse sistema de templates.

O problema dessa solução… é que ela não funciona. O resultado será uma lista vazia. Por que? Justamente porque o implementador teve uma visão imperativa do sistema de templates. O loop foreach é imperativo, e retorna o valor Unit(valor não usável). O sistema de templates do Play Framework é funcional, e irá imprimir como resultado o retorno da expressão @, não seus efeitos colaterais.

Já esta solução produz o resultado esperado:

@(artigos: Vector[models.Artigo])

<h3>@artigos.length Artigos Científicos</h3>
<ul>
@artigos.map { artigo => 		
		<li>
			<a href="/artigo/@artigo.codigo/">
				@artigo.titulo
			</a>
		</li>	
	 }
</ul>

A diferença encontra-se no map que substitui foreach para a iteração. O sistema de templates não executa o loop e produz seus efeitos colaterais. Ele executa o trecho de código, obtém um retorno e então renderiza esse retorno. O retorno de foreach é Unit(valor não usável), por isso a lista renderizada estará vazia. No caso de map a lista UL é convertida em uma coleção Scala, a qual é então retornada, o sistema de templates a renderiza na forma de HTML.

Para trabalhar com os templates do Play Framework é preciso conhecer bem as coleções Scala. A chave do exemplo aqui citado está em saber que foreach é um loop imperativo e map é um loop funcional que produz outra coleção como resultado do processamento de cada item.

Standard