2006-09-29

Quantos o diabo matou?

Baal Gente, este texto que segue a baixo me foi enviado por um amigo meu de mente aberta e é de autor desconhecido. Na verdade o autor postou o texto num fórum e não quis se identificar, portanto o mais correto seria dizer que é de autor anônimo.

Não concordo como todos os pormenores do texto e não tenho a pretenção de fazer-lhe apologia, mas concordo com o sentido geral e gostaria de dar a você leitor a chance que tive de refletir sobre o assunto. Acho esse tipo de crítica muito importante para todo religioso.

Segue então o texto:

QUANTOS O DIABO JÁ MATOU? ZERO! E DEUS? LEIAM

O Antigo Testamento é um receituário de dominação prescrito pelos judeus aos povos reféns do banditismo israelita. O próprio nome Israel significa: simaquia com Deus (Deus como seu aliado em guerra).

Raciocine: No Antigo Testamento, Deus é retratado como uma propriedade exclusiva dos judeus (hebreus). Por quê? Porque foram eles quem inventaram Deus! A mulher é descrita como um objeto do homem, no pentateuco. Por quê? Porque aquele conjunto de livros foi escrito integralmente por homens, daí o cunho machista. Ora, se o corpo humano consta de 206 ossos, como poderia a mulher se resumir à fração de 1/206 de um homem, já que Eva foi feita duma costela? (Gen. 2:22).

Outra incoerência: ainda, no Antigo Testamento, Deus aparece na condição de precursor dos métodos de destruição em massa (o aniquilamento de Sodoma e Gomorra), Gen. 19:1-29, algo assemelhado a uma explosão nuclear. Nas dez pragas do Egito, (Ex. 7:14 e 11:10), Deus teria sido o preconizador da guerra química (envenenando as águas do rio Nilo), e da guerra biológica (disseminando gafanhotos pelo reino de faraó). Será se Deus, onisciente e todo-misericordioso, teria cometido aquelas barbáries? Mesmo porque o Senhor já sabia previamente que, no segundo milênio do nascimento do Seu filho unigênito, Seus ensinamentos genocidas iriam habilitar o Bin Laden para atentar contra uma nação protestante, os EUA, que se dizem ser habitados por um povo "santo e escolhido"?

A Deus também o papel de pivô do primeiro fratricídio lavrado na bíblia, ao ficar grato pelas ovelhas recebidas de Abel, e se mostrando indiferente para com as batatas de Caim. Percebendo que o Senhor não reconheceu a sua humilde oferta na mesma medida das ovelhas doadas pelo seu irmão Abel, isso despertou um sentimento de inveja em Caim; levando o segundo a assassinar o primeiro. (Gen. 4:8).

Aqueles escritos são apenas malícias humanas. Em estando sentenciadas nas Sagradas Escrituras, todas as atrocidades perpetradas pelos judeus às outras tribos recebiam uma conotação "divina" e, como tal, eram legitimadas e justificadas. Ainda hoje, israelenses (judeus) e árabes (muçulmanos) se arrastam em um conflito milenar e sangrento, nas terras da Palestina. Tudo teria começado com a interpretação preconceituosa de uma lenda bíblica. Ismael, filho bastardo de Abraão com a escrava egípcia, Agar, teria dado origem ao povo árabe (Gen. 16:5-15). E Isaac, filho legítimo de Abraão (ex-Abrão) com a sua verdadeira esposa, Sara (ex-Sarai), haveria sido o progenitor dos judeus (Gen. 21:1-7). Então, para desqualificá-los, os judeus tacham os árabes de descenderem do filho duma puta. Com efeito, se considerarmos aquelas narrativas nefastas (assassinatos, seqüestros, estupros, pilhagens; por exemplo, leiam: Num. 31:17-18; Deut. 20:10, 13 e 14; 23:13; 25:11 e 12; 2º Reis 19:35; Juízes 8:10; 2ª Cron. 28:6; 13:17 e 14:19; Isa. 37:36......); uns executados pelo próprio Deus, outros pelos Seus jagunços: Davi, Moisés etc., (cumprindo ordem divina), então, temos de dar a mão à palmatória, e concordarmos com o Santo Ofício, como tendo sido um cumprimento fiel às Sagradas Escrituras por parte da Igreja Católica. Acaso, imitar os ensinamentos bíblicos constitui um pecado ou uma virtude? Inquisição que não foi exclusiva apenas do catolicismo, o protestatismo também valeu-se de morticínios para fazer valer seu proselitismo. João Calvino, o pai dos presbiterianos, mandou queimar na fogueira o médico espanhol, Michel Servert Grizar. E tantos outros atos sangrentos promovidos pelos protestantes.

