2007-01-28

Reiterador IV

Lua Bem, prometi que disponibilizaria um artigo melhor sobre o assunto então está aí:



O Walter estava revisando, mas se alguém encontrar algum erro, por favor não culpe ele! Porque ele não teve tempo de me entregar o texto revisado.

[]'s

2007-01-25

Desabafo

Baal Hoje vou reclamar... já está chegando em meu limite e minha sanidade está querendo tirar férias. =P

Estou trabalhando num projeto para uma organização não-governamental e já estou sem recebem desde novembro. Por culpa da organização? Não! Absolutamente!

A tal organização só faz pagamento por depósito em conta bancária. Bem, minha empresa se encontra atualmente sem conta bancária.

Fácil de resolver, não? Fui ao banco e iniciei o processo de abertura. Aí vem a primeira dor-de-cabeça...

Um de meus sócios, amarelão, disse que não vai assinar nada porque ele quer sair da firma e esta é uma forma de forçar sua saída.

Tudo bem... há saída...

Procurei meu contador e iniciei o processo para alteração contratual. Novo problema: meu outro sócio foi viajar!

Não posso fazer a alteração até ele voltar.

P. da vida com esta situação, ontem me liga uma cliente de um ISP onde presto serviço dizendo que o técnico deles tinha trocado a máquina principal da rede deles e que eles não conseguiam mais acessar a Internet. Como eu não estava lá na hora, o pessoal tentou resolver da melhor forma possível. O técnico da cliente disse que deixou toda rede configurada e pronta para acessar a Internet, e que não funcionava por culpa do ISP.

Chegando lá hoje pela manhã, desassociei o IP da cliente do endereço MAC, liguei para ela e disse que, como houve troca da máquina, o técnico dela deveria ter fornecido um novo endereço físico para funcionar. Como o pessoal do suporte também não havia pedido, eu fui lá na cliente para ajeitar a bagunça.

Chegando na cliente, ela estava com o técnico dela no telefone e disse que ele falou para ela que não existe endereço físico. Na mesma hora falei que ele só diria isso se não entendesse nada de Informática e peguei o telefone.

O técnico muito nervoso reclamou porque eu não deveria ter dito para ela que ele não entende nada e que ele havia trabalhado por quinze anos na IBM.

Perguntei para ele porque então ele falou para ela que não existe endereço físico e ele desconversou, dando a entender que ela entendeu mal o que ele disse. Depois falou que não funcionava por culpa do ISP e pediu para falar com a cliente de novo, com quem ficou reclamando um tempão.

Tudo bem. Respirei fundo, ignorei a abobrinha – a cliente pode ter entendido mal mesmo – e fui ver por que as máquinas não navegavam, e descobri um monte de coisas:

  • O compartilhamento de rede (não é o compartilhamento de arquivos e impressoras!) estava desabilitado. Ok, um técnico que trabalhou por quinze anos na IBM realmente não tem a obrigação de saber que o sistema NT precisa que o compartilhamento de rede esteja habilitado para compartilhar a rede.

  • O compartilhamento de arquivos e impressoras estava habilitado para a rede externa. Bem, um técnico que trabalhou por quinze anos na IBM não precisa saber que, ao habilitar o compartilhamento de arquivos para uma rede externa, a máquina estará compartilhando seus arquivos com todas as máquinas da rede externa.

  • As máquinas da rede interna não tinham IP e nem havia um servidor DHCP disponível. Ok, ok! Um técnico que trabalhou por quinze anos na IBM não precisa saber que para uma máquina participar de uma rede TCP/IP ela precisa de um endereço IP.

  • Ele disse que havia trocado apenas a placa mãe, não a placa de rede, mas a placa de rede era on-board. Tudo bem, um técnico que trabalhou por quinze anos na IBM não tem a obrigação de saber que ao trocar uma placa mãe de uma máquina, todas as placas on-board são trocadas também.


Depois de ter detectado essas lambanças, corrigi tudo, refiz a rede interna, e deixei as máquinas funcionando.

Nesse tempo todo a cliente me dizendo para eu não me estressar tanto porque senão vou ter um enfarto... e eu pensando comigo mesmo «sorria, ela não tem nada a haver com seus problemas».

