Sei sulla pagina 1di 20

Estudo sobre a linguagem de programao Lua*

Bruno Lopes Dalmazo1, Francisco Tiago Avelar1


1
Curso de Cincia da Computao Universidade Federal de Santa Maria (UFSM)
Santa Maria, RS Brasil
{dalmazo, avelar}@inf.ufsm.br

Resumo. Este trabalho apresenta funcionalidades da linguagem brasileira de


programaco Lua atravs de uma abordagem simples e informativa. Noes
gerais de histrico demonstram seu propsito e seus domnios de aplicao
exemplificam a aceitao do trabalho perante os outros pases. Alm disso,
detalhes mais especficos so explicados de modo a apresentar ao profissional
de computao a grande facilidade de programao sob a abordagem
envolvendo os conceitos de linguagens de programao.

1. Histria do surgimento da linguagem


A Petrobrs, parceira da TeCGraf, grupo de Tecnologia em Computao grfica da
PUC-RJ, formado pelos professores Roberto Ierusalimschy, Waldemar Celes e Luiz
Henrique Figueiredo, necessitava traar um perfil de um poo de petrleo. Durante uma
perfurao, junto com a broca, vrios sensores descem em conjunto, para que os
gelogos acompanhem o processo. Estes sensores recebem as informaes medida que
o poo perfurado.
Os valores capturados pelos sensores eram colocados em um grfico na tela do
computador, com dados diversos, como temperatura, condutividade do material naquela
profundidade, resistncia e presso. Os programas coletam estas informaes e as
manipulam para que o grfico seja montado. Contudo, existem vrios fatores complexos
de configurao que o gelogo pode desejar visualizar. s vezes, preciso ver uma
coluna do lado da outra; outras; h necessidade de verificar outro tipo de informao,
mudar a cor ou a escala. A complexidade de realizar esse trabalhado era grande com o
uso de uma nica interface grfica, pois sempre fica faltando algum detalhe.
Sendo assim, quando o gelogo necessitava de mais comandos, era obrigado a
contatar os desenvolvedores da aplicao para que o software fosse alterado ou para que
fosse criado um novo programa, enviando em seguida para a plataforma. Desta forma
foi criado o Lua, para colocar um final para esse problema. Com esta linguagem,
algum que tenha uma pequena formao tcnica pode fazer, ele mesmo, essa
configurao. A linguagem simples o suficiente para que a pessoa possa modificar e

* Trabalho Conceitos de Linguagem de Programao (ELC1007) primeiro semestre 2007.


adaptar s suas necessidades. Assim, o programa um pouco de linguagem de
programao C, que cria a parte grfica, e um pouco de Lua, que pode estar gravada em
um arquivo texto, encarregado de dizer para o C como as informaes so apresentadas.

2. Domnios de aplicao
A linguagem de programao Lua possui grande uso no domnio corporativo voltado
para o mercado de jogos de computadores [WoW] e consoles de video-game
[Psychonauts]. Alm disso, bastante empregada em aplicaes Web e no
desenvolvimento de ferramentas para auxiliar a pesquisa cientfica, como a Biologia
Molecular [GUPPY].
Lua foi projetada para estender aplicaes, sendo freqentemente utilizada como
uma linguagem de propsito geral. Dessa forma, diversos casos de uso podem ter Lua
como parte da implementao de uma soluo, seja para o domnio empresarial,
cientfico e industrial. A comunidade de desenvolvimento em linguagem Lua de
domnio geral. Assim, qualquer interessado pode ter acesso a documentao e o cdigo-
fonte da implementao da linguagem, pois Lua software livre de cdigo aberto.
Demais exemplos de uso da linguagem Lua de forma a descrever seus domnios
de aplicao podem ser vistos da Internet, atravs do website oficial, nas referncias
finais deste trabalho.

3. Variveis e tipos de dados


As variveis globais de Lua no precisam ser declaradas. Assim, possvel escrever o
comando
a = 2.3

sem necessidade prvia de declarar a varivel global a. Uma caracterstica fundamental


de Lua que as variveis no tm tipo: os tipos esto associados aos dados armazenados
na varivel. Assim, o cdigo acima armazena em a um dado do tipo numrico, com
valor 2.3, enquanto, aps o comando
a = "Linguagem Lua"

a varivel a passa a armazenar um dado do tipo cadeia de caracteres (string).


Os dados em Lua podem ser de oito tipos bsicos: nil, lgico, number, string,
function, userdata, thread e table.

3.1. Tipo nil


O tipo nil representa o valor indefinido. Todas as variveis ainda no inicializadas
assumem o valor nil. Assim, se o cdigo:
a = b
for encontrado antes de qualquer atribuio varivel b, ento esta assumida como
contendo o valor nil, significando que a tambm passa a armazenar nil,
independentemente do valor anteriormente armazenado em a. A palavra reservada nil
pode ser usada na programao para expressar o valor do tipo nil. Com isto, pode-se
escrever:
a = nil