Hoje muitas pessoas ficam horrorizadas ao saberem que, nas favelas das grandes cidades, os comerciantes são obrigados a pagar pedágios para os chefes do tráfico local, se quiserem continuar exercendo suas atividades mercantis. Ora, ora esse critério de sujeição extorsiva já era praticado pelos "capangas de Deus", quando submetiam determinadas comunidades à condição de Cidades Tributárias. Para sobreviverem sem serem molestadas pelos judeus mandões, mafiosos, tais comunidades-reféns tinham de transferir grande parte de sua força de trabalho e riquezas aos seus "protetores". (Vide em 1ª Cron. 18 e 2º Sam. 8).

O mais gozado e incoerente de tudo isso é que Deus, retratado como bandido e sanguinário no Antigo Testamento, ainda assim, Ele personifica a figura do BEM. Ao passo que o diabo, embora nunca tenha matado ou roubado alguém, paradoxalmente, foi eleito como a fonte do MAL.

(Autor anônimo)


Pensem bem sobre o assunto agora.

[]'s

2006-09-22

Voto em vão

Dana Carvey Ontem me perguntaram em quem pretendo votar para governador. Cometi o erro de responder.

Fui então duramente criticado, segundo meus críticos porque vou jogar meu voto fora.

Mas tenho então de votar no candidato que lidera as pesquisas? Ou no segundo lugar? Pensei que o voto fosse um exercício de cidadania, não de dominação (na verdade, escravidão intelectual)!

Tudo bem, não concordo com essa quantidade enorme de candidatos a um cargo único, acho que isso só visa dividir os votos, mas nem por isso vou me render aos líderes de pesquisas. =P

Algumas dicas para quem vai votar:

  • Conheça as propostas dos candidatos, veja se elas atendem a necessidades sociais ou se não passam de pagamento pelo seu voto.
  • Conheça o passado dos candidatos pra saber se eles costumam cumprir as propostas ou não.
  • Não se deixe levar por pesquisas, que só servem para manipular seu voto.
  • Conheça as pesquisas. =P
  • Tenha a mesma preocupação com qualquer voto, seja pra presidente ou deputado estadual.
  • Se você votar com consciência, mesmo que seu candidato não vença, não foi em vão. Seu voto não foi jogado fora. Saiba que pelo menos você está insentivando seu candidato – e deixou de votar num político desonesto só porque todo mundo votou nele.


É tudo o que tenho a dizer.

[]'s

2006-09-19

As doze mais

Poliedro Recentemente o sítio NotíciasLinux.com.br divulgou uma lista das «10 linguagens de programação que você deveria aprender agora mesmo».

Nós (Rodrigo Cacilhas e Walter Cruz) conversamos e decidimos fazer nossas próprias lista. Qual não foi nossa surpresa ao descobrir que estas só divergiam em duas linguagens!

Então resolvemos escrever um artigo sobre as «12+». =)

Segue então a lista em ordem alfabética.

C



rank Cacilhas: 1
rank Walter: 3


C é a raiz de todas as linguagens modernas. Ninguém que precise de desempenho e confiabilidade abre mão de C.

Apesar de ser uma linguagem de alto nível – não confunda notação matemática com baixo nível! –, proporciona um melhor entendimento sobre o funcionamento do sistema, ajudando o programador a ter um pensamento menos dependente das peculidades de cada linguagem. É muito boa para explicar sobre o funcionamento de um computador nos seus detalhes.

C#



rank Cacilhas: 4
rank Walter: 10


É a melhor coisa que a Microsoft já fez. Tem lá seus problemas – como não poderia deixar de ser –, mas é uma linguagem eficiente e a melhor escolha para programação .NET.