Depois de vinte anos mexendo com computador ainda tenho de ouvir essas... c'est la vie.

2007-01-24

Tampinhas


Passei quase o mês todo conversando com o Walter sobre closures, porque o ele está escrevendo um artigo muito bom sobre o assunto e eu estou revisando.

Como fiquei empolgado, resolvi escrever meu próprio artigo sobre o assunto, apenas como uma prévia para o artigo do Walter – muito melhor.

O conceito de closures (literamente «tampas», ou «clausuras») não é tão complicado assim, mas é preciso entender bem outros conceitos antes de chegar lá.

Variável


Em programação, variável é um repositório (na memória principal) para armazenar uma informação. O conteúdo deste repositório pode mudar ao longo do programa.

Há em programação basicamente três tipos de variáveis:
  1. alocação direta: a variável é um apelido para uma posição na memória;
  2. ponteiro: a variável contém um endereço de memória e este sim contém a informação;
  3. referência: uma variação muito popular de ponteiro, usada nas linguagens mais modernas.


Primeira classe


Dado ou objeto de alto nível ou de primeira classe é qualquer informação que pode ser armazenada por uma variável.

Basicamente qualquer objeto de primeira classe pode ser passado como parâmetro ou recebido como retorno de uma função.

Para podermos trabalhar com closures, função precisa ser um objeto de primeira classe na linguagem.

Escopo


Escopo (em inglês namespace) é a «região» onde uma variável «existe», ou seja, terminando o escopo, a variável deixa de existir.

Em linguagens com boa coleta de lixo (garbage collection), quando não há mais variáveis referenciando um dado na memória, este também deixa de existir (a memória é liberada).

Você pode ter um escopo dentro do outro. As variáveis pertencentes ao escopo superior (escopo pai) existem no escopo interno, porque o escopo destas ainda não terminou.

Em C, Java, C++ e Perl, o escopo se inicia com abre-chaves ({) e termina com fecha-chaves (}), ou seja, todo e qualquer bloco de código é um escopo em si.

Em Python o escopo se inicia com a indentação de uma função ou classe e termina com a dedentação equivalente.

Em Lua, assim como em C, todo e qualquer bloco é um escopo em si.

Em Ruby, eu não faço a mínima... =P
Tem tempo que não mexo com essa linguagem.

Closures


Tendo esclarecido os conceitos anteriores, podemos falar de closures agora. =)

Imaginem que temos uma função (que tem seu escopo), dentro dela há outra função. Então o escopo da segunda função está dentro do escopo da primeira e, portanto, as variáveis da primeira existem no escopo da segunda.

Agora imaginem que na linguagem usada, função é um dado de alto nível e a primeira função retorna a segunda. Então, ao terminar sua execução, o escopo da primeira se encerra, mas o escopo mais interno não!

O que acontece?

O escopo da primeira função continua existindo «preso» ao escopo da segunda.

Isso é muito legal, porque podemos criar reiteradores mesmo se a linguagem não tiver este recurso diretamente disponível.

Por exemplo, criar um reiterador que devolva a sequência de Fibonacci (já repararam como gosto desta sequência?).

Em Perl temos:
sub mkfib {
my $a, $b = 0, 1;
return sub {
$a, $b = $b, $a+$b;
return $a;
};
};

my $fib = mkfib();


A cada chamada de $fib->() será retornado o próximo elemento da sequência. Em Perl, a palavra reservada my indica que aquela(s) variável(is) pertence(m) ao escopo atual (local). Se não for usado my, a variável será procurada no escopo pai e, se não existir, no anterior, até chegar ao global. Se a variável não existir no escopo global, será criada (no escopo global).

Vamos ver o equivalente em Python:
def mkfib():
c = [0, 1]
def f():
c[0], c[1] = c[1], sum(c)
return c[0]
return f

fib = mkfib()


Em Python, toda atribuição cria uma variável no escopo local (se ela não existir neste), portanto tivemos de usar uma lista para «enganar» a linguagem e poder alterar valores de variáveis do escopo pai.