que atribui o valor nil varivel a (a partir deste ponto, como se a varivel a ainda
no tivesse sido atribuda).
Pode-se testar se uma varivel foi inicializada comparando o seu valor com nil:
a == nil

3.2. Tipo lgico

O tipo lgico, tambm conhecido como tipo booleano, pode assumir somente dois
valores: verdadeiro (true) ou falso (false).

3.3. Tipo number


O tipo number representa valores numricos. Lua no faz distino entre valores
numricos com valores inteiros e reais. Todos os valores numricos so tratados como
sendo do tipo number. Assim, o cdigo

a = 4
b = 4.0
c = 0.4e1
d = 40e-1

armazena o valor numrico quatro nas variveis a, b, c e d.

3.4. Tipo string


O tipo string representa cadeia de caracteres. Uma cadeia de caracateres em Lua
definida por uma seqncia de caracteres delimitadas por aspas simples (' ') ou duplas ("
"). A seqncia de caracteres deve estar numa mesma linha de cdigo.
Por simplicidade, quando a cadeia de caracteres delimitada por aspas duplas,
pode-se usar aspas simples no seu contedo, sem necessidade de trat-las como
seqncias de escape. Entretanto, para reproduzir na cadeia de caracteres as aspas
usadas como delimitadoras, necessrio usar os caracteres de escape. Assim, so
vlidas e equivalentes as seguintes atribuies:

s = "Marca d'agua"
s = 'Marca d\'agua'

Colchetes duplos ([[ ]]) tambm podem ser utilizados como delimitadores de
strings. Diferentemente dos delimitadores aspas simples e aspas duplas, esse
delimitador no interpreta sequncias de escape e tolera que a string tenha quebras de
linhas e pode conter strings com delimitadores aninhados. Exemplo:
s = [[Esse um texto que
atravessa
mais de uma linha
e contm uma string aninhada: [[aninhada]] no final !]]

3.5. Tipo function


Funes em Lua so consideradas valores de primeira classe. Isto significa que funes
podem ser armazenadas em variveis, passadas como parmetros para outras funes,
ou retornadas como resultados. A definio de uma funo equivale a atribuir a uma
varivel global o valor do cdigo que executa a funo (ver definio de escopo). Esta
varivel global passa a armazenar um dado do tipo function. Assim, adiantando um
pouco a sintaxe de definio de funes, o trecho ilustrativo de cdigo abaixo armazena
na varivel func1 um valor do tipo function:
function func1 (...)
...
end

que pode posteriormente ser executada atravs de uma chamada de funo:


func1(...)

3.6. Tipo userdata


O tipo userdata permite armazenar numa varivel de Lua um ponteiro qualquer de C.
Este tipo corresponde ao tipo void* de C e somente pode ser atribudo ou comparado
para igualdade a outro valor de mesmo tipo em Lua. Este tipo muito til para
programadores de aplicao que fazem a ligao Lua-C, mas no manipulado por
usurios que programam somente em Lua, pois no possvel criar dados deste tipo
diretamente em Lua.
O prposito de oferecer esse tipo de dado na linguagem Lua oferecer
integrao com as demais linguagens, pois assim mantem o ideal de ser uma linguagem
simples, facilmente estensvel e de propsito geral.

3.7. Tipo thread


O tipo thread representa diferentes fluxos de execuo, sendo utilizado para
implementar subrotinas (coroutines). No confundir Lua threads com as do sistema
operacional. Lua suporta subrotinas em todos os sistemas, mesmo os que no possuem
suporte a threads.
A forma especial de coroutines na linguagem Lua tambm chamada de
multithreadings colaborativas, representando um fluxo independente de execuo.
Entretanto, diferentemente das threads em sistemas multithreads, uma coroutine
somente encerra sua execuo atravs da chamada explcita de funo de entrega (yield
function).
Simplesmente invocando coroutine.create, uma coroutine criada
retornado um objeto do tipo thread de manipulao. A funo no inicia sua execuo
nesse ponto de desenvolvimento do programa.
Quando chamado pela primeira vez coroutine.resume, passando o
argumento do tipo thread retornado por coroutine.create, a coroutine inicia sua
execuo na primeira linha da funo principal. Os argumentos adicionais so passados
juntamente com o tipo thread para a funo da coroutine. Depois de iniciar a execuo,
permanece at terminar ou ocorre uma interrupo yield.
H somente duas maneiras de uma coroutine encerrar: normalmente, quando sua
funo principal retorna (explicitamente ou implicitamente aps a ltima instruo); ou
incorretamente, se h presena de erros. No primeiro caso, coroutine.create
retorna true, alm das variveis retornadas pela funo principal de coroutine. No caso
de erros, coroutine.resume retorna false mais uma mensagem de erro.
Ocorre yield atravs da chamada explcita de coroutine.yield.
Acontecendo isso, o correspondente coroutine.resume retorna imediatamente,
mesmo se um yield ocorre dentro de funo aninhada, ou seja, no na funo principal,
mas na funo diretamente ou indiretamente chamada pela funo principal. No caso de
yield, coroutine.resume tambm retorna true, alm dos valores passados para
coroutine.yield. Na prxima vez que a mesma coroutine retomada, a execuo
continua do ponto onde ocorreu yield, com a chamada de coroutine.yield
retornando quaisquer argumentos extras passados por coroutine.resume.

function func_secundaria (a)


print("func_secundaria", a)
return coroutine.yield(2 * a)
end

co_rotina= coroutine.create( function (a,b)


print("co_rotina", a, b)
local r = func_secundaria(a + 1)
print("co_rotina", r)
local r, s = coroutine.yield(a + b, a-b)
print("co_rotina", r, s)
return b, "fim"
end)
print("principal", coroutine.resume(co_rotina, 1, 10))
print("principal", coroutine.resume(co_rotina, r))
print("principal", coroutine.resume(co_rotina, x, y))
print("principal", coroutine.resume(co_rotina, x, y))

A sada da execuco do programa representado abaixo:

co_rotina 1 10
func_sec 2
principal true 4
co_rotina r
principal true 11 -9
co_rotina x y
principal true 10 fim
principal false cannot resume dead coroutine

3.8. Tipo table


O tipo table (tabela) o tipo mais expressivo da linguagem. Este tipo implementa os
chamados vetores associativos, que permitem indexao por valores de qualquer outro
tipo, com exceo do tipo nil. As tabelas em Lua permitem a construo de vetores
convencionais, listas e records numa mesma estrutura. Tabelas devem ser explicitamente
criadas. Adiantando a sintaxe de criao de uma tabela, o cdigo
a = { }

cria uma tabela vazia e armazena em a este valor. Novos campos podem ser adicionados
posteriormente a esta tabela.
A partir de table, possvel implementar diversas estruturas de dados, como
arrays comuns, tabela de smbolos, conjuntos, registros, grafos, rvores, etc.

4. Comandos de controle
Lua possui os mecanismos usuais para controle de fluxo. Estes controladores agrupam
diversos comandos em blocos que podem ou no serem executados uma ou mais vezes.
Lua tambm permite a declarao de variveis locais. Estas variveis deixam de existir
ao final do bloco onde foram declaradas.

4.1. Estrutura If
O comando de deciso bsico de Lua o if, sendo representado por uma das formas
abaixo:

if expr then
bloco
end

ou
if expr then
bloco1...
else
bloco2...
end
ou ainda
if expr1 then
bloco1
elseif expr2 then
bloco2
...
elseif expr N then
bloco N
else
bloco N+1
end

Na primeira forma, o bloco de comandos representado por bloco executado se


a expresso expr produzir um valor diferente de nil. Na segunda forma, bloco2
ser executado se expr produzir o valor nil. Caso contrrio, bloco1 ser executado.
A terceira forma ilustra a possibilidade de tomada de deciso entre diversas alternativas
usando-se o comando if-then-elseif-then-...-else-end. No cdigo ilustrado, bloco1
executado se expr1 produzir um valor verdadeiro (diferente de nil), bloco2
executado de expr2 for verdadeiro, ..., e bloco N+1 executado se todas as
expresses forem falsas (i.e., iguais a nil).

4.2. Estrutura while (tomadas de deciso no incio)


A instruo while permite que a tomada de deciso (se os comandos do lao devem ou
no ser executados) seja feita no incio do bloco. Sua forma geral :

while expr do
bloco
end

isto , enquanto a expresso expr produzir um valor verdadeiro (diferente de nil), os


comandos do bloco so executados. Para exemplificar, considere o cdigo abaixo que
calcula o fatorial de um nmero (assumido como inteiro positivo) armazenado na
varivel n:

f = 1 -- valor do fatorial
i = n -- controle do lao
while i > 0 do
f = f * i
i = i 1
end

Ao final da execuo do cdigo acima, f armazena o valor do fatorial de n e i


armazena o valor zero (condio de fim de execuo do lao).

4.3. Estrutura repeat (tomadas de deciso no final)


A construo de um lao com tomada de deciso no fim pode ser feita atravs do
comando repeat. Sua forma geral :
repeat
bloco
until expr

Nesta construo, o bloco de comandos executado pelo menos uma vez (pois o
teste de deciso s ocorre no final do lao) e repetido at se alcanar o valor
verdadeiro para a expresso. O mesmo exemplo de clculo de fatorial pode ser escrito:

f = 1 -- valor do fatorial
i = 1 -- controle do lao
repeat
f = f * i
i = i + 1
until i > n

4.4. Estrutura for


A estrutura for apresenta duas formas: uma numrica e outra genrica. A forma
numrica repete as instrues do bloco numa progresso aritmtica definida como
primeiro valor a atribuio numrica exp1 em var, com limite mximo exp2 numa
razo exp3. No caso da ausncia exp3, o incremento padro unitrio.

for var = exp1, exp2 [, exp3] do


bloco
end

A declarao do for genrico trabalha sobre funes, conhecidos como


iteradores. A cada iterao, a funo de iterao chamada para produzir um novo
valor, encerrando quando nil encontrado. O lao genrico representado de acordo
com a sintaxe
for namelist in explist do
bloco
end

ou de forma mais representativa,


for var_1, , var_n in explist do
bloco
end

Conforme foi definido na seo 3.8, a estrutura table um tipo primitivo em Lua
com comportamento dinmico. O exemplo abaixo implementa um percurso numa tabela
para procurar um determinado valor na estrutura, retornando verdadeiro ou falso como
resultado na busca de um determinado valor no interior da tabela. Atravs do cdigo,
simples de perceber como os valores inicializados da tabela representam tipos distintos
de dados.
-- devo declarar explicitamente uma tabela local
local tabela = {}

function func()
-- funcao func() eh uma variavel
-- que sera inserida na tabela
end

tabela = {5, false, 3.14, func, nil, "texto"}

function existe_valor(valor)

for k, v in pairs(tabela) do -- 'for' genrico


if v == valor then
return true
end
end
return false
end

parametro = "texto" -- apenas atribui o que ser procurado

if( existe_valor(parametro) ) then


io.write( tostring(parametro).." 'encontrado." )
else
io.write( tostring(parametro).." ' NAO encontrado." )
end

io.write("\n")

5. Subprogramas (funes)
Conforme foi dito na seo 3.5, a linguagem Lua trata funes como valores de primeira
classe. Quando definimos uma funo em Lua, o armazenando feito na varivel global
cujo nome corresponde ao nome da funo o cdigo de mquina interno da funo,
que pode posteriormente ser executado atravs de chamadas para a funo.
Funes em Lua podem ser definidas em qualquer lugar do ambiente global. A
forma bsica para definio de funes

function nome ( [lista-de-parmetros] )


bloco de comandos
end

onde nome representa a varivel global que armazenar a funo. Pode-se fornecer uma
lista de parmetros que so tratados como variveis locais da funo e inicializados
pelos valores dos argumentos na chamada da funo.
A chamada da funo segue a forma bsica
nome ( [lista-de-argumentos] )

isto , o nome da funo seguido de abre e fecha parnteses, que pode ou no conter
uma lista de argumentos. Se nome no for uma varivel que armazena um valor de
funo (i.e., do tipo function), Lua reporta um erro de execuo (TAG METHODS). Se
presente, a lista de argumentos avaliada antes da chamada da funo. Posteriormente,
os valores dos argumentos so ajustados para a atribuio dos parmetros seguindo uma
regra de atribuio mltipla na qual os parmetros recebem os valores dos argumentos.
Lua passa parmetros por valor. Isto quer dizer que quando se altera o valor de
um parmetro dentro de uma funo, altera-se apenas o valor da varivel local
correspondente ao parmetro. O valor da varivel passada como argumento na chamada
da funo permanece inalterado.
Funes em Lua podem retornar zero, um ou mais valores atravs do comando
return. A possibilidade de retorno mltiplo evita a necessidade de passagem de
parmetros por referncia. Quando, durante a execuo de uma funo, encontra-se o
comando return, a execuo da funo terminada e o controle volta para o ponto
imediatamente posterior chamada da funo. O comando return pode vir seguido
de uma lista de expresses; sua forma geral
return [lista-de-expresses]

Por razes sintticas, o comando return deve sempre ser o ltimo comando de
um bloco de comandos. Deste modo, evita-se a ocorrncia de comandos inalcanveis
(tendo em vista que comandos aps return nunca sero executados). Se return no
for o ltimo comando do bloco, Lua reporta um erro de sintaxe.
Os valores retornados por uma funo so ajustados para a atribuio na linha
que faz a chamada. Para exemplificar, supe-se uma funo que incrementa os valores
de um ponto cartesiano (x, y):

function translada (x, y, dx, dy)


return x+dx, y+dy
end

Considera-se, agora, que a chamada da funo feita por:


a, b = translada(20, 30, 1, 2)

Assim, a recebe o valor 21 (= 20 + 1) e b recebe o valor 32 (= 30 + 2). Se a


chamada fosse
a = translada(20, 30, 1, 2)
ento o segundo valor retornado seria desprezado, e a receberia o valor 21. Por outro
lado, a atribuio:
a, b, c = translada(20, 30, 1, 2)

faria a = 21, b = 32 e c = nil.


importante notar que uma chamada de funo que retorna mltiplos valores
no pode estar no meio de uma lista de expresses. Por razes de ajustes de valores em
atribuies mltiplas, se uma funo estiver sendo chamada no meio de uma lista de
expresses, s se considera o primeiro valor retornado. Para exemplificar, duas situaes
sutilmente diferentes so analisadas; considera-se inicialmente a chamada de funo
abaixo:
a, b, c = 10, translada(20, 30, 1, 2)

que faz com que a receba o valor 10, b o valor 21 e c o valor 32. Neste caso, o
funcionamento o esperado, tendo em vista que a chamada da funo a ltima
expresso numa lista de expresses. No entanto, se o cdigo fosse
a, b, c = translada(20, 30, 1, 2), 10

ento teria-se resultados incorretos, j que a chamada da funo est no meio de uma
lista de expresses. Conforme mencionado, independentemente do nmero de valores
retornados pela funo, considera-se apenas o primeiro (no caso, o valor 21).
O valor 32 retornado pela funo perdido durante o ajuste. Assim, teramos
como resultado o valor 21 armazenado em a e o valor 10 armazenado em b. A varivel
c, ento, receberia o valor nil, pois no se tem outra expresso aps a constante 10.
possvel definir funes em Lua que aceitem nmero varivel de argumentos.
Para tanto necessrio acrescentar lista de argumentos da definio a indicao ...
(trs pontos seguidos). Uma funo definida dessa forma no faz ajuste do nmero de
parmetros em relao ao nmero de argumentos. Ao invs disso, quando a funo
chamada os argumentos extras so colocados em um parmetro implcito de nome arg.
Esse parmetro sempre inicializado como uma tabela, onde o campo n contm o
nmero de argumentos extras e os campos 1, 2, ... os valores dos argumentos,
seqencialmente.
Para exemplificar, duas diferentes definies de funes so apresentadas:

function f(a, b) end


function g(a, b, ...) end

Os seguintes mapeamentos de argumentos a parmetros seriam efetuados na


chamada dessas funes:
Chamada Parmetros
f(3) a = 3, b = nil
f(3, 4) a = 3, b = 4
f(3, 4, 5) a = 3, b = 4
g(3) a = 3, b = nil, arg = { n = 0 }
g(3, 4) a = 3, b = 4, arg = { n = 0 }
g(3, 4, 5, 8) a = 3, b = 4, arg = { 5, 8; n = 2 }

6. Subprogramas sobrecarregados e genricos.


A linguagem Lua no apresenta declarao formal para tipos de dados, conforme
mencionado na seo 3. Dessa forma, subprogramas possuem comportamento genrico
quando a aceitabilidade de dados de entrada e retorno de valores. Por outro lado, em se
tratando de sobrecarga de operadores na linguagem Lua, uma estrutura interessante,
chamada metatable, foi criada para permitir maior flexibilidade no desenvolvimento de
programas.
Elemento presente em qualquer varivel na linguagem Lua, um metatable uma
table comum cuja funo definir o comportamento do valor original perante certas
operaes. possvel efetuar diversas alteraes do comportamento das operaes sobre
o valor atravs de ajustes dos campos especficos na metatable. Por exemplo, quando um
valor no-numrico operando de uma adio, Lua verifica a funo no campo
"__add" na sua metatable. Ao encontrar alguma, ocorre a invocao dessa funo para
desempenhar a adio. possvel consultar eventos de um metatable e os metamtodos
de qualquer valor atravs da funo getmetatable. No caso anterior, o evento
"add" para o metamtodo da funo que efetua a adio. No caso de substituir um
metatable em tabelas, passa a ser usado a funo setmetatable.
Tables e userdata possuem metatables individuais (apesar que mltiplas tabelas
e userdata compartilham suas metatables), ao passo que todos os outros tipos
compartilham um nico metatable por tipo. Desse modo, h uma nica metatable para
todos os numbers, uma para todas as strings, etc.
Um metatable pode controlar o comportamento de um objeto em operaes
aritmticas, comparaes, concatenao, cardinalidade, indexao, etc. Alm disso,
pode definir uma funo para ser chamada quando um userdata coletado para lixo.
Para cada uma dessas operaes, Lua associa uma chave especfica denominado evento.
Ao desempenhar uma dessas operaes sobre um valor, Lua verifica caso esse valor
possui uma metatable com o evento correspondente. Em caso afirmativo, o valor
associado com aquela chave (o metamtodo) controla como a linguagem ir efetuar a
operao.
Cada operao identifidada pelo nome correspondente. A chave uma string
com o nome prefixado de duas sublinhas, '__', por exemplo. Desse modo, a chave para a
operao de adio a string "__add".
A funo getbinhandler abaixo define como Lua escolhe um manipulador
para uma operao de binria. Primeiramente, o primeiro operando verificado, caso
seu tipo no define um manipulador para a operao, o segundo operando analisado.
function getbinhandler (op1, op2, event)
return metatable(op1)[event] or metatable(op2)[event]
end

A tabela segue com a representao string dos operadores em Lua que possuem a
capacidade de sobrecarga atravs de metatables.
Nome Descrio Smbolo
add adio +

sub subtrao -

mul multiplicao *

div diviso /

mod resto da diviso %

pow exponenciao ^

unm unrio -

concat concatenao ..

len cardinalidade #

eq equivalncia ==

lt1 menor a <

le2 menor ou igual a <=

index acesso indexado table[key]

newindex atribuio de indexao table[key] =


value
call chamada de valor ausente

O exemplo abaixo representa o uso de metatable para o operador de adio de


forma a ser sobrecarregado atravs da atribuio de um manipulador m.
1 a>b equivalente a b<a
2 a>=b equivalente a b<=a. Notar que, na ausncia do metamtodo le, Lua tenta lt, assumindo
que a<=b equivalente a not(b < a)
function evento_add (op1, op2)
local o1, o2 = tonumber(op1), tonumber(op2)
if o1 and o2 then -- ambos operandos so numricos?
return o1 + o2 -- '+' primitiva 'add'
else -- pelo menos um no numrico
local m = getbinhandler(op1, op2, "__add")
if m then
-- invoca o manipulador com os dois operandos
return m(op1, op2)
else -- no h manipulador: comportamento padro
error()
end
end
end

7. Escopo (regras de visibilidade)


Lua uma linguagem com escopo lxico de variveis, iniciando na primeira
especificao aps as declaraes e permanece at o final do bloco mais interno que
inclui a declarao. Considerando o exemplo abaixo, fica simples de deduzir.

x = 10 -- varivel global
do -- novo bloco
local x = x -- novo 'x', com valor 10
print(x) -- imprime 10
x = x+1
do -- outro bloco
local x = x+1 -- outro 'x'
print(x) -- imprime 12
end
print(x) -- imprime 11
end
print(x) -- imprime 10 (varivel global)

Lua permite que se defina explicitamente variveis de escopo local. A declarao


de uma varivel local pode ocorrer em qualquer lugar dentro de um bloco de comandos,
e seu escopo termina quando termina o bloco no qual foi declarada. A declarao de
uma varivel local com mesmo nome de uma varivel global obscurece
temporariamente (i.e., dentro do bloco da declarao local) o acesso varivel global.
Quando o programador escrever o nome da varivel, estar se referindo varivel local.
Variveis locais podem ser inicializadas na declarao seguindo a sintaxe de
atribuies. Para exemplificar, considere o cdigo abaixo:
a = 2 -- varivel global igual a 2
if a > 0 then
local b = a -- varivel local 'b' com atribuio 2
a = a + 1 -- incrementa a varivel global 'a'
-- de uma unidade
local a = b -- declara-se uma varivel local 'a'
-- que recebe o valor de 'b'
print(a) -- a refere-se a varivel local,
-- logo imprime o valor 2
end -- fim do bloco e do escopo de
-- 'a' e 'b' locais
print(a) -- 'a' refere-se varivel global, logo
-- imprime o valor 3

Pode-se ainda declarar e inicializar vrias variveis locais num mesmo comando:
local a, b, c = 2, 5+6, -3

Neste caso, a recebe 2, b recebe 11 e c recebe -3. Variveis locais no


inicializadas assumem o valor nil.

8. Acesso a ambientes no locais


Na linguagem Lua, funes so variveis locais tratadas como qualquer outro tipo de
dado. Desse modo, quando ocorre o caso de funes estarem definidas no interior de
outras, um mecanismo para acessar variveis em diferentes nveis de programa criou o
conceito de encerramento de variveis e funes no-globais. Nas subsees seguintes,
ambos os casos so verificados.

8.1. Closures (encerramentos)

Quando uma funo escrita no interior de outra, a funo includa passa a ter acesso
completo a todas as variveis locais da funo detentora; funcionalidade conhecida
como escopo lxico. Embora parea simples, s vezes no to bvia quanto seja.

O pequeno cdigo abaixo ilustra o conceito simples envolvendo closures.


Suponha uma lista de estudantes e as notas ambos armazenados numa table. O objetivo
ordenar a lista de nomes de acordo com as notas em ordem decrescente.

nomes = {"Pablo", "Paula", "Mariana"}


notas = {Mariana = 10, Paula = 7, Pablo = 8}
table.sort(nomes, function (n1, n2)
return notas[n1] > notas[n2] -- compara as notas
end)

Agora, suponha que o cdigo que contm a funo que desempenha a tarefa de
ordenao dos nomes de alunos atravs da nota maior at a nota menor:
function ordena_por_nota(nomes, notas)
table.sort(nomes, function (n1, n2)
return notas[n1] > notas[n2] -- compara as notas
end)
end

O exemplo demonstra que a funo annima interna a sort acessa o parmetro


notas, o qual local (parmetro formal) na funo ordena_por_nota. No interior
na funo annima, notas no nem uma varivel global e tanto como no uma
varivel local. O conceito envolvido denominado varivel local externa, ou upvalue3.

Qual o diferencial dessa idia? O motivo devido s funes serem variveis de


primeira classe. Considere o cdigo:

function novo_contador()
local i = 0
return function() -- funo annima
i = i + 1
return i
end
end
c1 = novo_contador()
print( c1() ) --> 1
print( c1() ) --> 2

A funo annima utiliza um upvalue, i, para manter seu contador. Entretanto,


na ocasio de invocao da funo annima, i est fora de escopo, pois a funo que
criou a varivel (novo_contador) encerrou com o retorno. Apesar disso, Lua
gerencia a situao corretamente atravs do conceito de closures. Em outras palavras,
uma closure uma funo incluindo todas as caractersticas para acessar upvalues de
forma correta. Ao invocar novo_contador novamente, uma nova varivel local i
ser criada, assim como uma nova closure, atuando sobre a nova varivel:

c2 = novo_contador()
print( c2() ) --> 1
print( c1() ) --> 3
print( c2() ) --> 2

Como se pode concluir, c1 e c2 so diferentes closures sobre a mesma funo e


cada ao atua sob instanciao independente da varivel local i. Mais especificamente,
todo valor em Lua uma closure, no uma funo. Por si s, funo apenas um
prottipo para closures.

3 O termo "upvalue" um tanto enganoso, pois notas uma varivel, no um valor. Entretanto, esse
termo possui razes histricas da linguagem Lua e tambm uma forma de abreviatura para "varivel
local externa".
Atravs do mecanismo de closures, programas em Lua incorporam tcnicas de
programao personalizveis, como uso de callbacks, muito teis para aplicativos GUI.

Outro uso de closures justifica a grande flexibilidade de Lua, pois funes so


variveis regulares e podem ser facilmente redefinidas. Por exemplo, suponha que
queremos redefinir a funo seno para operar com ngulos em graus ao invs de arcos
em radianos. Essa nova funo deve converter seu argumento e ento chamar a funo
seno original para efetuar o trabalho real. Considere o cdigo:

seno_velho = math.sin
math.sin = function (x)
return seno_velho(x * math.pi/180)
end

Um exemplo de uso da funo est abaixo :

do
local seno_velho = math.sin
local l = math.pi/180
math.sin = function (x)
return seno_velho(x * l)
end
end

A idia foi manter a verso antiga numa varivel privada. O nico caminho e
acesso atravs da nova verso.

A partir do conceito de redefinio de funes, possvel utilizar a mesma


caracterstica para criar ambientes seguros, tambm conhecidos como sandboxes
("caixas de areia"). Segurana essencial quando h execuo de cdigo no confivel,
como um trecho de programa recebido atravs da Internet por um servidor. Por exemplo,
para restringir acesso aos arquivos por um programa "desconhecido", a funo open, da
biblioteca io, pode ser redefinida utilizando closures:

do
local velho_open = io.open
io.open = function (nome_arq, modo)
if access_OK(nome_arq, modo) then
return velho_open(nome_arq, modo)
else
return nil, "acesso negado"
end
end
end

O que torna esse exemplo interessante que, aps a redefinio, no h mais um


modo do programa invocar o open irrestrito, exceto atravs da nova e restrita verso. O
resultado foi manter a verso insegura como uma varivel privada numa closure,
inacessvel ao exterior. Com essa facilidade, possvel construir sandboxes at mesmo
em Lua, aproveitando o benefcio usual: flexibilidade. Dessa forma, ao invs de
solues nicas gerais, Lua oferece meta-mecanismos para que possa adequar o
ambiente para necessidades especficas de segurana.

8.2. Funes no-globais.

Uma evidente conseqncia das funes de primeira classe que possvel armazenar
funes no somente em variveis globais, mas tambm em tables e em variveis locais.
Quando uma funo armazenada numa varivel local, a funo ser local, ou seja,
restrita a um dado escopo.

Tal definio particularmente til para pacotes: Lua manipula cada chunk4
como uma funo, uma chunk pode declarar funes locais, as quais so somente
visveis no interior de um chunk. O escopo lxico garante que outras funes no pacote
podem usar essas funes locais:

local f = function (...)


...
end

local g = function (...) -- igual a local funcion g(...)


...
f() -- funo externa 'f()' visvel aqui
...
end

Uma questo importante ocorre na definio de recursividade em funes locais.


A abordagem primria abaixo no ir funcionar:

local fatorial = function (n)


if n == 0 then return 1
else return n * fatorial(n-1) -- ocorre erro
end
end

Quando Lua compila a chamada fatorial fatorial(n-1), no corpo da


funo, o fatorial local ainda no foi definido. Portanto, a expresso do cdigo onde
ocorre erro invoca a global fatorial, no a local. Para resolver esse problema,
necessrio definir a varivel local e ento criar a funo:

4 Cada poro de cdigo em Lua pode ser chamado de chunk, tal como um arquivo ou uma nica linha
de comando. Mais especificamente, um chunk simplesmente uma seqncia de declaraes. Veja
nas referncias para saber mais.
local fatorial
fatorial = function (n)
if n == 0 then return 1
else return n*fatorial(n-1)
end
end

Agora fatorial no interior da funo faz referncia a varivel local. Seu valor no
importa quando a funo definida, pois em tempo de execuo, fatorial j possui o
valor correto. Uma maneira expansiva para funes locais possui uma forma alternativa
para uso de recursividade:

local function fatorial (n)


if n == 0 then return 1
else return n * fatorial(n - 1)
end
end

Por outro lado, esse recurso no funciona quando ocorre recursividade de forma
indireta. Nesses casos, preciso usar a declarao explcita:

local f, g -- declarao explcita

function g ()
... f() ...
end

function f ()
... g() ...
end

9. Concluses

O estudo envolvendo conceitos de linguagens de programao representa o requisito


bsico para o compreendimento das entidades e elementos de linguagens de forma a
diferenciar os diversos prpositos da criao de linguagens, visto que no existe uma
soluoo universalmente utilizada que atenda todos os requisitos no desenvolvimento de
sistemas em computao. Em termos de evoluo, pases desenvolvidos iniciaram a
pesquisa na criao de linguagens de programao, regendo tcnicas e paradigmas para
desenvolvimento de programas.

Resultados consagrados na criao de linguagens de programao so


fundamentados na capacidade simplificada no uso e expresso dos mecanismos para
desenvolvimento de programas, alm de ferramentas envolvendo o apoio para correo
de erros (debug) e interfaces integradas de desenvolvimento, nos quais so recursos
essenciais para qualquer linguagem moderna para programao.
A linguagem de programao Lua demonstrou possuir grandes caractersticas
reunidas de solues existentes no desenvolvimento de linguagens e sustena os
paradigmas de programao estudados formalmente em Cincia da Computao. Alm
disso, incorpora funcionalidades prprias, como a alta flexibilidade no desenvolvimento
de cdigo, gerncia automtica de memria e a integrao com demais sistemas. Em
outras palavras, a linguagem no recria os mecanismos existentes das linguagens
consagradas de programao. A aceitao de Lua por diversos programadores ao redor
do mundo est na simplificidade de cdigo aliado a magnitude para implementao de
programas.

O presente trabalho comprova que pesquisadores e profissionais brasileiros em


Cincia da Computao possuem grande capacidade na criao de linguagens e sistemas
de forma a contribuir significativamente para facilitar a soluo de muitos problemas do
mundo moderno, oferecendo meios facilitadores de expresso entre Homem e mquina,
alm de tcnicas que ofeream desempenho aceitvel e clareza no tratamento de erros.

Referncias
WoW World of Warcraft - http://www.worldofwarcraft.com/
Psychonauts - Double Fine Productions - http://www.doublefine.com/
GUPPY - genetic sequence visualization . Computational Biology Research Center,
AIST Tokyo. http://staff.aist.go.jp/yutaka.ueno/guppy/
Aplicaes da linguagem Lua: http://www.lua.org/uses.html
Pgina oficial da Linguagem Lua: http://www.lua.org/
Livro on-line: http://www.lua.org/pil/
Manual do programador: http://www.lua.org/manual/5.1/
Lua chunks: http://www.lua.org/pil/1.1.html
Artigo que recebeu o primeiro prmio (categoria tecnologia) no II Prmio Compaq
de Pesquisa e Desenvolvimento em Cincia da Computao em 1997:
http://www.lua.org/spe.html
Artigo envolvendo corotinas em Lua:
http://www.inf.puc-rio.br/~roberto/docs/corosblp.pdf
Pgina geral de papers sobre Lua:
http://www.lua.org/papers.html

Potrebbero piacerti anche