Sem falar que é um plágio de Java.

C++



rank Cacilhas: -
rank Walter: 4


É uma linguagem importante devido à quantidade de aplicações desenvolvidas e também porque é a mais neutra das linguagens orientadas a objeto.

Ocupou um lugar relativamente importante na história da orientação a objetos, e foi mercadologicamente suplantada por Java.

Assim como C, ajuda o programador a ter um pensamento mais livre, a livrar-se da escravidão imposta por outras linguagens, apesar de não passar de um «C mais lento».

Cobol



rank Cacilhas: 10
rank Walter: -


Há um mercado legado muito grande de aplicações Cobol no Brasil que necessitam de manuteção – e constantes reindexações de bases de dados. =P

Em cinco ou dez anos talvez esta realidade mude, mas atualmente programadores Cobol são necessários e estão se tornando raros.

Fortran



rank Cacilhas: 9
rank Walter: -


Um linguagem antiga e ultrapassada sim, mas muito usada em ambiente acadêmico: pós-graduação e pesquisas.

Seu foco em análise numérica é perfeitamente conveniente para satisfazer as necessidades da Computação Científica e dificilmente outra linguagem conseguirá tomar seu lugar.

Portanto, para quem não quer ser mais uma batata no saco, é importante conhecer Fortran.

Java



rank Cacilhas: 2
rank Walter: 5


Java foi o que na verdade trouxe a orientação a objetos para a boca dos programadores.

Traz em seu bojo uma cultura que muitos chegam a pensar que é originada de Java, mas isso é um engano. Poderíamos citar dentre eles: Design Patterns, máquina virtual (já presente no Smalltalk na década de 80), refatoração (outro que nasceu na comunidade Smalltalk) e Programação Extrema (outro filho do Smalltalk).

O que mais dizer de Java? Não é lá grande coisa, nem se compara a C ou Fortran, mas funciona e bem.

Quando o front-end é mais importante que o back-end, Java é o que há. E ainda trabalha bem em aplicações de back-end – não tão bem quando as outras, mas a homogeneidade com o front-end compensa.

Um dos grandes problemas que eu vejo em Java é sua quase onipresença. Tem um problema? Não importa qual, mas a solução é Java. Outro grande diferencial é que essa é a linguagem que fala empresariês. É a linguagem que tem mais siglas, mais nomes e expressões complicadas, que no final acabam por se mostrar coisas simples na maioria dos casos. Não me entendam mal – depois de anos, resolvi aprender Java, e de fato estou até gostando. Existem na verdade duas coisas chamadas Java: a plataforma Java (JVM) e a linguagem Java. Apenas recentemente, com o advento do .NET a comunidade Java se tocou que nem todos gostavem de Java e passaram a alardear que outras linguagens poderiam rodar na JVM. Será que isso veio tarde demais? Espero que não.
(Walter)


Lua



rank Cacilhas: 8
rank Walter: 6


A linguagem de extensão por excelência! Combinada a C é imbatível.

Como se já não bastasse dizer que Lua conquistou seu nicho no mercado de animação, nós brasileiros temos um compromisso patriótico com esta linguagem (em vez de tratá-la com ignorância sistemática, como temos feito).

Sem contar que Lua tem méritos próprios. Metatabelas e orientação a objetos em Lua são coisas totalmente originais.
(Walter)


Perl



rank Cacilhas: 5
rank Walter: 8


Perl é uma linguagem pra gente grande. Uma das mais eficientes, não deixando a desejar a nenhuma outra.

É uma linguagem de propósito geral, mas se dá muito bem na Computação Científica, e serve como base de entendimento para outras linguagens mais modernas nela baseadas.

Outra curiosidade de Perl é ter a capacidade de irritar os trolls defensores de verdades absolutas, já que, sendo uma linguagem estrutura de tipagem fraca e orientada a objetos – ao contrário do que dizem os trolls –, é mais eficiente e aplicável do que qualquer linguagem da moda.

Python



rank Cacilhas: 3
rank Walter: 1



Python é tudo o que Java e Ruby pretendem ser.