O equivalente em Lua:
fib = (function ()
local a, b = 0, 1
return function ()
a, b = b, a+b
return a
end
end)()


Lua funciona como Perl (local equivale a my de Perl).

Contador


Só para arrematar, vou passar como exemplo um contador...

Em Perl:
sub mkcounter {
my $c = 0;
return sub {
return ++$c;
};
};

$count = mkcounter();


Em Python:
def mkcounter():
c = [0]
def f():
c[0] += 1
return c[0]
return f

count = mkcounter()


Em Lua:
count = (function ()
local c = 0
return function ()
c = c + 1
return c
end
end)()


[]'s

2007-01-19

Reblogging: bom de viola

Não é costume meu «reblogar», mas há coisas que valem a pena.

Vou fazer o seguinte, em vez de colocar o vídeo aqui, acho mais justo colocar um link pra página onde vi o vídeo:

Nação Livre – Bom de viola...

A técnica usada pelo violonista é conhecida como hammer-on (martelada). Isso sim é tocar violão!

[]'s

2007-01-12

Bom ou ruim?

Poliedro Outro dia quando respondi um comentário do Tiago ao artigo PHP estúpido, estava muito zangado com alguns assuntos e o pobre Tiago acabou levando a bronca sem culpa no cartório.

Mas de qualquer forma, tirando o tom agressivo a resposta foi muito boa e esclarecedora, segundo o Silvio, quase um artigo.

Já escrevi um artigo sobre o assunto, mas nunca é demais reiterar.

Como há um senso comum na Informática de que passado é passado, o que deixa os mais novos (geralmente programadores com menos de 10 anos de computação) sem um background muito sólido, e os leva a acreditar em «verdades absolutas» cantadas por grandes empresas e defensores ferrenhos desta ou daquela ferramenta.

Tipagem fraca × tipagem forte


Há uma crença de que a tipagem forte é muito superior à fraca, e não é bem assim.

Precisamos primeiro entender o que é uma coisa e o que é outra...

Tipagem fraca é quando os tipos usados pela linguagem não são muito bem definidos, são poucos ou se confundem entre si. Nesta definição, são linguagens fracamente tipadas C (éééé... C é fracamente tipada, pois os tipos se confundem), Perl (que possui pouquíssimos tipos) e PHP, por exemplo, e fortemente tipadas C++ (que é bem menos tolerante quanto a tipos do que C), Java, Python...

Há linguagens que ficam mais ou menos entre os dois, como Lua.

É incontestável que a tipagem forte controla melhor o que o programador pode ou não fazer, minimizando a probabilidade de ocorrer uma burrada grande, o que é bom quando o programador precisa de uma babá.

Mas se falamos de programadores crescidinhos, é o programador quem deve controlar a linguagem, não o contrário.

Tipagem dinâmica × tipagem estática


Mais um blá-blá-blá comum em discussões entre linguagens.

Vamos começar definindo...

Tipagem dinâmica é quando o tipo está associado ao valor constante, não à variável. Assim uma variável pode ter em momentos diferentes valores de tipos diferentes.

Tipagem estática é quando o tipo está associado à variável. Assim uma variável só poderá ter valores de um mesmo tipo ao longo de todo o programa.

Tipagem estática não é a mesma coisa que tipagem forte! Uma linguagem pode ter tipagem fraca e estática, fraca e dinâmica, forte e estática, forte e dinâmica ou qualquer coisa intermediária.


Novamente dizem que a tipagem estática é melhor que a dinâmica, o que não é uma verdade. É somente uma escolha entre caminhos que levam equidistantemente ao mesmo objetivo.

Só que, novamente, alguns programadores precisam de uma babá que os leve pela mãozinha através do caminho, e é isso que a tipagem estática faz.

Programadores criativos e maduramente cuidadosos se sentem mais livres com tipagem dinâmica.

Paradigma estruturado × orientação a objetos


Aqui se encontra um dos maiores mal-entendidos da história da programação: orientação a objetos presume programação estruturada.

Você não deixa de programar estruturadamente para programar orientado a objetos, mas simplesmente nao pode orientar a objetos sem programação estruturada!

Mas programadores mais jovens e entoxicados pelo lero-lero javista acham que uma coisa exclui a outra e que orientação a objetos é superior a programação estruturada.

Na verdade orientação a objetos é mais uma ferramenta que você pode usar e não a chave mestra para todas as portas... e muitas vezes pode atrapalhar em vez de ajudar – como usar uma pá para tirar um parafuso.

Programação scripting


Há uma noção errada amplamente divulgada de que programação scripting é inferior.

Novamente precisamos definir o que é programação scripting.

Um script é um programa geralmente interpretado (diretamente ou através de uma máquina virtual) que agrega recursos pré-programados.

O problema com esta definição é que quase tudo pode ser considerado linguangem de scripting, principalmente Java.

No entanto Java não é considerada linguagem de scripting e Python é. Portanto só podemos concluir uma coisa: classificar uma linguagem como scripting ou não é um ato puramente arbitrário.

Daí podemos deduzir sem medo de estar errados que esta classificação é um ato puramente pejorativo, apesar de eu pessoalmente não ter nada contra o termo scripting.

Conclusão


Só há uma conclusão possível: não acredite em tudo o que ouvir!

[]'s

2007-01-09

Isto é Capitalismo

É gente...

Quase sempre que converso com alguém sobre sistemas sócio-político-econômicos sou duramente criticado pro meus pontos de vista alternativos.

Vejam bem, antes de me rotular saibam que não sou comunista... por pouco. Acho as idéias de Karl Marx muito legais, mas um tanto utópicas.

Esclarecido o ponto, volto ao assunto principal: isto é Capitalismo.

Empresas transnacionais compraram dos governos terras «sem dono», colocando na estrada incontáveis indígenas e caboclos, e continuam a fazê-lo. Quem tem dinheiro pode...

Um grande defensor da soberania nacional e da Identidade Latino-americana foi assassinado na Bolívia pela CIA.

Isso para citar apenas grandes eventos passados... vamos chegar ao presente...

As pessoas são respeitadas por seus «contatos», ou seja, pela soma de dinheiro que pode ser gasta pelo conjunto de contatos de cada pessoa. Conhecimento, boa vontade, inteligência, nada disso tem importância (ou é hierarquicamente inferior ao capital potencial).

Não é meu objetivo final, mas quero passar pelo fato de uma modelo que cometeu atentado ao pudor em outro país consiga apoio legal no Brasil para criminosamente bloquear o acesso dos internautas brasileiros a um sítio internacional de hospedagem vídeos, que tanto contém besteiras quando vídeos úteis para estudo e trabalho, privando diversas pessoas, que não cometeram atentado ao pudor, de seu direito de acesso à informação.

Ou seja, uma única pessoa que foi pega em flagrante delito tem poder «legal» para prejudicar muitos e muitos brasileiros em pleno gozo de seus direitos. Isto é Capitalismo.

Vocês gostam do Capitalismo? Apoiam esta merda? Então aguentem! É assim que funciona.

Em outra oportunidade completarei meu raciocício, chegando à conclusão que realmente quero – agora não dá, não estou com cabeça pra tanto.

[]'s

PS.: Referências:
Aqueles que simplesmente não entendem (Ricardo Bánffy)
Sobre liberdade e justiça (Falcon_Dark)
Youtube bloqueado: Telefônica e Embratel avisam que vão seguir os passos da Brasil Telecom (Tatiana T – BR-Linux.org)

2007-01-06

América Latina

Oscar Niemeyer
Às vezes sinto que nós brasileiros somos alienados da América Latina.

Somos rodeados por países de língua espanhola, mas aprendemos o inglês como língua estrangeira, o que nos afasta de nossa verdadeira identidade cultura.

Fica então algo em que se pensar:

O sentimento de unidade latino-americana é o limiar de um novo tempo. O esforço de organização para eliminar a opressão dos poderosos e construir um destino maior e mais justo é o compromisso solene de todos nós.
(Orestes Quercia)


[]'s

PS: Hay que endurecer pero sin perder la ternura jamás! (Ernesto Che Guevara)

Reiterador III


Andei pensando e concluí que, como o primeiro artigo já foi voltado para programadores, o segundo deveria ter sido um pouco mais explicativo.