Simples, clara, multipropósito, fortemente orientada a objetos, fortemente tipada e explícita. Sua sintaxe é clara e fácil, permitindo que iniciantes possam aprender Python rapidamente mesmo sem ter conhecimento algum de programação, mas ao mesmo tempo possui recursos avançados, como metaclasses, e incontáveis módulos, o que permite o desenvolvimento de aplicações complexas, como o Zope.

Assim temos uma linguagem – talvez a única – que faz a ponte entre o iniciante e o programador avançado.

Para saber mais veja Introducing Python.

Na minha opnião, é uma das melhores linguagens pra ensino.
(Walter)


Ruby



rank Cacilhas: 7
rank Walter: 7


Vem ganhando um certa importância atualmente, principalmente por causa dos programadores Java frustrados, mas que não querem dar o braço a torcer para Python e não aguentam esperar pelo Groovy, que é uma mistura de Ruby e Java, só que abençoada pelo JCP.

É uma linguagem da moda, mas faz coisas legais, como Ruby on Rails.

Embora seja muito semelhante a Python na superfície, são bichos de espécies diferentes. Ruby nasce do cruzamento de Perl com Smalltalk, e Python herda da linguagem ABC. Isso é algo importante de se lembrar.
(Walter)


Smalltalk



rank Cacilhas: -
rank Walter: 9


É a orientação a objetos por excelência. Mais antiga que C, quase todos os paradigmas que têm sua criação erroneamente atribuída a Java foram desenvolvidos no Smalltalk (vide seção sobre Java).

É uma linguagem de propósito geral, mas focada na interface com o usuário, há ferramentas profissionais interessantes, como Cincom VisualWorks.

Considero uma ironia que PHP tenha tido um grande sucesso e Smalltalk tenha ficado sempre em segundo plano. É particularmente chatinha de aprender – eu tentei fazer qualquer coisinha aqui e sempre me atrapalho. Isso porque a mente da maioria dos programadores já está viciada em sintaxes C-like. A história da informática seria certamente muito diferente se Smalltalk tivesse alcançado o merecido sucesso. Mas isso é díficil para quem está sempre um passo à frente.
(Walter)


SQL



rank Cacilhas: 6
rank Walter: 2


É impossível manter e interfacear uma base de dados sem conhecer seu funcionamento, e nada melhor para isso do que conhecer ANSI-SQL.

Considerando os principais bancos livres, podemos subdividir este tópico em três:

ANSI-SQL


Cobertor curto, mas conhecendo – e entendendo – o ANSI-SQL, é possível entender qualquer querência estruturada.

MySQL


O MySQL implementa um SQL ligeiramente diferente, mas nada de assustar. =)

PL/pgSQL


Sem o conhecimento das funções e peculiaridades do PostgreSQL, ele não passa de uma alterativa gorda e gulosa ao MySQL.

Mas com o entendimento do PL/pgSQL, o PostgreSQL se torna a mais poderosa das ferramentas de banco de dados.

Omissões Notáveis.

PHP
PHP é na minha opinião uma linguagem de desenho ruim, e que o passar do tempo apenas acentua isso.

JavaScript
Embora seja praticamente impossível desenvolver para a web sem ela, creio que ela já fica coberta pelo tópico Lua. Lua é muito semelhante à JavaScript, com objetos de primeiro nível, closures, e sintaxe parecida.
(Walter)

The Geek Code

-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/H d? s:+ a C+++$ UL++$ P+>++ L++ E--- W++ N o K- w--
O>++ M>+ V- PS+ PE-- Y PGP(+) t+ 5 X+ R++>+++ tv+ b+(++)
DI- D+ G- e+(++)>++++ h---- r+++ y+++
------END GEEK CODE BLOCK------


[]'s

2006-09-15

Orientação a objetos em Perl

Uma das linguagens mais poderosas que há é Perl. Criada por Larry Wall em 1987 com base em C, Lisp, AWK e sed, Perl se tornou a base de diversas linguagens modernas, como Python e Ruby.

Possui uma abordagem sintática ligeiramente diferente, resultante de seu lema: «há mais de uma forma de fazer algo». Sua tipagem estupidamente fraca (só três tipos básicos, escalar, vetor e vetor associativo ou hash, mais alguns menos usados, como soquete) ajuda mais do que atrapalha, devido a sua abordagem, o que deixa os defensores da tipagem forte vermelhos de raiva.