Introdução


O objetivo aqui é explicar um pouco mais de metatabelas e corrotinas através da criação de um reiterador.

Mas o que diabos é um reiterador?

Reiterador (em inglês iterator) é um objeto que percorre uma lista geralmente grande demais para ser carregada na memória, retornando cada elemento sem precisar carregar toda a lista de uma só vez.

Por exemplo, um cursor de uma consulta de banco de dados. A tabela retornada pela consulta pode ter 200MB ou mais, mas o cursor jamais vai ocupar mais espaço na memória do que o suficiente para manipular um único registro.

Como funciona?

O cursor aponta para o vazio. Quando seu valor é requerido (geralmente pelo método next()), ele avança para o primeiro registro e retorna seus campos. Quando é requerido novamente, ele avança para o próximo registro, retornando-o, e assim sucessivamente até o último.

É assim que funciona um reiterador.

Outro exemplo é um descritor de arquivo.

O descritor começa apontando para a posição 0 do arquivo. Quando seu valor é requerido, ele retorna o byte dessa posição e avança para a próxima posição, e assim até o fim do arquivo. O funcionamento é similar.

Vamos criar um reiterador muito simples que retorne cada elemento da sequência de Fibonacci.

Metatabela


Metatabela é um recurso da linguagem Lua que funciona de modo similar a uma classe em linguagens orientadas a objetos.

A metatabela é uma tabela que contém a chaves especiais para tratamento de chamadas. As tabelas que recebem a metatabela como sua trabalham de modo similar a instâncias.

Por questão de simplicidade passeremos a usar os seguintes termos:
- instância: uma tabela relacionada a uma metatabela (apesar de não ser o termo mais adequado);
- método: um par chave-valor onde o valor é uma função;
- atributo: qualquer outro par chave-valor de uma instância ou metatabela.


A chave __index da metatabela é chamada quando é feita uma tentativa de leitura de uma chave que a instância não possui.

Se o valor de __index da metatabela for uma tabela, a chave requerida é consultada nessa tabela. Por exemplo:

t = { a = 2 }
setmetatable(t, { __index = { x = 0, y = 3 } })


Então t.x retornará 0, pois o valor vem da tabela em __index.

Esta chave também pode conter uma função, onde o primeiro parâmetro é a instância e o segundo a chave. O valor é o retorno da função:

t = { a = 2 }
setmetatable(t, {
__index = function (t, k)
return "-- chave " .. k .. " --"
end
} )


Então t.x retornará a string «-- chave x --».

Já a chave __newindex da metatabela é chamada quando é feita uma tentativa de gravação em uma chave que a instância não possui. Seu valor é uma função cujos argumentos recebem a instância, a chave e o valor.

Criando a metatabela


Como nossa metatabela será um reiterador, vamos chamá-la iter. Podemos usar a própria metatabela para armazenar as chaves.

Esta é uma prática comum de programação em orientação a objetos em Lua: usar a própria metatabela como valor para a chave __index.

Precisaremos apenas de dois métodos: construtor e next().

Vamos criar primeiro a metatabela:

local iter = {}
iter.__index = iter
iter.__newindex = function (t, k, v)
-- Esta função apenas evita a criação de novas chaves
error("Chave " .. k .. " não existe")
end


O construtor


O construtor é o método que é executado na criação de uma instância, e torna muito mais simpática a instanciação em Lua.

A idéia é a seguinte: ao contrário dos demais métodos, self é a classe e o primeiro argumento será a instância. Um construtor padrão em Lua é:

function iter:new(o)
o = o or {}
setmetatable(o, self)
return o
end


Mas, como a metatabela iter é local (digamos, privada), o construtor também será. Precisaremos de um construtor público... é nessa função que começaremos a mexer com corrotina.

Corrotina


Corrotina é a biblioteca de Lua para criação de reiteradores.

O foco da biblioteca de corrotina é fazer algo similar a manipulação de threads, mas na prática se assemelha mais a reiteradores em Python (yield).

Como funciona?

A função coroutine.create() recebe uma função como parâmetro e retorna uma corrotina.

O tipo retornado para uma corrotina (função type()) é thread.