Só que a implementação Perl de orientação a objetos é no mínimo excêntrica. Não usei outro adjetivo, como «alienígena», ou «transcendental», porque prefiro reservar estes para a implementação Perl de multithreading (vide as manpages perlthrtut e perlothrtut).

Há uma reformulação de POO para Perl chamada reform, mais parecida com Ruby, mas ainda não consegui fazer funcionar direito.


Em Perl, as classes são chamadas «pacotes», e são declaradas com o operador package (óbvio =P). O final do pacote é onde termina o arquivo ou onde é declarado um novo pacote. Caso o programador queira começar o programa em si no mesmo arquivo onde são criados os pacotes, basta declarar o início do pacote main:

package main;


Mas a forma mais elegante é criar um pacote .pm (por exemplo, exemplo.pm) e importanto o pacote no arquivo .pl (use exemplo;).

O método construtor é chamado new e o destruidor DESTROY (com letras maiúsculas mesmo). Há um procedimento padrão no construtor, que deve ser executado invariavelmente: (1) determinar a classe, (2) criar a instância, (3) transformar a instância numa instância «real» da classe (com o operador bless) e (4) retornar a instância pronta.

Alguns passos podem ser executados simultaneamente.

Vamos a um exemplo: a criação de uma classe Pessoa, com os atributos nome e ano_nasc (ano de nascimento):

package Pessoa;

sub new {
my $this = shift;
my $class = ref($this) || $this;
my $self = {
nome => shift,
ano_nasc => shift
};
return bless $self, $class;
}


Funções em Perl recolhem os parâmetros no vetor especial @_. No caso de métodos, o primeiro argumento é a instância escopo do método, assim como Python.

O operador shift retorna o «próximo» elemento do vetor – não sendo informado qual vetor, o padrão é @_. Se for a primeira execução de shift, retorna o primeiro elemento, se for a segunda, retorna o segundo elemento, e assim por diante.

Assim, $this recebe o primeiro argumento, que é o escopo de execução, ou seja, uma representação da própria classe (diferente de todos os demais métodos =P). O próximo comando refina este dado.

A declaração de $self cria escopo escalar semelhante a um hash, cujas chaves são nome e ano_nasc, e os valores são respectivamente o segundo e o terceiro elementos de @_.

O último comando faz duas coisas: transforma $self em uma instância verdadeira de $class (bless) e retorna a instância (return).

Bem, se você não conseguiu acompanhar até aqui, aconselho voltar lá em cima e começar de novo. =P


Vamos agora criar dois métodos! Um para retornar nome e outro para retornar a idade (calculada a partir de ano_nasc). Primeiro o nome:

sub nome {
my $self = shift;
my $v = shift;
$self->{nome} = $v if ($v);
return $self->{nome};
}


O primeiro comando atribui o escopo atual (a instância) a $self, depois a variável escalar $v recebe o próximo argumento (se não houver, recebe undef, equivalente a null de Java). Se foi passado algum parâmetro, este será atribuído à chave (atributo) nome, depois o valor deste é retornado.

Em suma, $inst->nome retorna nome. =)

Agora vamos à idade:

sub idade {
my $self = shift;
my (
$seg, $min, $hora,
$dia, $mes, $ano,
$dsem, $dano, $isdst
) = localtime(time);
return (1900 + $ano - self->{ano_nasc});
}


Novamente o primeiro comando atribui o escopo atual (a instância) a $self.

O próximo comando parece meio estranho, mas é só olhar melhor: localtime(time) retorna a hora local na forma de um vetor de nove posições, onde as três primeiras são a hora e as três seguintes a data (as três últimas também não são complicadas, e são até bem úteis). Assim conseguimos atribuir o número do ano a $ano.

Só que o número do ano em Perl é dado a partir de 1900! Então 2006 é retornado como 106.

Por último é retornada a diferença entre o ano atual (1900 + $ano) e o ano de nascimento atribuído à instância (ano_nasc).

Herança



Agora a coisa fica melhor!

Os defensores de linguagens orientadas a objetos dizem que Perl não é orientado a objetos e pronto, principalmente os programadores C++ e Java. Estranho isso.

Por que estranho?

Porque Perl além de suportar orientação a objetos, suporta herança múltipla, algo que Java não suporta. =P


Em Perl, a herança (simples ou múltipla) é implementada através do vetor @ISA.

Como exemplo, será criado um pacote Retangulo, com o método desenhar e as chaves (atributos) altura e largura, e será criado um pacote filho Quadrado:

(¡NOVO! Corrigi alguns erros de digitação no código seguinte que poderiam impedir o funcionamento do programa ¡NOVO!)

package Retangulo;

sub new {
my $this = shift;
my $class = ref($this) || $this;
my $self = {
altura => shift,
largura => shift
};
return bless $self, $class;
}

sub desenhar {
my $self = shift;
foreach (1 .. $self->{altura}) {
foreach (1 .. $self->{largura}) {
print '(*)';
}
print "\n";
}
}

package Quadrado;
@ISA = qw/ Retangulo /;

sub new {
my $this = shift;
my $class = ref($this) || $this;
my $lado = shift;
my $self = new Retangulo($lado, $lado);
return bless $self, $class;
}

1


[update 2008-09-09]Fica mais claro fazendo assim:
package Quadrado;
use base qw/ Retangulo /;
[/update]


Não há nada de novo no pacote Retangulo. Talvez o foreach, que repete o loop para cada elemento do vetor informado (o elemento atual é atribuído à variável especial $_). Veja a manpage perlintro.

O pacote interessante é Quadrado. Logo de cara temos a atribuição de @ISA. O operador qw «quebra» a string fornecida (entre / /) em um vetor, onde cada palavra (qw = queue of words, lista de palavras) é um elemento. É aconselhável usar qw sempre que for feita uma atribuição a @ISA.

Assim, Retangulo foi atribuído a @ISA de Quadrado, tornando este filho do primeiro.

O construtor é bastante simples, nada diferente do que foi visto até aqui – obs.: $lado está recebendo o primeiro parâmetro (segundo argumento, o primeiro é o escopo).

A operação mais diferente é a atribuição de $self, que chama o construtor do pacote (classe) pai. Repare que, da forma como está sendo feito, as duas chaves (altura e largura) receberão o valor de $lado (definição de quadrado, lembra?).

Para testar, salve este trecho de código como formas.pm, então crie um arquivo teste.pl:

#!/usr/bin/perl

use formas;

print "Qual o tamanho do lado do quadrado? ";
chomp($_ = <>);

my $sq = new Quadrado($_);
$sq->desenhar;

exit;


Execute então o script:

$ perl teste.pl
Qual o tamanho do lado do quadrado?


Informe um valor (5, ou 12, ou o que você quiser), pressione <Enter> e veja o resultado.


Espero que alguém tenha se empolgado para aprender Perl. =)

[]'s

Referências:

2006-09-13

Metaclasses: singleton

Brincando na aula de PRJ no ISTCC-P, surgiu o assunto singleton (a página em inglês é muuuuito mais completa), que é quando queremos que uma determinada classe tenha somente uma instância, e esta instância seja retornada na tentativa de se criar novas conexões.

Complicado? Que nada! Vou dar o mesmo exemplo que o professor deu: imagine que seu programa tenha uma conexão com um banco de dados. Cada vez que uma função do programa tente criar uma conexão, esta receberá a conexão que já foi criada.

Simples! Em Java isso é feito «bloqueando» o construtor da classe e usando um método para intermediar esta requisição:

class Conexao {
//Atributos
...
private static Conexao inst = null;

//Metodos
private Conexao() {
// O construtor é privado!
...
}

public static Conexao nova() {
// Este método fará as vezes do construtor
if (inst == null)
inst = new Conexao();
return inst;
}
...
}


Então, para criar uma conexão, não será usado new, mas o método nova():

Conexao conn = Conexao.nova();


Funciona. =)

Mas o grande problema aqui é que singleton não é transparente. É preciso estar atento e não usar new, que é a forma natural de se obter uma instância de classe. =P

Outras linguagens já têm uma abordagem diferente, possibilitando a criação de singleton transparente. As duas que comentarei aqui são Python e Ruby.

Ruby