Quando a corrotina é passada como primeiro parâmetro para coroutine.resume(), a função da corrotina é executada até encontrar uma chamada a coroutine.yield(). Então coroutine.resume() retorna true e o parâmetro de coroutine.yield().

A cada chamada de coroutine.resume() a função da corrotina continua até encontrar novamente coroutine.yield().

Confuso? Vai clarear...

Construtor público


O construtor público precisa criar a corrotina com uma função que calcule os elementos de Fibonacci e passar a corrotina para a tabela que será transformada numa instância de iter:

function new()
local t = {}
t.co = coroutine.create(function ()
local a, b = 0, 1
while true do
a, b = b, a+b
coroutine.yield(a)
end
end)

return iter:new(t)
end


Esta é uma função simples (algoritmo reiterativo, hehe) para calcular Fibonacci. A cada chamada de coroutine.resume() a função correrá até o coroutine.yield(), que retornará o próximo elemento.

Método principal


Vamos criar o método next(), que tratará toda essa brincadeira e retornará um valor limpo:

function iter:next()
local _, r = coroutine.resume(self.co)
return r
end


A função coroutine.resume() retorna como primeiro valor true para indicar que tudo correu bem, e como segundo o elemento que queremos. Então isolamos o retorno (na variável r) e retornamos só o que interessa.

Criando um módulo compatível com 5.1


Precisamos tornar locais todas as bibliotecas e funções globais que usamos, depois criamos o módulo:

local coroutine = coroutine
local error = error
local setmetatable = setmetatable

module "fib"


Colocando tudo junto


local coroutine = coroutine
local error = error
local setmetatable = setmetatable

module "fib"

local iter = {}
iter.__index = iter
iter.__newindex = function (t, k, v)
-- Esta função apenas evita a criação de novas chaves
error("Chave " .. k .. " não existe")
end

function iter:new(o)
o = o or {}
setmetatable(o, self)
return o
end

function iter:next()
local _, r = coroutine.resume(self.co)
return r
end

function new()
local t = {}
t.co = coroutine.create(function ()
local a, b = 0, 1
while true do
a, b = b, a+b
coroutine.yield(a)
end
end)

return iter:new(t)
end


Salve tudo num arquivo (por exemplo, fib.lua), depois levante o interpretador e veja funcionando:

lua> require "fib"
lua> f = fib.new()
lua> for i = 1, 10 do print(f:next()) end
1
1
2
3
5
8
13
21
34
55


[]'s

2007-01-05

Reiterador II

Lua Versão «metatabela + corrotina» do artigo anterior:

local coroutine = coroutine
local math = math
local setmetatable = setmetatable
local table = table
local type = type

module "rand"

-- Criação da metatabela
local iter = { sec = {} }
iter.__index = iter
iter.__newindex = function (t, k, v)
error("Chave " .. k .. " não encontrada")
end

-- Construtor local
function iter:new(o)
o = o or {}
setmetatable(o, self)
return o
end

-- Método principal
function iter:next()
local _, r = coroutine.resume(self.co)
return r
end

-- Construtor público
function new(t)
-- É preciso receber um vetor
if type(t) ~= "table" then
error "Parâmetro deve ser um vetor"
end

-- Vetor vazio?
if table.getn(t) == 0 then
error "Vetor vazio"
end

-- Criação da corrotina
t.co = coroutine.create(function (t)
-- Inicialição
local m, e
coroutine.yield(nil)

-- Loop principal
while true do
m = table.getn(t)

-- Se o vetor estiver vazio, começa de novo
if m == 0 then
while table.getn(t.sec) > 0 do
table.insert(t, table.remove(t.sec, 1))
end
m = table.getn(t)
end

-- Seleciona um elemento aleatoriamente
e = table.remove(t, math.random(m))
table.insert(t.sec, e)
coroutine.yield(e)
end
end)

-- Passa a tabela principal para a corrotina
coroutine.resume(t.co, t)

return iter:new(t)
end


[]'s

2007-01-04

Reiterador

Lua Uma coisa fácil de fazer em Python é um reiterador (para quem gosta de estrangeirismos: «iterador», de iterator). Basta um simples comando yield e está tudo resolvido.