Como Ruby não é meu forte, vou falar desta linguagem primeiro. É extremamente simples fazer singleton em Ruby:

requires 'singleton'

class Conexao
include Singleton
...
end


Bastou um include! Isto é incrivelmente simples, prático, mas tem um pequeno problema pra quem está tentando entender: como é que funciona?

Fica aí a dúvida pros rubyistas explicarem nos comentários. =)

Singleton em Python usando herança



Já Python é outra história. Como sou programador Python (La Batalema Pitonisto, lembram?) posso usar melhor esta linguagem para mostrar como as coisas funcionam.

Uma forma de fazer singleton em Python é usando herança. Assim podemos criar uma classe Singleton que implemente a funcionalidade (feature) desejada e herdar as demais classes desta.

Bem, em Python o construtor é __init__(), mas há um método que é chamado antes do construtor, que é __new__(), e funciona de forma muito parecida com new de Perl. Ele cria a nova instância e a retorna.

Na verdade, em Python quando fazemos:

a = X(b, c)


Por trás o que está acontecendo é:

a = X.__new__(X, b, c)
a.__init__(b, c)


Então podemos sobrescrever este método para termos singleton. A idéia é que, se já houver uma instância, o __new__() retorne esta instância em vez de uma nova:

class Singleton(object):

__inst = None

def __new__(cls, *args, **kw):
if cls.__inst is None:
cls.__inst = object.__new__(cls)
return cls.__inst

def __copy__(self): #(trecho novo de código!)
return self

def __deepcopy__(self, memo=None):
return self


Então temos o atributo privado de classe __inst que contém nada (None) na criação da classe, mas depois será uma referência à instância única.

O método __new__() está preparado para receber argumentos genéricos (*args, **kw), mas não fará nada com eles – é problema do __init__(). A função do __new__() é verificar se já existe a instância única, se não existe, cria, depois retorna ela.

Podemos usar a herança desta forma:

class Conexao(Singleton):
...


Ou seja, funciona exatamente como em Ruby.

Agora vamos à crítica!

O grande problema aqui é justamente a sobrescrita um método geralmente esquecido...

Isso pode gerar uma série de problemas quando surge a herança múltipla ou quando o método é novamente sobrescrito – ou foi também sobrescrito por outra classe pai.

Para contornar estes problemas uma boa saída é o uso de metaclasses.

Singleton em Python usando metaclasse



Em Python classes são objetos! São instâncias de type. Metaclasses são classes filhas de type, portanto suas instâncias também são classes.

Podemos criar uma metaclasse que tenha procedimentos que precedam o construtor e o chamem só se for preciso.

Assim as classes instância da metaclasse podem ser filhas de outras classes e possuir até herança múltipla sem se preocupar com sobrescrita de métodos – pois todo tratamento é realizado num escopo ainda mais protegido.

Numa metaclasse o método que precede o construtor das classes instância é – por motivos óbvios para programadores Python – __call__().

Vamos criar então a metaclasse! Vou chamar de unique em vez de singleton (Por quê? Porque eu gosto, ora pois!):

class unique(type):

def __init__(cls, name, base, dict):
super(unique, cls).__init__(name, base, dict)
cls.__inst = None
cls.__copy__ = lambda self: self #(nova linha!)
cls.__deepcopy__ = lambda self, memo=None: self #(nova linha!)

def __call__(cls, *args, **kw):
if cls.__inst is None:
cls.__inst = super(unique, cls).__call__(*args, **kw)
return cls.__inst


Esta metaclasse é bela! Vamos dissecá-la:

O construtor chama seu super (construtor da classe pai, type) e depois, a única coisa que faz de diferente é criar um atributo privado de classe __inst. Só que este atributo é «mais privado» do que os normais. =)

Aqui o escopo para o atributo privado não é a classe, mas unique (a metaclasse). Podem imaginar o nível de proteção disso? É como em C++, só que funciona. =)

Bem, o método __call__() faz exatamente o mesmo que __new__() no exemplo que usa herança, só que de forma mais eficiente. A implementação disso poderia ser:

class Conexao(object):

__metaclass__ = unique

...


Simples! E sem os problemas que poderiam vir com o uso de herança.

Mas aí vem um espírito de porco qualquer e pergunta:

Peraí! E se eu quiser usar também outra metaclasse, como autoprop?

Ahá! Não é tão complicado assim!

class Conexao(object):

__metaclass__ = type("__metaclass__", (autoprop, unique), {})

...


Complicou? É realmente... o uso de type não é tão intuitivo... =P

Mas há uma forma mais clara (aliás, eu prefiro) de fazer isso!

class Conexao(object):

class __metaclass__(autoprop, unique):
pass

...


Acho que é só isso! Comentários – ou melhor, complementos – por favor!

[]'s

Leitura recomendada:

2006-09-11

O Caçador de Crocodilos

Resolvi escrever sobre este assunto somente agora, pois somente agora consegui digerir o caso...

Steve Irwin, mais conhecido como o Caçador de Crocodilos, foi o diretor do Australia Zoo, fundado por seus pais Bob e Lyn Irwin em 1970.

A notícia de sua morte me foi dada da seguinte forma: «dá uma olhada no Google... aquele idiota dos crocodilos morreu»...

Tenho pena dessas pessoas que pensam assim. Vivem num mundo pequeno e sem sentido. Aquele «idiota» foi uma das pessoas mais admiráveis de nosso tempo, comparável a Jacques Cousteau.

Para dar uma pista da falta que Steve Irwin fará no mundo, segue uma citação dele:

Preservação ambiental é meu trabalho, minha vida, é tudo que sou. (Steve Irwin)


Vamos sentir saudades...

2006-09-01

Vírus

Algumas pessoas – de respeito até – dizem por aí que não existe vírus para GNU/Linux porque ele ainda não é tão usado quanto o Windows®, porém basta que o GNU/Linux se difundir mais para que comecem a aparecer os vírus.

Mas pensem só: por que então não há vírus para outros sistemas operacionais famosos?

Existem outros tipos de programa malicioso para GNU/Linux (e outros sistemas operacionais), como os worms, e com o aumento do uso do GNU/Linux consequentemente haverá o aumento desses tipos de programas. Mas não vírus.

O fato é o seguinte: não existe vírus pra GNU/Linux e nem nunca vai existir. Na verdade, «vírus» só existe pra Windows® e ponto.

Bem, é uma afirmação meio radical, não é? Mas ela tem base e vamos defendê-la neste artigo.

O Windows® possui um recurso em seu gerenciamento de processos que nenhum outro sistema operacional possui (pelo menos nenhum que eu conheça). O vírus é um mau uso desse recurso.

Mas que recurso é esse?

Quando um programa é executado, ele se torna um processo (task), ou seja, processo é um programa em execução. O sistema operacional mantém um controle de quais são os processos executados e o estado de cada um.

Cada processo possui pelo menos um fluxo de procedimentos, que é uma execução linear de comandos. Este fluxo é chamado thread. Alguns processos possuem mais de um fluxo – o que é chamado multithreading.

Só que multithreading é transparente para o sistema operacional! Quem gerencia os fluxos concorrentes é o próprio processo – inclusive o programador deve programar isso explicitamente.

Então cada processo possui um controle de quais são os fluxos atuais. Porém, reiterando, isso é transparente para o sistema operacional.

No caso do Windows®, a coisa é um pouco diferente.

No Windows® quem controla os fluxos dos processos é o cerne. É um recurso interessante, pois o sistema operacional pode iniciar novos fluxos em um processo ou interferir no processo encerrando alguns fluxos.

Agora, este recurso abre uma possibilidade de mau uso: um programa pode acessar o cerne e, através dele, se propagar para dentro de outros processos em execução.

Um vírus é isso! É um fluxo (thread) dentro de um processo que se replica para dentro de outros processos.

Em outros sistemas operacionais isso não é possível, pois o sistema nem sabe dos threads, então cada processo só possui threads que lhe pertencem. Já no Windows® o sistema pode interferir nos threads dos processos.

Não podemos de todo culpar a Microsoft por querer acrescentar recursos especiais – e inusitados – em seu sistema, de modo a criar um diferencial, mas que eles realmente pensaram mal, ah isso sim! E agora já é tarde para voltar atrás.

[]'s

PS: Valeu pela dica, Fábio!