Estava pensando comigo mesmo: e em Lua?

Então resolvi fazer um objeto que retorne indefinidamente e de forma aleatória os elementos de um vetor, mas sem repetir até que todos tenham sido retornados. Em Python a gente resolve isso com uma função:

from random import choice

def rand_new(*args):
assert len(args) > 0
t1 = list(args)
t2 = []
while True:
e = choice(t1)
t1.remove(e)
t2.append(e)
if len(t1) == 0:
t1, t2 = t2, []
yield e


Para resolver este problema (pretensão =P) em Lua, decidi usar uma metatabela.

Vamos então criar a metatabela:

local iter = { sec = {} }
iter.__index = iter
iter.__newindex = function (t, k, v)
error("Chave " .. k .. " não encontrada")
end


Pronto. A chave sec vai funcionar como a lista t2 do código Python. A o próprio objeto (a parte indexada) vai funcionar como a lista t1.

Vamos agora criar o construtor:

function iter:new(o)
o = o or {}
setmetatable(o, self)
return o
end


Como vamos colocar isso dentro de um módulo, vamos criar uma função para retornar o objeto:

function new(t)
if type(t) ~= "table" then
error "Esta função recebe um vetor como parâmetro"
end

if table.getn(t) == 0 then
error "Vetor vazio"
end

return iter:new(t)
end


Vamos criar uma função para reiniciar o contador interno, ou seja, reabilitar todos os elementos do vetor:

function iter:reinit()
while table.getn(self.sec) > 0 do
table.insert(self, table.remove(self.sec, 1))
end
end


Agora vamos criar o next() (como no reiterador de Python):

function iter:next()
local m, resp
m = table.getn(self)

-- Esvaziou? Recomeça do princípio...
if m == 0 then
self:reinit()
m = table.getn(self)
end

resp = table.remove(self, math.random(m))
table.insert(self.sec, resp)

return resp
end


Primeiro determinamos quantos elementos ainda estão no vetor principal (se não tiver nenhum, reinicia). Escolhemos um aleatoriamente, removemos, inserimos no vetor secundário e retornamos o elemento.

E é só isso!

Agora vamos transformar esta festa toda em um módulo!

Se você está usando Lua 5.1 ou possui o Compat-5.1, basta no início do arquivo transformar em locais todas as funções globais que estamos usando e em seguida declarar o módulo:

local error = error
local math = math
local table = table
local setmetatable = setmetatable
local type = type

module "rand"


Se você está usando Lua 5.0 e não possui o módulo Compat-5.1, talvez isto não funcione, então, em vez disso, transforme a função new() em local e no final do arquivo declare a seguinte tabela:

rand = { new = new }


Vamos testar agora:

lua> require "rand"
lua> a = rand.new { 1, 2, 3 }
lua> =a:next()
3
lua> =a:next()
1
lua> =a:next()
2
lua> =a:next()
2
lua> =a:next()
1
lua> =a:next()
3
lua> =a:next()
1


[]'s

2007-01-01

Feliz 2007!!!

Começamos um novo ano com aquele mesmo gás anual, que sabemos terminará até o Carnaval no máximo, mas ainda assim gostaria de traçar alguns planos:

Vou continuar em 2007 a divulgação da língua internacional, em prol das culturas que estão sendo devastadas pela globalização.

Também vou continuar incentivando o uso da linguagem Lua, um bem cultural nacional, que os programadores brasileiros, se fossem um pouco mais perceptivos política e culturalmente, estaria usando e divulgando. Ainda também a linguagem de programação Python, uma das mais poderosas que já conheci.

Outra coisa que devo continuar é a incentivar o Software Livre, por motivos filosóficos sim, digam o que disserem os trasgos que só enxergam o lucro.

Convido também todos os que têm um pouco de consciência a fazer o mesmo – ou algo similar.

Que tal a campanha da sopa?

Que tal colaborar para com iniciativas de caridade, como a LBV?

Que tal simplesmente fazer o que é certo quando é tão fácil e tentador fazer o contrário?

Lugar comum? Baboseira altruísta? Talvez... mas que tal tentar?

Já pensaram: e se der certo?