<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-1387996720436450649</id><updated>2009-12-07T17:40:54.738-03:00</updated><title type='text'>Kodumaro</title><subtitle type='html'>As sombras da programação</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default?start-index=26&amp;max-results=25'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>83</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-1284665232521181172</id><published>2009-12-06T12:42:00.007-03:00</published><updated>2009-12-07T17:40:54.788-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><title type='text'>Mais sobre reiteração</title><content type='html'>&lt;img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; width: 55px; height: 55px; border: none;" src="http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s200/glider.png" alt="Glider" /&gt; A reiteração ou iteração é um dos mais efetivos algoritmos para para processamento de sequências, mas sua eficiência não se limita a processamento de conjuntos prontos, essa técnica de algoritmo também pode ser usada para processamento de amostragens em plena coleta.&lt;br /&gt;&lt;br /&gt;Vamos a um algoritmo bem simples, a média aritmética:&lt;br /&gt;&lt;center&gt;&lt;img src="http://cacilhas.info/bin/mimetex.cgi?\bar{x}=\frac{\sum_{i=1}^nx_i}{n}" alt="mean_x=sum_x/n" /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;O algoritmo reiterativo pode ser expresso da seguinte forma:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun mean ((a-list list))&lt;br /&gt;  (/&lt;br /&gt;    (apply #'+ a-list)&lt;br /&gt;    (length a-list)))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora imagine que você tem o registro contínuo do comportamento de um dado específico ao longo do tempo e gostaria de manter sua média sem preocupação como os valores em si (acho um caso pouco provável, mas…).&lt;br /&gt;&lt;br /&gt;Se reparando bem, há dois dados importantes para o cálculo da média aritmética: a própria média e a quantidade de elementos. Basta que a função receba esses valores além dos novos valores que serão usados para atualizar a média anterior.&lt;br /&gt;&lt;br /&gt;Assim é possível armazenar apenas a média atual e a quantidade de elementos avaliados:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun update-mean ((the-mean hash-table) (a-list list))&lt;br /&gt;  (let ((*count* (+ (gethash 'count the-mean) (length a-list))))&lt;br /&gt;    (setf (gethash 'mean the-mean)&lt;br /&gt;      (/&lt;br /&gt;        (+&lt;br /&gt;          (apply #'+ a-list)&lt;br /&gt;          (* (gethash 'mean the-mean) (gethash 'count the-mean)))&lt;br /&gt;        *count*))&lt;br /&gt;    (setf (gethash 'count the-mean) *count*)&lt;br /&gt;    the-mean))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Então, além de receber a lista com os dados mais recentes (segundo parâmetro), a função recebe como primeiro parâmetro um &lt;em&gt;hash&lt;/em&gt; com os dados de média anteriores.&lt;br /&gt;&lt;br /&gt;O formato inicial do &lt;em&gt;hash&lt;/em&gt; deve ser:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;#S(hash-table :test fasthash-eql (count . 0) (mean . 0))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ou seja, &lt;code&gt;'mean&lt;/code&gt; zero (0) e &lt;code&gt;'count&lt;/code&gt; zero (0). O &lt;em&gt;hash&lt;/em&gt; será atualizado e retornado:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(setq *mean*&lt;br /&gt;  (make-hash-table&lt;br /&gt;    :initial-contents (list&lt;br /&gt;      (cons 'count 0)&lt;br /&gt;      (cons 'mean 0))))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Na próxima falarei em &lt;a href="http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm"&gt;variância &lt;em&gt;on-line&lt;/em&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-1284665232521181172?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/1284665232521181172/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=1284665232521181172' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/1284665232521181172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/1284665232521181172'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/12/mais-sobre-reiteracao.html' title='Mais sobre reiteração'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_rGfO7DAuOSE/SwSZGIY_eXI/AAAAAAAAATA/Gh-qDqdTMX0/s72-c/glider.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-285191462001059816</id><published>2009-11-04T19:41:00.004-03:00</published><updated>2009-11-27T14:01:57.273-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><title type='text'>Ideias poderosas por trás de uma piada</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://photos1.blogger.com/blogger/6505/3295/200/baal.png" alt="Baal" /&gt; &lt;a href="http://www.dieblinkenlights.com/"&gt;Ricardo Bánffy&lt;/a&gt; fez uma &lt;strong&gt;piada de 1º de abril&lt;/strong&gt; no ano passado lançando um suposto &lt;em&gt;framework&lt;/em&gt; em &lt;a href="http://www.lisp.org/"&gt;Lisp&lt;/a&gt; chamado &lt;a href="http://www.dieblinkenlights.com/artigos_pt/o-kanamit-web-framework"&gt;Kanamit&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;No entanto a parte da piada é somente o terceiro tópico do texto e o Bánffy aproveitou o ar de piada para rasgar o verbo e dizer umas verdades sem medo.&lt;br /&gt;&lt;br /&gt;Como &lt;strong&gt;concordo quase 100% com o texto&lt;/strong&gt;, decidi reproduzi-lo aqui de forma séria:&lt;br /&gt;&lt;blockquote&gt;&lt;em&gt;Eu sempre gostei de escrever aqui sobre linguagens «exóticas». Já houve um tempo em que &lt;a href="http://python.org/"&gt;Python&lt;/a&gt; era exótico. Hoje Python é &lt;/em&gt;mainstream&lt;em&gt;. &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt;, idem. Há até suporte a &lt;a href="http://www.rubyonrails.pro.br/"&gt;Rails&lt;/a&gt; no NetBeans 6 e para Python no Visual Studio. Não dá pra ser muito mais &lt;/em&gt;mainstream&lt;em&gt; do que isso.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Nem todas as linguagens exóticas que eu conheci deram certo. &lt;a href="http://smalltalk.org/"&gt;Smalltalk&lt;/a&gt;, por exemplo, continua sendo aquela linguagem muito sofisticada, &lt;strong&gt;anos-luz à frente&lt;/strong&gt; do Java, mas que quase ninguém usa. Smalltalk tem &lt;strong&gt;ideias poderosas&lt;/strong&gt; demais. A ideia de rodar dentro de uma máquina virtual, de todo o código poder ser examinado e modificado «ao vivo», do compilador incremental, do &lt;/em&gt;class browser&lt;em&gt;, do &lt;/em&gt;late-binding&lt;em&gt;, das mensagens... Tudo isso era demais pras cabecinhas da maioria dos programadores que só conseguem entender Visual Basic ou PHP e olha lá.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Mas «Visual Basic e PHP resolvem todos os meus problemas», dizem eles. Claro. Se tudo o que eles conhecem se resume a isso, eles não imaginam sequer que existam outros tipos de problema. É uma limitação de capacidade expressiva: eles não têm as ferramentas intelectuais necessárias para expressar as &lt;strong&gt;classes de problemas que outras ferramentas expressam&lt;/strong&gt; e resolvem.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;Não se pode pensar em uma lâmpada fluorescente se tudo o que você conhece são pedras lascadas e peles de urso.&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Uma outra linguagem muito além do seu tempo é o Lisp. Além do seu tempo porque, se ela é uma coisa poderosa hoje comparada ao que temos hoje, imaginem em 1960 quando ela foi inventada…&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Por muito tempo, havia implementações de Lisp para computadores &lt;/em&gt;desktop&lt;em&gt;, mas, com processadores de 16 bits e menos de um &lt;/em&gt;megabyte&lt;em&gt; de RAM, essas máquinas serviam apenas como brinquedos. Você podia fazer um &lt;/em&gt;loop&lt;em&gt; e imprimir 10 vezes «fulano é bobo», mas não muito mais do que isso.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Naquele tempo, para se rodar programas em Lisp, você precisaria de uma Lisp &lt;/em&gt;machine&lt;em&gt;, um computador dedicado, com um processador único capaz de coisas que nenhum outro processador da época – ou de hoje – era capaz de fazer. Eram incrivelmente caras.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Mas as implementações de brincquedo eram o bastante para abrir as cabeças dos jovens computólogos (antes deles se chamarem assim). Lisp e &lt;a href="http://schemers.org/"&gt;Scheme&lt;/a&gt; (um dialeto de Lisp) são usados como ferramenta didática em todos os bons cursos de ciência da computação. Se no seu curso não tem, pare de perder tempo e paça seu dinheiro de volta. Não sei quanto é a mensalidade, mas é certo que o curso vale menos.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;E, claro, hoje em dia, temos computadores amplamente capazes de rodar boas implementações de Lisp. Meu &lt;/em&gt;notebook&lt;em&gt; consegue emular uma Lisp &lt;/em&gt;machine&lt;em&gt; da Texas Instruments (uma Micro-Explorer) mais depressa do que ela era originalmente.&lt;/em&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Artigo original: &lt;a href="http://www.dieblinkenlights.com/artigos_pt/o-kanamit-web-framework"&gt;O Kanamit Web Framework&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-285191462001059816?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/285191462001059816/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=285191462001059816' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/285191462001059816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/285191462001059816'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/11/ideias-poderosas-por-tras-de-uma-piada.html' title='Ideias poderosas por trás de uma piada'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-716295691748370467</id><published>2009-10-21T22:01:00.007-03:00</published><updated>2009-10-21T22:11:23.976-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Mais sobre programação funcional</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://4.bp.blogspot.com/_rGfO7DAuOSE/Rgv00nwEXZI/AAAAAAAAAB8/r59qEVD0qOE/s200/haskell.jpg" alt="Paradigma funcional" /&gt;&lt;br /&gt;&lt;br /&gt;Aproveitando o ensejo do &lt;a href="http://kodumaro.blogspot.com/2009/10/oddwording-2.html"&gt;artigo anterior&lt;/a&gt; sobre programação funcional, gostaria de puxar mais este artigo sobre três algoritmos tradicionais: sequência de Fibonacci, fatorial e &lt;em&gt;quick sort&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Fatorial&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://pt.wikipedia.org/wiki/Fatorial"&gt;Fatorial&lt;/a&gt; é um dos algoritmos recursivos mais tradicionais da Matemática. É também um dos algoritmos mais simples:&lt;br /&gt;&lt;center&gt;&lt;img src="http://cacilhas.info/bin/mimetex.cgi?%5Cleft{0!=1%5C%5Cn!=n%5Ccdot(n-1)!" alt="0!=1 n!=n*(n-1)!" /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Sua implementação tanto em &lt;a href="http://www.haskell.org/"&gt;Haskell&lt;/a&gt; quanto em &lt;a href="http://clisp.cons.org/"&gt;Common Lisp&lt;/a&gt; descreve exatamente esse algoritmo.&lt;br /&gt;&lt;br /&gt;Em Haskell:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;factorial :: Integer -&amp;gt; Integer&lt;br /&gt;factorial 0 = 1&lt;br /&gt;factorial n = n * (factorial (n - 1))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Em Common Lisp:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun factorial ((n integer))&lt;br /&gt;  (if (= n 0)&lt;br /&gt;    n&lt;br /&gt;    (* n (factorial (- n 1)))))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Já em &lt;a href="http://schemers.org/"&gt;Scheme&lt;/a&gt; a coisa pode complicar… se o interpretador (uso &lt;a href="http://www.gnu.org/software/guile/guile.html"&gt;&lt;code&gt;guile&lt;/code&gt;&lt;/a&gt;) tiver sido compilado com suporte a &lt;a href="http://gmplib.org/"&gt;&lt;em&gt;bignum&lt;/em&gt;&lt;/a&gt;, tudo bem, se não, é preciso fazer uma pequena mágica, multiplicando os resultados do maior para o menor:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(define (factorial n)&lt;br /&gt;  (define (loop k l)&lt;br /&gt;    (if (zero? k)&lt;br /&gt;      l&lt;br /&gt;      (loop (- k 1) (* k l))))&lt;br /&gt;  (loop n 1))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Sequência de Fibonacci&lt;/h3&gt;&lt;br /&gt;A &lt;a href="http://pt.wikipedia.org/wiki/Sequência_de_Fibonacci"&gt;Sequência de Fibonacci&lt;/a&gt; é uma progressão natural iniciando por 1, 1 e progredindo ao passo de que cada elemento é a soma dos dois anteriores:&lt;br /&gt;&lt;center&gt;&lt;img src="http://cacilhas.info/bin/mimetex.cgi?%5Cleft{a_0=1%5C%5Ca_1=1%5C%5Ca_n=a_{n-2}+a_{n-1}" alt="a0=1 a1=1 an=a(n-2)+a(n-1)" /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;É uma sequência recursiva em árvore binária, o pesadelo dos programadores. =D&lt;br /&gt;&lt;br /&gt;Mas como já foi muito estudada, há diversas formas de implementá-la sem usar código recursivo, como &lt;a href="http://pt.wikipedia.org/wiki/Iteração"&gt;algoritmo reiterativo&lt;/a&gt;, &lt;a href="http://pt.wikipedia.org/wiki/Matriz_(matemática)#Operações_envolvendo_matrizes"&gt;potência de matrizes&lt;/a&gt; e &lt;a href="http://montegasppa.blogspot.com/2006/07/desempenho-de-algoritmos.html"&gt;função fechada&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A seguinte implementação em Haskell utiliza recursão e lista infinita:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;fib :: [Integer]&lt;br /&gt;fib = 1 : 1 : zipWith (+) fib (tail fib)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Já em Common Lisp foi uma boa ideia usar reiteração, muito mais elegante do que seria possível em qualquer linguagem imperativa:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun fib (index)&lt;br /&gt;  (check-type index (integer 0 *))&lt;br /&gt;  (loop&lt;br /&gt;    for a = 1 then b&lt;br /&gt;    and b = 1 then (+ a b)&lt;br /&gt;    repeat index&lt;br /&gt;    finally (return a)))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;em&gt;Quick sort&lt;/em&gt;&lt;/h3&gt;&lt;br /&gt;O &lt;a href="http://pt.wikipedia.org/wiki/Quicksort"&gt;algoritmo de ordenação &lt;em&gt;quick sort&lt;/em&gt;&lt;/a&gt; é a exceção das exceções: um algoritmo de ordenação recursivo em árvore binária, o que deveria ser o pior dos casos, no entanto é um dos métodos de ordenação mais rápidos e eficientes que conhecemos.&lt;br /&gt;&lt;br /&gt;O princípio é o seguinte: toma-se um elemento qualquer da lista, tradicionalmente o primeiro, então separa-se a lista em duas, uma de elementos menores que o tomado e outra de elementos maiores. Aplica-se a mesma ordenação &lt;em&gt;quick sort&lt;/em&gt; a cada uma das novas listas e concatena-as com o elemento tomado no meio.&lt;br /&gt;&lt;br /&gt;Em Haskell isso pode ser descrito assim:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;qsort :: Ord a =&amp;gt; [a] -&amp;gt; [a]&lt;br /&gt;qsort [] = []&lt;br /&gt;qsort (x:xs) = qsort lesser ++ [x] ++ qsort greater&lt;br /&gt;    where&lt;br /&gt;        lesser =  [e | e &amp;lt;- xs, e &amp;lt; x]&lt;br /&gt;        greater = [e | e &amp;lt;- xs, e &amp;gt;= x]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Em Common Lisp o princípio é o mesmo, mas com aquele monte de parêntesis característicos de Lisp:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun qsort ((a-list list))&lt;br /&gt;  (if (&amp;lt; (length a-list) 2)&lt;br /&gt;    a-list&lt;br /&gt;    (let ((x (pop a-list)))&lt;br /&gt;      (concatenate 'list&lt;br /&gt;        (qsort&lt;br /&gt;          (loop for e in a-list&lt;br /&gt;            if (&amp;lt; e x)&lt;br /&gt;              collect e))&lt;br /&gt;        (list x)&lt;br /&gt;        (qsort&lt;br /&gt;          (loop for e in a-list&lt;br /&gt;            if (&amp;gt;= e x)&lt;br /&gt;              collect e))))))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;**&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Espero que este artigo tenha sido interessante e cause curiosidade aos leitores sobre programação funcional.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-716295691748370467?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/716295691748370467/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=716295691748370467' title='2 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/716295691748370467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/716295691748370467'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/10/mais-sobre-programacao-funcional.html' title='Mais sobre programação funcional'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_rGfO7DAuOSE/Rgv00nwEXZI/AAAAAAAAAB8/r59qEVD0qOE/s72-c/haskell.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-7637611925033835765</id><published>2009-10-16T21:46:00.012-03:00</published><updated>2009-10-20T20:42:42.320-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Oddwording de novo</title><content type='html'>&lt;img style="border: medium none ; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://photos1.blogger.com/blogger/6505/3295/200/prog.png" alt="Poliedro" /&gt; Em maio de 2007 publiquei um &lt;a href="http://kodumaro.blogspot.com/2007/05/oddwording.html"&gt;artigo&lt;/a&gt; sobre a implementação do algoritmo &lt;em&gt;oddwording&lt;/em&gt; em diversas linguagens de programação.&lt;br /&gt;&lt;br /&gt;Para relembrar, segue o código em &lt;a href="http://www.haskell.org/"&gt;Haskell&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;module Main where&lt;br /&gt;&lt;br /&gt;import IO&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;main = mainloop&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;mainloop :: IO ()&lt;br /&gt;mainloop = do&lt;br /&gt;    ph &amp;lt;- readString&lt;br /&gt;    if ph == ""&lt;br /&gt;        then&lt;br /&gt;            return ()&lt;br /&gt;        else do&lt;br /&gt;            let nph = oddword ph&lt;br /&gt;            putStrLn nph&lt;br /&gt;            mainloop&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;readString :: IO String&lt;br /&gt;readString = do&lt;br /&gt;    putStrLn "Digite uma frase: "&lt;br /&gt;    putStr "&amp;gt; "&lt;br /&gt;    hFlush stdout&lt;br /&gt;    s &amp;lt;- getLine&lt;br /&gt;    return s&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;oddword :: String -&amp;gt; String&lt;br /&gt;oddword s = listToStr $ invodd $ strToList s&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;strToList :: String -&amp;gt; [String]&lt;br /&gt;strToList "" = []&lt;br /&gt;strToList s = (take spi s) : (strToList (drop (incr spi) s))&lt;br /&gt;    where spi = nextspace s&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;incr :: Int -&amp;gt; Int&lt;br /&gt;incr = (+ 1)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;nextspace :: String -&amp;gt; Int&lt;br /&gt;nextspace "" = 0&lt;br /&gt;nextspace (x:xs) =&lt;br /&gt;    if x == ' '&lt;br /&gt;        then&lt;br /&gt;            0&lt;br /&gt;        else&lt;br /&gt;            1 + (nextspace xs)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;listToStr :: [String] -&amp;gt; String&lt;br /&gt;listToStr [] = ""&lt;br /&gt;listToStr (x:xs) = x ++ " " ++ (listToStr xs)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;invodd :: Ord a =&amp;gt; [[a]] -&amp;gt; [[a]]&lt;br /&gt;invodd [] = []&lt;br /&gt;invodd (x:xs) = x : (inveven xs)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;inveven :: Ord a =&amp;gt; [[a]] -&amp;gt; [[a]]&lt;br /&gt;inveven [] = []&lt;br /&gt;inveven (x:xs) = (inv x) : (invodd xs)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;inv :: Ord a =&amp;gt; [a] -&amp;gt; [a]&lt;br /&gt;inv [] = []&lt;br /&gt;inv (x:xs) = (inv xs) ++ [x]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;tt&gt;&amp;lt;update ressaca&amp;gt;&lt;/tt&gt;&lt;br /&gt;Havia esquecido de forçar o &lt;em&gt;flush&lt;/em&gt; de STOUT na função &lt;code&gt;readString&lt;/code&gt;. Corrigido!&lt;br /&gt;&lt;tt&gt;&amp;lt;/update&amp;gt;&lt;/tt&gt;&lt;/blockquote&gt;&lt;br /&gt;No entanto ficou faltando uma linguagem excepcionalmente importante, &lt;a href="http://www.lisp.org/"&gt;Lisp&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Lisp (LISt Processing) é uma família de linguagens funcionais concebida por John McCarthy em 1958, baseada no &lt;a href="http://pt.wikipedia.org/wiki/Cálculo_lambda"&gt;cálculo lambda&lt;/a&gt;. As principais linguagens da família Lisp são &lt;a href="http://clisp.cons.org/"&gt;Common Lisp&lt;/a&gt;, &lt;a href="http://schemers.org/"&gt;Scheme&lt;/a&gt; e &lt;a href="http://www.gnu.org/software/emacs/manual/html_mono/elisp.html"&gt;Emacs Lisp&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;O código acima será reimplementado abaixo em Common Lisp.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Observação:&lt;/strong&gt; os blocos de código deverão ser escritos em arquivo na ordem &lt;strong&gt;inversa&lt;/strong&gt; em que aparecem aqui, ou seja, digite cada bloco no arquivo em linhas acima do bloco digitado anteriormente.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ciclo principal&lt;/h3&gt;&lt;br /&gt;O ciclo principal será a função &lt;code&gt;mainloop&lt;/code&gt;. Sua lógica de funcionamento é a seguinte:&lt;br /&gt;&lt;ol&gt; &lt;li&gt;Pegar uma &lt;em&gt;string&lt;/em&gt; digitada na entrada padrão;&lt;/li&gt; &lt;li&gt;Se a &lt;em&gt;string&lt;/em&gt; for vazia, sair do programa;&lt;/li&gt; &lt;li&gt;Aplicar o algoritmo &lt;em&gt;oddwording&lt;/em&gt;;&lt;/li&gt; &lt;li&gt;Exibir na tela o resultado;&lt;/li&gt; &lt;li&gt;Recomeçar o ciclo.&lt;/li&gt; &lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;A função fica assim:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun mainloop ()&lt;br /&gt;  (loop do&lt;br /&gt;    (format t "~&amp;amp;~a~%"&lt;br /&gt;      (oddword (*exit-if-empty* (*read-string*))))))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Lendo uma linha da entrada padrão&lt;/h3&gt;&lt;br /&gt;Para ler uma linha da entrada padrão, devemos exibir um &lt;em&gt;prompt&lt;/em&gt;, ler a entrada digitada pelo usuário e remover os espaços em branco do começo e do fim:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun *read-string* ()&lt;br /&gt;  (format t "~&amp;amp;Digite uma frase:~%&amp;gt; ")&lt;br /&gt;  (string-trim " " (read-line)))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Saindo caso a &lt;em&gt;string&lt;/em&gt; esteja vazia&lt;/h3&gt;&lt;br /&gt;Caso nada tenha sido digitado, o programa encerra. Para isso é preciso avaliar a &lt;em&gt;string&lt;/em&gt;, encerrando o processo se apropriado, caso contrário retornar a &lt;em&gt;string&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun *exit-if-empty* ((a-string string))&lt;br /&gt;  (if (string= a-string "")&lt;br /&gt;    (exit)&lt;br /&gt;    a-string))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Descrição do algoritmo em alto nível&lt;/h3&gt;&lt;br /&gt;Podemos agora definir em alto nível o algoritmo &lt;em&gt;oddwording&lt;/em&gt;:&lt;br /&gt;&lt;ol&gt; &lt;li&gt;Transformar a &lt;em&gt;string&lt;/em&gt; em uma lista de palavras;&lt;/li&gt; &lt;li&gt;Inverter somente o conteúdo dos elementos de índice ímpar da lista;&lt;/li&gt; &lt;li&gt;Transformar novamente a lista de palavras em uma &lt;em&gt;string&lt;/em&gt;.&lt;/li&gt; &lt;/ol&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun oddword ((a-string string))&lt;br /&gt;  (list-to-str (invodd (str-to-list a-string))))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;em&gt;String&lt;/em&gt; para lista&lt;/h3&gt;&lt;br /&gt;Para transformar uma &lt;em&gt;string&lt;/em&gt; em uma lista, basta quebrada em cada ocorrência de espaço (&lt;code&gt;#&amp;#92;Space&lt;/code&gt;):&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun str-to-list ((a-string string))&lt;br /&gt;  (loop&lt;br /&gt;    for i = 0 then (1+ j)&lt;br /&gt;    as j = (position #&amp;#92;Space a-string :start i)&lt;br /&gt;    collect (subseq a-string i j)&lt;br /&gt;    while j))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Lista para &lt;em&gt;string&lt;/em&gt;&lt;/h3&gt;&lt;br /&gt;Para transformar uma lista de palavras em uma &lt;em&gt;string&lt;/em&gt; única, é preciso concatenar todos os elementos da lista, sem esquecer de acrescentar espaços entre eles:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun list-to-str ((a-list list))&lt;br /&gt;  (string-trim " "&lt;br /&gt;    (apply #'concatenate 'string&lt;br /&gt;      (loop for e in a-list&lt;br /&gt;        collect (concatenate 'string e " ")))))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Inversão dos elementos ímpares&lt;/h3&gt;&lt;br /&gt;Só faltou inverter os elementos de índice ímpar da lista. Nada mais simples: pegar cada elemento, se o índice for ímpar, inverter:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(defun invodd ((a-list list))&lt;br /&gt;  (loop&lt;br /&gt;    for x in a-list&lt;br /&gt;    and i from 0&lt;br /&gt;    collect (if (oddp i)&lt;br /&gt;      (reverse x)&lt;br /&gt;      x)))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Fazendo funcionar&lt;/h3&gt;&lt;br /&gt;Para que tudo aconteça, no &lt;strong&gt;final&lt;/strong&gt; do arquivo acrescente uma chamada à função principal:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(mainloop)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E execute o arquivo com o comando &lt;code&gt;clisp&lt;/code&gt; (aconselho o uso dos parâmetros &lt;code&gt;-K&amp;nbsp;full&lt;/code&gt; e &lt;code&gt;-q&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;**&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Lisp tem uma abordagem extremamente elegante e clara, aproveita o paradigma funcional perfeitamente e seus programas podem ser retroalimentados recursivamente para obter-se um comportamento de aprendizado, apreciado no desenvolvimento de &lt;a href="http://pt.wikipedia.org/wiki/Inteligência_artificial"&gt;IA&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;tt&gt;&amp;lt;update 2009-10-20&amp;gt;&lt;/tt&gt;&lt;br /&gt;Adicionada tipagem aos argumentos das funções e removido código redundante.&lt;br /&gt;&lt;tt&gt;&amp;lt;/update&amp;gt;&lt;/tt&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-7637611925033835765?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/7637611925033835765/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=7637611925033835765' title='3 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/7637611925033835765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/7637611925033835765'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/10/oddwording-2.html' title='O&lt;em&gt;ddwording&lt;/em&gt; de novo'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-4978013544784863230</id><published>2009-10-06T21:20:00.005-03:00</published><updated>2009-10-06T21:31:37.620-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Perl'/><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><category scheme='http://www.blogger.com/atom/ns#' term='Tcl'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Basic'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>IDEs em ambiente GNU/Linux</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://photos1.blogger.com/blogger/6505/3295/200/prog.png" alt="Poliedro" /&gt; Semana passada escrevi um artigo sobre alguns &lt;a href="http://pt.wikipedia.org/wiki/Ambiente_de_desenvolvimento_integrado"&gt;ambientes de desenvolvimento integrado&lt;/a&gt; e editores de texto, alguns deles &lt;a href="http://pt.wikipedia.org/wiki/Rapid_Application_Development"&gt;RAD&lt;/a&gt;. No entanto o artigo ficou muito longo, daí tive a ideia de quebrá-lo em três partes.&lt;br /&gt;&lt;br /&gt;Publiquei em meu &lt;em&gt;blog&lt;/em&gt; &lt;a href="http://montegasppa.blogspot.com/"&gt;Reflexões de Monte Gasppa e Giulia C.&lt;/a&gt;, mas agora, pensando bem, acho que cabe pelo menos uma referência aqui no &lt;a href="http://kodumaro.blogspot.com/"&gt;Kodumaro&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As três partes do artigo são:&lt;br /&gt;&lt;ol&gt; &lt;li&gt;&lt;a href="http://montegasppa.blogspot.com/2009/10/ide-1.html"&gt;Editores de texto&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://montegasppa.blogspot.com/2009/10/ide-2.html"&gt;IDEs focadas em projeto&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://montegasppa.blogspot.com/2009/10/ide-3.html"&gt;RAD&lt;/a&gt;&lt;/li&gt; &lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;A quem se interessar, boa leitura!&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-4978013544784863230?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/4978013544784863230/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=4978013544784863230' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/4978013544784863230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/4978013544784863230'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/10/ides-em-ambiente-gnu-linux.html' title='IDEs em ambiente GNU/Linux'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-2511996179269125893</id><published>2009-08-21T11:00:00.001-03:00</published><updated>2009-08-21T11:02:19.360-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Evento'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Dev in Rio 2009</title><content type='html'>Gente,&lt;br /&gt;&lt;br /&gt;Notícia fresquinha no &lt;a href="http://henriquebastos.net/2009/08/21/dev-in-rio-2009-eu-vou/"&gt;&lt;em&gt;blog&lt;/em&gt; do Henrique Bastos&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;h2&gt;Dev in Rio 2009: EU VOU!&lt;/h2&gt;&lt;br /&gt;Finalmente o Rio de Janeiro ganhou um grande evento de tecnologia focado no que é mais importante: &lt;strong&gt;Pessoas&lt;/strong&gt;!&lt;br /&gt;&lt;br /&gt;É com muito orgulho que apresentamos o &lt;a href="http://devinrio.com.br"&gt;&lt;strong&gt;&lt;em&gt;Dev in Rio 2009&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;, uma conferência bombástica sobre desenvolvimento de software que acontecerá no próximo dia &lt;strong&gt;14 de setembro&lt;/strong&gt; no &lt;a href="http://www.ccsulamerica.com.br/PgLocalizacao.php"&gt;Centro de Convenções SulAmérica&lt;/a&gt;, no Rio de Janeiro!&lt;br /&gt;&lt;br /&gt;O &lt;a href="http://devinrio.com.br"&gt;&lt;strong&gt;&lt;em&gt;Dev in Rio 2009&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;, contará com palestrantes nacionais e internacionais que falarão sobre &lt;a href="http://java.sun.com/"&gt;Java&lt;/a&gt;, &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; e &lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt;, &lt;a href="http://python.org"&gt;Python&lt;/a&gt;, &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;, &lt;a href="http://www.opensource.org/"&gt;Open Source&lt;/a&gt;, &lt;a href="http://www.joomla.org/"&gt;Joomla!&lt;/a&gt;, &lt;a href="http://improveit.com.br/xp/manifesto_agil"&gt;Métodos Ágeis&lt;/a&gt;, e muito mais. Nomes como &lt;a title="Akita é a referência de Rails no Brasil." href="http://akitaonrails.com/"&gt;Fábio Akita&lt;/a&gt;, &lt;a title="Vinícius é especialista em Extreme Programming e produtos Web." href="http://improveit.com.br/"&gt;Vinícius Manhães Teles&lt;/a&gt;, &lt;a title="Jacob é co-criador do Django" href="http://jacobian.org"&gt;Jacob Kaplan-Moss&lt;/a&gt;, &lt;a title="Conheça mais sobre o Guilherme e sua particpação na Comunidade Java." href="http://guilhermesilveira.wordpress.com/"&gt;Guilherme Silveira&lt;/a&gt;, &lt;a title="Conheça mais sobre o Nico e seu trabalho na Caelum." href="http://blog.caelum.com.br/"&gt;Nico Steppat&lt;/a&gt;, &lt;a title="Conheça o Ryan e seu trabalho com Open Source e Joomla!" href="http://www.picnet.net/blog/author/cozimek/"&gt;Ryan Ozimek&lt;/a&gt; e &lt;a title="Jeff é consultor especializado em métodos ágeis." href="http://www.agileproductdesign.com/"&gt;Jeff Patton&lt;/a&gt; agitarão um dia inteiro de muita tecnologia e diversão. Veja a &lt;a href="http://devinrio.com.br"&gt;programação detalhada&lt;/a&gt; no site da &lt;a href="http://devinrio.com.br/"&gt;&lt;strong&gt;&lt;em&gt;Dev in Rio 2009&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Mas não é só isso. Como eu disse no início, este é um evento focado em &lt;strong&gt;pessoas&lt;/strong&gt;. Toda a organização do evento está voltada para promover ao máximo a interação e integração entre os presentes.&lt;br /&gt;&lt;br /&gt;Por isso, o &lt;a href="http://devinrio.com.br/"&gt;&lt;strong&gt;&lt;em&gt;Dev in Rio 2009&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; contará com uma &lt;a href="http://dojorio.org"&gt;Arena DojoRio&lt;/a&gt; onde participantes e palestrantes poderão programar lado à lado, experimentando diversas linguagens e técnicas, buscando juntos as melhores formas de desenvolver software.&lt;br /&gt;&lt;br /&gt;O evento está sendo organizado por &lt;a href="http://henriquebastos.net"&gt;mim (Henrique Bastos)&lt;/a&gt; em parceria com o meu amigo &lt;a href="http://gc.blog.br/2009/08/20/dev-in-rio-2009-eu-vou/"&gt;Guilherme Chapiewski&lt;/a&gt;, contando com todo o apoio dos membros da  &lt;a href="http://pythonrio.org"&gt;PythOnRio&lt;/a&gt;, &lt;a href="http://dojorio.org"&gt;DojoRio&lt;/a&gt; e &lt;a href="http://horaextra.org"&gt;#Horaextra&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A realização está sendo coordenada pelas nossas experientes amigas da  &lt;a href="http://www.arteccom.com.br"&gt;Arteccom&lt;/a&gt;. E tê-las ao nosso lado já garante que este será um evento para marcar o circuito carioca.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Você&lt;/strong&gt; não pode perder esta incrível oportunidade de participar desse mega evento, interagir com grandes nomes do cenário mundial de tecnologia, conhecer pessoas interessantes que compartilham a paixão pelo desenvolvimento de software, e ainda por cima começar sua semana só na terça-feira. &lt;a href="http://devinrio.com.br"&gt;Inscreva-se já!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;Nos vemos por lá!&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;[]’s!&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-2511996179269125893?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/2511996179269125893/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=2511996179269125893' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/2511996179269125893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/2511996179269125893'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/08/dev-in-rio-2009.html' title='Dev in Rio 2009'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-3640145799036930672</id><published>2009-07-01T19:01:00.004-03:00</published><updated>2009-08-01T11:45:11.752-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><title type='text'>Ponteiro opaco</title><content type='html'>&lt;img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; width: 100px; height: 119px; border: none;" src="http://4.bp.blogspot.com/_rGfO7DAuOSE/Skfqi_b3SZI/AAAAAAAAAPw/LGCcKqN8ONI/s200/gcc.jpg" alt="GCC" id="BLOGGER_PHOTO_ID_5352504569017878930" /&gt; Muitas vezes programadores de &lt;a href="http://www.cplusplus.com/"&gt;C++&lt;/a&gt; e &lt;a href="http://java.sun.com"&gt;Java&lt;/a&gt; confundem &lt;a href="http://pt.wikipedia.org/wiki/Encapsulamento"&gt;encapsulamento&lt;/a&gt; com &lt;strong&gt;ocultação&lt;/strong&gt;, o que não é a intenção da &lt;a href="http://pt.wikipedia.org/wiki/Orientação_a_objetos"&gt;orientação a objetos&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;No entanto, o contrário da ocultação, a &lt;strong&gt;exposição&lt;/strong&gt;, também não é desejável para o encapsulamento, pois causa uma confusão entre &lt;a href="http://en.wikipedia.org/wiki/Interface_(computer_science)"&gt;interface&lt;/a&gt; e &lt;a href="http://en.wikipedia.org/wiki/Implementation"&gt;implementação&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Em C++, a declaração de uma classe força a exposição de sua estrutura privada. Um exemplo bem simples:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class X {&lt;br /&gt;    public:&lt;br /&gt;        X(int);&lt;br /&gt;        ~X();&lt;br /&gt;&lt;br /&gt;        int get(void) const;&lt;br /&gt;&lt;br /&gt;    private:&lt;br /&gt;        int value;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Neste exemplo insanamente simples, é possível ver a estrutura privada da classe &lt;code&gt;X&lt;/code&gt;, o que no caso não é um problema muito sério, mas em casos ligeiramente mais complexos, é possível &lt;a href="http://kodumaro.blogspot.com/2009/01/atributos-privados-onde.html"&gt;corromper o encapsulamento&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Uma forma de resolver o problema é usando um &lt;a href="http://en.wikipedia.org/wiki/Design_pattern"&gt;&lt;em&gt;design pattern&lt;/em&gt;&lt;/a&gt;&amp;sup1; chamado &lt;a href="http://en.wikipedia.org/wiki/Opaque_pointer"&gt;ponteiro opaco&lt;/a&gt; ou &lt;em&gt;Pimpl&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;A ideia é que a classe de interface seja apenas uma moldura (&lt;em&gt;wrapper&lt;/em&gt;) para a classe de implementação. A classe de implementação é declarada no corpo da classe de interface, mas nada é exposto ali.&lt;br /&gt;&lt;br /&gt;A classe de implementação vai ser finalmente implementada no arquivo onde os métodos da classe de interface são implementados. Os métodos da classe de interface então simplemente chamam os métodos da classe de implementação.&lt;br /&gt;&lt;br /&gt;Voltemos ao exemplo&amp;hellip; o arquivo de cabeçalho de nossa classe (&lt;code&gt;x.h&lt;/code&gt; por exemplo) passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class X {&lt;br /&gt;    class Ximpl;&lt;br /&gt;&lt;br /&gt;    public:&lt;br /&gt;        X(int);&lt;br /&gt;        ~X();&lt;br /&gt;&lt;br /&gt;        int get(void) const;&lt;br /&gt;&lt;br /&gt;    private:&lt;br /&gt;        Ximpl *pimpl;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como é possível ver, nada da implementação está exposto.&lt;br /&gt;&lt;br /&gt;Então a classe de implementação é finalmente definida no arquivo de implementação (&lt;code&gt;x.cc&lt;/code&gt;):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class X::Ximpl {&lt;br /&gt;    public:&lt;br /&gt;        Ximpl(int);&lt;br /&gt;        ~Ximpl();&lt;br /&gt;&lt;br /&gt;        int get(void) const;&lt;br /&gt;&lt;br /&gt;    private:&lt;br /&gt;        int value;&lt;br /&gt;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O resto do código fica:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;X::X(int value): pimpl(new X::Ximpl(value)) {&lt;br /&gt;    // Nada mais a fazer&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;X::Ximpl::Ximpl(int value): value(value) {&lt;br /&gt;    // Nada mais a fazer&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;X::~X() {&lt;br /&gt;    delete this-&amp;gt;pimpl;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;X::Ximpl::~Ximpl() {&lt;br /&gt;    // Nada mais a fazer&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;X::get(void) const {&lt;br /&gt;    return this-&amp;gt;pimpl-&amp;gt;get();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;X::Ximpl::get(void) const {&lt;br /&gt;    return this-&amp;gt;value;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;É claro que é um &lt;em&gt;pattern&lt;/em&gt; extremamente &lt;strong&gt;desconfortável&lt;/strong&gt;, pois é preciso implementar cada método duas vezes, uma para a classe de interface, outra para a classe de implementação&amp;hellip; e há sim formas melhores de fazer isso.&lt;br /&gt;&lt;br /&gt;Mas &lt;em&gt;Pimpl&lt;/em&gt; funciona, é uma saída viável e pode salvar sua vida. =D&lt;br /&gt;&lt;br /&gt;&lt;small&gt;&lt;tt&gt;[update 2009-08-01]&lt;/tt&gt;Sugestão de leitura de &lt;a href="http://0xc0de.wordpress.com/"&gt;0xc0de&lt;/a&gt;: &lt;a href="http://www.gotw.ca/gotw/024.htm"&gt;Compilation Firewalls&lt;/a&gt;.&lt;tt&gt;[/update]&lt;/tt&gt;&lt;/small&gt;&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;small&gt;&amp;sup1; &lt;em&gt;Design patterns&lt;/em&gt;: antes que me crucifiquem por usar esta expressão fora do mundinho pequeno de Java, a definição de &lt;em&gt;design pattern&lt;/em&gt; é «um jeito formal de documentar a solução para um problema de desenvolvimento», o que define corretamente ponteiro opaco.&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-3640145799036930672?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/3640145799036930672/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=3640145799036930672' title='4 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/3640145799036930672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/3640145799036930672'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/07/pimpl.html' title='Ponteiro opaco'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_rGfO7DAuOSE/Skfqi_b3SZI/AAAAAAAAAPw/LGCcKqN8ONI/s72-c/gcc.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-8181852037886965787</id><published>2009-06-28T19:10:00.010-03:00</published><updated>2009-06-29T21:22:28.812-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><title type='text'>Variaridade</title><content type='html'>&lt;img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; width: 100px; height: 119px; border: none;" src="http://4.bp.blogspot.com/_rGfO7DAuOSE/Skfqi_b3SZI/AAAAAAAAAPw/LGCcKqN8ONI/s200/gcc.jpg" alt="GCC" id="BLOGGER_PHOTO_ID_5352504569017878930" /&gt; Uma &lt;a href="http://en.wikipedia.org/wiki/Variadic_function"&gt;função &lt;del&gt;&lt;em&gt;variádica&lt;/em&gt;&lt;/del&gt; variária&lt;/a&gt; &amp;ndash; em inglês &lt;strong&gt;&lt;em&gt;variadic&lt;/em&gt;&lt;/strong&gt;, &lt;em&gt;variable arity&lt;/em&gt;, aridade&amp;sup1; variável &amp;ndash; é aquela que suporta uma quantidade variável de parâmetros.&lt;br /&gt;&lt;br /&gt;Muitas linguagens suportam funções variárias, aliás de forma bem simples. &lt;a href="http://python.org/"&gt;Python&lt;/a&gt; usa o operador &lt;code&gt;*&lt;/code&gt; para indicar quantidade variável de parâmetros, &lt;a href="http://www.lua.org/"&gt;Lua&lt;/a&gt; usa o operador &lt;code&gt;...&lt;/code&gt; e &lt;a href="http://clisp.cons.org/"&gt;Common Lisp&lt;/a&gt; o operador &lt;code&gt;&amp;amp;rest&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Outras linguagens podem ser ainda mais simples, como por exemplo &lt;a href="http://www.perl.org/"&gt;Perl&lt;/a&gt;, onde toda função é variária e os parâmetros são recebidos na lista &lt;code&gt;@_&lt;/code&gt;, tradicionalmente capturados por &lt;code&gt;shift&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Já &lt;a href="http://java.sun.com/"&gt;Java&lt;/a&gt; não suporta funções verdadeiramente variárias devido a sua limitação forçada de tipagem, no entanto é possível simular com o uso de &lt;code&gt;Object&lt;/code&gt; e &lt;em&gt;casting&lt;/em&gt; («vazamento» na falta de uma tradução melhor):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;void myFunction(Object... args) {&lt;br /&gt;    // Código do método&lt;br /&gt;    …&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Funções variárias em C/C++&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://pt.wikipedia.org/wiki/C_(linguagem_de_programação)"&gt;C&lt;/a&gt;/&lt;a href="http://www.cplusplus.com/"&gt;C++&lt;/a&gt; usa o cabeçalho &lt;a href="http://en.wikipedia.org/wiki/Stdarg.h"&gt;&lt;code&gt;stdarg.h&lt;/code&gt;&lt;/a&gt; para suporte a funções variárias.&lt;br /&gt;&lt;br /&gt;O exemplo apresentado na &lt;a href="http://en.wikipedia.org/wiki/Stdarg.h"&gt;Wikipédia&lt;/a&gt; é bastante simples: uma função &lt;code&gt;printargs&lt;/code&gt; que recebe uma quantidade arbitrária de números inteiros, encerrando com -1 (ou qualquer número negativo em nosso exemplo), e os exibe na saída padrão.&lt;br /&gt;&lt;br /&gt;Precisamos incluir dois cabeçalhos em C++, &lt;code&gt;cstdarg&lt;/code&gt; para suporte a funções variária e &lt;code&gt;cstdio&lt;/code&gt; para exibir o resultado:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;#include &amp;lt;cstdarg&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ou, em C:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdarg.h&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A assinatura da função fica assim:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;void printargs(int arg1, ...) {&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para acesso aos parâmetros múltiplos é usado um objeto &lt;code&gt;va_list&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    va_list args;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A função &lt;code&gt;va_start()&lt;/code&gt; inicializa o objeto. Ela recebe dois parâmetros: o objeto &lt;code&gt;va_list&lt;/code&gt; e o nome do último argumento antes da lista:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    va_start(args, arg1);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Portanto é preciso haver pelo menos um argumento antes da lista variável. Podemos então exibir o primeiro parâmetro, recebido no argumento &lt;code&gt;arg1&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    printf("%d", arg1);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A função &lt;code&gt;va_arg()&lt;/code&gt; retorna o argumento seguinte. Ela recebe como parâmetros o objeto &lt;code&gt;va_list&lt;/code&gt; e o tipo do parâmetro da lista a ser recuperado.&lt;br /&gt;&lt;br /&gt;O tipo precisar ser plenamente promovido, ou seja, ponteiro, inteiro, ponto flutuante ou precisão dupla. Outros tipos, como &lt;code&gt;char&lt;/code&gt; precisam sofrer &lt;em&gt;casting&lt;/em&gt;, como por exemplo (&lt;strong&gt;não faz parte do código de &lt;code&gt;printargs&lt;/code&gt;&lt;/strong&gt;):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;char c = static_cast&amp;lt;char&amp;gt;(va_arg(va, int));&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Continuando o código, podemos agora reiterar sobre os resultados de &lt;code&gt;va_arg()&lt;/code&gt; até encontrarmos o valor de parada negativo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    int arg;&lt;br /&gt;    while((arg = va_arg(args, int)) &gt;= 0)&lt;br /&gt;        printf(" %d", arg);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Após o fim da reiteração dos parâmetros obtidos do objeto &lt;code&gt;va_list&lt;/code&gt; através de &lt;code&gt;va_arg()&lt;/code&gt;, é preciso encerrar o objeto:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    va_end(arg);&lt;br /&gt;    printf("\n");&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Caso você queira restringir o formato de entrada da função, isso é possível usando &lt;code&gt;__attribute__&lt;/code&gt; em sua declaração. Por exemplo, se a função &lt;code&gt;log()&lt;/code&gt; recebe o nível de &lt;em&gt;log&lt;/em&gt; como primeiro parâmetro, uma &lt;em&gt;string&lt;/em&gt; de formatação como segundo parâmetro (&lt;code&gt;2&lt;/code&gt;) e os parâmetros variáveis a partir do terceiro (&lt;code&gt;3&lt;/code&gt;), com formato similar ao da função &lt;code&gt;printf()&lt;/code&gt;, isso é feito com a seguinte assinatura:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;extern void&lt;br /&gt;log(int level, cons char *fmt, ...)&lt;br /&gt;__attribute__((format(printf, 2, 3)));&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As opções para &lt;code&gt;format()&lt;/code&gt; são &lt;code&gt;printf&lt;/code&gt;, &lt;code&gt;scanf&lt;/code&gt;, &lt;code&gt;strftime&lt;/code&gt; e &lt;code&gt;strfmon&lt;/code&gt;. Veja &lt;a href="http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Function-Attributes.html"&gt;Declaring Attributes of Functions&lt;/a&gt; da documentação do &lt;a href="http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/"&gt;GCC&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;small&gt;&amp;sup1;Aridade: em Matemática é o número de operandos de uma função.&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-8181852037886965787?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/8181852037886965787/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=8181852037886965787' title='3 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/8181852037886965787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/8181852037886965787'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/06/variadic.html' title='Variaridade'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_rGfO7DAuOSE/Skfqi_b3SZI/AAAAAAAAAPw/LGCcKqN8ONI/s72-c/gcc.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-1057086620735538448</id><published>2009-05-14T19:03:00.001-03:00</published><updated>2009-05-14T19:04:34.699-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tcl'/><title type='text'>Um «Olá Mundo!» pequenininho</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left;" src="http://photos1.blogger.com/blogger/6505/3295/200/tcl.jpg" alt="tcl.jpg" /&gt; Como este &lt;em&gt;blog&lt;/em&gt; estava muito parado, resolvi postar um «Olá Mundo!» com janela de duas linhas em &lt;a href="http://wiki.tcl.tk/"&gt;Tcl/Tk&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;wm title . Hello&lt;br /&gt;grid [ button .bt -text { Olá Mundo! } -command exit ]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Se preferir, pode ser criado um &lt;em&gt;script&lt;/em&gt; autoexecutável acrescentando o &lt;em&gt;hash-bang&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#!/bin/sh&lt;br /&gt;#&amp;#92;&lt;br /&gt;exec wish "$0" "$@"&lt;br /&gt;&lt;br /&gt;wm title . Hello&lt;br /&gt;grid [ button .bt -text { Olá Mundo! } -command exit ]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-1057086620735538448?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/1057086620735538448/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=1057086620735538448' title='2 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/1057086620735538448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/1057086620735538448'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/05/um-ola-mundo-pequenininho.html' title='Um «Olá Mundo!» pequenininho'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-4749053583994587531</id><published>2009-03-19T00:01:00.012-03:00</published><updated>2009-03-19T11:57:22.376-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='OO'/><title type='text'>Sobre APIs</title><content type='html'>Umas das coisas mais importantes em programação, sem a qual ninguém consegue desevolver, é &lt;a href="http://pt.wikipedia.org/wiki/API"&gt;API&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;API &amp;ndash; Interface de Programação de Aplicativos &amp;ndash; é o conjunto de recursos de que o programador dispõe para desenvolver suas aplicações.&lt;br /&gt;&lt;br /&gt;Este artigo faz uma comparação &amp;ndash; na verdade, mais uma demonstração &amp;ndash; de cinco APIs muito usadas: &lt;a href="http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?tp=&amp;isnumber=4694975&amp;arnumber=4694976&amp;punumber=4694974"&gt;IEEE 1003&lt;/a&gt;, &lt;a href="http://www.cplusplus.com/reference/"&gt;STL&lt;/a&gt;, &lt;a href="http://www.gnustep.org/resources/OpenStepSpec/OpenStepSpec.html"&gt;OpenStep&lt;/a&gt;, &lt;a href="http://library.gnome.org/devel/glib/stable/"&gt;GLib&lt;/a&gt; e &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/"&gt;Java&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Para a demonstração será usado um trecho de código para ler a primeira linha de um arquivo.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Por que não a API do Windows?&lt;/h3&gt;&lt;br /&gt;Antes de começar, é preciso esclarecer por que não a &lt;a href="http://msdn.microsoft.com/pt-br/default.aspx"&gt;API do Windows&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;O objetivo de uma API é oferecer um ambiente homogêneo de programação, para que o programador não seja obrigado a reaprender a mesma coisa diversas vezes. Para facilitar isso, muitas APIs ainda podem ser usadas em diversas linguagens diferentes, outras em apenas uma.&lt;br /&gt;&lt;br /&gt;No entanto uma API que funciona apenas em um único sistema operacional &amp;ndash; ou ainda no grupo de sistemas operacionais de uma única empresa &amp;ndash; não está fazendo seu trabalho, por mais usado que esse(s) sistema(s) possa ser.&lt;br /&gt;&lt;br /&gt;Assim a API do Windows não faz mais do que se espera da interface de um sistema operacional.&lt;br /&gt;&lt;br /&gt;É claro que é necessário que o Windows possua uma API, mesmo que seja exclusivamente para conexão de outras APIs mais universais.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;IEEE 1003 (POSIX)&lt;/h3&gt;&lt;br /&gt;O padrão POSIX, definido pela &lt;a href="http://www.ieee.org/"&gt;IEEE&lt;/a&gt;, oferece uma interface completa para sistemas compatíveis com &lt;a href="http://www.unix.org/"&gt;UNIX&lt;/a&gt;. Alguns exemplos são &lt;a href="http://www.ibm.com/servers/aix"&gt;IBM AIX&lt;/a&gt;, &lt;a href="http://br.sun.com/practice/software/solaris/"&gt;Solaris&lt;/a&gt;, &lt;a href="http://www.gnu.org/"&gt;GNU&lt;/a&gt; (e daí também Linux), &lt;a href="http://www.bsd.org/"&gt;BSD&lt;/a&gt;, &lt;a href="http://www.apple.com/br/macosx/"&gt;Mac OS&amp;nbsp;X&lt;/a&gt;, &lt;a href="http://pt.wikipedia.org/wiki/Xenix"&gt;MS Xenix&lt;/a&gt; e muitos outros.&lt;br /&gt;&lt;br /&gt;O trecho de código em &lt;a href="http://pt.wikipedia.org/wiki/C_(linguagem_de_programação)"&gt;C&lt;/a&gt; para ler a primeira linha de um arquivo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;FILE *fd = fopen(filename, "r");&lt;br /&gt;&lt;br /&gt;if (fd) {&lt;br /&gt;    while (!eof(fd)) {&lt;br /&gt;        char buf;&lt;br /&gt;        fread(&amp;amp;buf, sizeof(char), 1, fd);&lt;br /&gt;        printf("%c", buf);&lt;br /&gt;        if (buf == '&amp;#92;n')&lt;br /&gt;            break;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    fclose(fd);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;1&lt;/sup&gt;: é preciso incluir o cabeçalho &lt;code&gt;stdio.h&lt;/code&gt; ou, em C++, &lt;code&gt;cstdio&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;2&lt;/sup&gt;: a variável &lt;code&gt;filename&lt;/code&gt; é do tipo &lt;code&gt;const&amp;nbsp;char&amp;nbsp;*&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;3&lt;/sup&gt;: foi preciso procurar ocorrência do carácter &lt;code&gt;&amp;#92;n&lt;/code&gt; pois POSIX não ofereça uma função de alto nível para ler uma linha.&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;4&lt;/sup&gt;: o padrão POSIX é completamente procedimental &amp;ndash; as demais APIs citadas aqui são orientadas a objetos &amp;ndash;, sendo um pouco desajeitado para algumas operações.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;STL&lt;/h3&gt;&lt;br /&gt;A linguagem de programação &lt;a href="http://www.cplusplus.com/"&gt;C++&lt;/a&gt; possui uma biblioteca padrão própria bastante completa chamada STL &amp;ndash; Standard Library.&lt;br /&gt;&lt;br /&gt;Para o exemplo, é preciso incluir o cabeçalho &lt;code&gt;fstream&lt;/code&gt; para a manipulação de arquivo e o cabeçalho &lt;code&gt;iostream&lt;/code&gt; para a exibição dos dados na tela:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;std::ifstream fd(filename);&lt;br /&gt;&lt;br /&gt;if (fd.is_open()) {&lt;br /&gt;    char buf[1024];&lt;br /&gt;    fd.getline(buf, 1023);&lt;br /&gt;&lt;br /&gt;    std::cout &amp;lt;&amp;lt; buf &amp;lt;&amp;lt; std::endl;&lt;br /&gt;    fd.close();&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;1&lt;/sup&gt;: como citado acima, é preciso incluir pelo menos o cabeçalho &lt;code&gt;fstream&lt;/code&gt; ao manipular arquivos:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;fstream&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;2&lt;/sup&gt;: a variável &lt;code&gt;filename&lt;/code&gt; precisa ser do tipo &lt;code&gt;const&amp;nbsp;char&amp;nbsp;*&lt;/code&gt; &amp;ndash; &lt;code&gt;std::ifstream&lt;/code&gt; não suporta &lt;code&gt;std::string&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;OpenStep&lt;/h3&gt;&lt;br /&gt;A empresa &lt;a href="http://www.dmoz.org/Computers/Software/Operating_Systems/Microkernel/Mach/NeXT/"&gt;NeXT&lt;/a&gt; de Steve Jobs, ora adquirida pela &lt;a href="http://www.apple.com/"&gt;Apple&lt;/a&gt;, abriu a API de seu sistema operacional em 1992 num acordo com a &lt;a href="http://www.sun.com/"&gt;SUN Microsystems&lt;/a&gt;, sob o nome de OpenStep, o que permitiu, além da criação de aplicações de terceiros para NeXTSTEP, também o desenvolvimento de outros sistemas operacionais compatíveis com sua API e APIs de programação para sistemas já existentes, tornando-os compatíveis com OpenStep.&lt;br /&gt;&lt;br /&gt;Exemplos de sistemas compatíveis com essa API são &lt;a href="http://www.apple.com/br/macosx/"&gt;Mac OS&amp;nbsp;X&lt;/a&gt; e &lt;a href="http://gnustep.org/"&gt;GNUstep&lt;/a&gt; (portável para Windows e qualquer plataforma compatível com POSIX).&lt;br /&gt;&lt;br /&gt;A API OpenStep funciona exclusivamente em &lt;a href="http://pt.wikipedia.org/wiki/Objective-C"&gt;Objective-C&lt;/a&gt;, apesar de haver alguns portes para outras linguagens, como C++, &lt;a href="http://smalltalk.org/"&gt;Smalltalk&lt;/a&gt; e &lt;a href="http://www.gnu.org/software/guile/guile.html"&gt;Guile Scheme&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Vamos ao exemplo em Objective-C:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;id fd = [NSFileHandle fileHandleForReadingAtPath: filename];&lt;br /&gt;&lt;br /&gt;if (fd != nil) {&lt;br /&gt;    char buf = 0;&lt;br /&gt;    [fd seekToEndOfFile];&lt;br /&gt;    unsigned long long eof = [fd offsetFile];&lt;br /&gt;    [fd seekToFileOffset: 0];&lt;br /&gt;&lt;br /&gt;    while (([fd offsetInFile] &amp;lt; eof) &amp;amp;&amp;amp; (buf != '&amp;#92;n')) {&lt;br /&gt;        [[fd readDataOfLength: 1] getBytes: &amp;amp;buf length: 1];&lt;br /&gt;        printf("%c", buf);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [fd closeFile];&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;1&lt;/sup&gt;: é preciso importar o cabeçalho &lt;code&gt;Foundation.h&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#import &amp;lt;Foundation/Foundation.h&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;2&lt;/sup&gt;: a variável &lt;code&gt;filename&lt;/code&gt; precisa ser do tipo &lt;code&gt;NSString&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;3&lt;/sup&gt;: &lt;strong&gt;eu&lt;/strong&gt; não conheço um método para ler uma linha de um arquivo em OpenStep, portanto usei um esquema similar ao usado acima em POSIX.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;GLib&lt;/h3&gt;&lt;br /&gt;A GLib começou como parte do &lt;em&gt;toolkit&lt;/em&gt; gráfico &lt;a href="http://www.gtk.org/"&gt;Gtk+&lt;/a&gt; na versão 2.0, tendo evoluído para se tornar uma API multiplataforma orientada a objetos completa e independente da interface gráfica.&lt;br /&gt;&lt;br /&gt;Você pode usar GLib em qualquer sistema POSIX e em Windows.&lt;br /&gt;&lt;br /&gt;A maior curiosidade da GLib é que ela deixa explícita o equívoco &amp;ndash; ou a falácia &amp;ndash; de quem crê que não seja possível programar orientado a objetos em uma linguagem não orientada a objetos: é escrita em C e completamente orientada a objetos.&lt;br /&gt;&lt;br /&gt;Aliás a base da GLib é o &lt;a href="http://library.gnome.org/devel/gobject/stable/"&gt;GObject&lt;/a&gt; que, curiosamente, não é compatível com a estrutura de orientação a objetos de C++ e outras linguagens clássicas, apesar de haver portes para C++ e outras.&lt;br /&gt;&lt;br /&gt;O exemplo a seguir é um trecho de código em &lt;a href="http://live.gnome.org/Vala"&gt;Vala&lt;/a&gt;, linguagem criada expecificamente para a GLib:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;var file = File.new_for_path(filename);&lt;br /&gt;&lt;br /&gt;if (file.query_exists(null)) {&lt;br /&gt;    try {&lt;br /&gt;        var fd = new DataInputStream(file.read(null));&lt;br /&gt;        stdout.printf("%s&amp;#92;n", fd.read_line(null, null));&lt;br /&gt;        fd.close(null);&lt;br /&gt;    } catch (Error e) {&lt;br /&gt;        // Ignora exceções&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;[update 2009-03-19]&lt;/tt&gt;Faltou o &lt;code&gt;close&lt;/code&gt;.&lt;tt&gt;[/update]&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;1&lt;/sup&gt;: é preciso «usar» &lt;code&gt;GLib&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;using GLib;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;2&lt;/sup&gt;: a variável &lt;code&gt;filename&lt;/code&gt; é do tipo &lt;code&gt;string&lt;/code&gt; &amp;ndash; equivalente em C a &lt;code&gt;GString&lt;/code&gt; e &lt;code&gt;gchar&amp;nbsp;*&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;3&lt;/sup&gt;: é preciso usar o pacote (&lt;code&gt;--pkg&lt;/code&gt;) &lt;code&gt;gio-2.0&lt;/code&gt;, que importa GIO, recursos de I/O da GLib.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Java&lt;/h3&gt;&lt;br /&gt;Em sua linguagem de programação, a SUN Microsystems optou por criar uma API própria (bem complicada e verborrágica em relação às demais, diga-se).&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;BufferedReader fd = null;&lt;br /&gt;try {&lt;br /&gt;    fd = new BufferedReader(new FileReader(filename));&lt;br /&gt;    System.out.println(fd.readLine());&lt;br /&gt;&lt;br /&gt;} catch (Exception e) {&lt;br /&gt;    // Ignora exceções&lt;br /&gt;&lt;br /&gt;} finally {&lt;br /&gt;    try {&lt;br /&gt;        if (fd != null)&lt;br /&gt;            fd.close();&lt;br /&gt;    } catch (IOException e) {&lt;br /&gt;        // Ignora exceções&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;1&lt;/sup&gt;: as classes usadas estão no pacote &lt;code&gt;java.io&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;import java.io.BufferedReader;&lt;br /&gt;import java.io.FileReader;&lt;br /&gt;import java.io.IOException;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Observação&lt;sup&gt;2&lt;/sup&gt;: a variável &lt;code&gt;filename&lt;/code&gt; é do tipo &lt;code&gt;String&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;**&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Fica aqui a dica de três APIs interessantes.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-4749053583994587531?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/4749053583994587531/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=4749053583994587531' title='9 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/4749053583994587531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/4749053583994587531'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/03/api.html' title='Sobre APIs'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-5790388600982301128</id><published>2009-03-11T22:05:00.013-03:00</published><updated>2009-04-01T23:13:55.745-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Quem vai pra Vala?</title><content type='html'>&lt;img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; width: 100px; height: 100px; border: none;" src="http://1.bp.blogspot.com/_rGfO7DAuOSE/SbhgHqf0qYI/AAAAAAAAAOI/2b3cylnjqy4/s200/live-gnome.jpg" alt="live.gnome.org" id="BLOGGER_PHOTO_ID_5312101445266614658" /&gt; Dessa vez o pessoal do &lt;a href="http://live.gnome.org/"&gt;Gnome&lt;/a&gt; acertou a mão. Estou falando da &lt;a href="http://live.gnome.org/Vala"&gt;linguagem de programação Vala&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Até hoje, quem queria programar em &lt;a href="http://pt.wikipedia.org/wiki/C_Sharp"&gt;C#&lt;/a&gt; era obrigado a usar ou um &lt;a href="http://www.microsoft.com/windows/"&gt;sistema operacional problemático&lt;/a&gt;, ou uma &lt;a href="http://www.mono-project.com/"&gt;ferramenta monstruosamente pesada e ineficiente&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Não mais.&lt;br /&gt;&lt;br /&gt;O projeto Gnome lançou há algum tempo a linguagem Vala, fortemente baseada na sintaxe do C#, mas voltada para aplicações Gnome. Quem manja de C# ou maja de &lt;a href="http://java.sun.com/"&gt;Java&lt;/a&gt; e já viu C# não terá dificuldade em lidar com Vala.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Instalação&lt;/h3&gt;&lt;br /&gt;Segundo a &lt;a href="http://live.gnome.org/Vala"&gt;página do projeto&lt;/a&gt;, Vala foi feito para plataforma Gnome. Surgiu aí meu primeiro problema: uso &lt;a href="http://www.slackware.org/"&gt;Slackware&lt;/a&gt; e o &lt;a href="http://pt.wikipedia.org/wiki/Patrick_Volkerding"&gt;Volkerding&lt;/a&gt; decidiu que Slackware não terá mais suporte a Gnome! Em sua total substituição, há o &lt;a href="http://www.xfce.org/"&gt;Xfce&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Simplesmente não há um pacote oficial de Gnome para Slackware &amp;ndash; e os não-oficiais que já experimentei simplesmente detonaram o sistema todo.&lt;br /&gt;&lt;br /&gt;Ainda mais: e quem usa outros SOs? Se não tiver Gnome já era?&lt;br /&gt;&lt;br /&gt;Qual não foi minha agradável surpresa quando descobri que &lt;strong&gt;Vala compilou e instalou sem problemas no Slackware 12.2&lt;/strong&gt;?! Sua dependência verdadeira é GTK+ 2.x, que você encontra em praticamente qualquer distribuição GNU/Linux ou &lt;a href="http://www.bsd.org/"&gt;BSD&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;E Windows? &lt;a href="http://live.gnome.org/Vala/ValaOnWindows"&gt;Também tem!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Usando&lt;/h3&gt;&lt;br /&gt;Um «Olá Mundo» em Vala é bastante simples (tanto quanto Java, pelo menos):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;using GLib;&lt;br /&gt;&lt;br /&gt;public class HelloWorld : Object {&lt;br /&gt;    public static int main(string[] args) {&lt;br /&gt;        stdout.printf("Olá Mundo!\n");&lt;br /&gt;        return 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ao contrário do &lt;a href="http://msdn.microsoft.com/netframework/"&gt;.NET&lt;/a&gt;, não há código escondido do programador. Por exemplo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;using GLib;&lt;br /&gt;&lt;br /&gt;public class HelloWorld : Object {&lt;br /&gt;&lt;br /&gt;    private Gtk.Window window;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public HelloWorld() {&lt;br /&gt;        window = new Gtk.Window(Gtk.WindowType.TOPLEVEL);&lt;br /&gt;        window.set_default_size(300, 200);&lt;br /&gt;        window.destroy += Gtk.main_quit;&lt;br /&gt;        window.add(new Gtk.Label("Olá Mundo!"));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public void show() {&lt;br /&gt;        window.show_all();&lt;br /&gt;        Gtk.main();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public static int main (string[] args) {&lt;br /&gt;        Gtk.init(ref args);&lt;br /&gt;        var sample = new HelloWorld();&lt;br /&gt;        sample.show();&lt;br /&gt;&lt;br /&gt;        return 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;del&gt;Antes que alguém reclame, peço desculpas pelos códigos mal orientados a objetos, mas não quis ter muito o que explicar.&lt;/del&gt;&lt;br /&gt;&lt;tt&gt;[update]&lt;/tt&gt;Ajeitei pra ninguém ficar me chateando.&lt;tt&gt;[/update]&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Maturidade&lt;/h3&gt;&lt;br /&gt;Estranhamente a linguagem já está bastante madura na &lt;a href="http://live.gnome.org/Vala/Release"&gt;0.5.7&lt;/a&gt;. Não encontrei quebras inusitadas nem erros bizarros.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;tt&gt;[update 2009-04-01]&lt;/tt&gt;&lt;br /&gt;Encontrei uma quebra inusitada: Vala não lida bem com &lt;a href="http://pt.wikipedia.org/wiki/Closure"&gt;&lt;em&gt;closures&lt;/em&gt;&lt;/a&gt; e escopo dinâmico. Ela se perde um pouco gerando alguns erros inesperados.&lt;br /&gt;&lt;br /&gt;Outro erro inconveniente está na API com C: o &lt;em&gt;bind&lt;/em&gt; de método destruidor não suporta parâmetros, o que pode ocorrer em alguns casos da GLib &amp;ndash; lembre-se do que não há métodos destruidores reais em C, mas sim funções de desalocação.&lt;br /&gt;&lt;tt&gt;[/update]&lt;/tt&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;A única coisa que tenho a reclamar &lt;strong&gt;muito&lt;/strong&gt; é a documentação precária, bem longe das documentações de API bem organizadas da &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/"&gt;SUN Microsystems&lt;/a&gt; e da &lt;a href="http://msdn.microsoft.com/"&gt;Microsoft&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;IDE&lt;/h3&gt;&lt;br /&gt;Por enquanto há uma IDE chamada &lt;a href="http://www.valaide.org/"&gt;Val(a)IDE&lt;/a&gt; &amp;ndash; só que essa já desarmou na minha cara algumas vezes &amp;ndash; e a promessa de uma &lt;a href="https://launchpad.net/valable"&gt;extensão&lt;/a&gt; para o &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; &amp;ndash; que ainda não apareceu na página da própria extensão.&lt;br /&gt;&lt;br /&gt;Segundo a &lt;a href="http://live.gnome.org/Vala"&gt;página official&lt;/a&gt;, há também extensões para &lt;a href="http://anonsvn.mono-project.com/source/trunk/monodevelop/extras/ValaBinding/"&gt;MonoDevelop&lt;/a&gt; (Deus me livre!) e para &lt;a href="http://vtg.googlecode.com/"&gt;GEdit&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;**&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;É isso aí! Quando eu ganhar um pouco mais de intimidade com a linguagem, escrevo mais alguma coisa. Por enquanto foi só divulgação. Um tutorial meia-boca pode ser encontrado &lt;a href="http://live.gnome.org/Vala/Tutorial"&gt;aqui&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-5790388600982301128?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/5790388600982301128/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=5790388600982301128' title='9 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/5790388600982301128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/5790388600982301128'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/03/vala.html' title='Quem vai pra Vala?'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_rGfO7DAuOSE/SbhgHqf0qYI/AAAAAAAAAOI/2b3cylnjqy4/s72-c/live-gnome.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-3333194749440288105</id><published>2009-03-04T12:25:00.002-03:00</published><updated>2009-03-04T12:27:12.761-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Calculadora científica com o Vim</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" alt="" /&gt; Desta vez vou &lt;em&gt;reblogar&lt;/em&gt;&amp;hellip;&lt;br /&gt;&lt;br /&gt;O &lt;a href="http://www.blogger.com/profile/11511626443237920795"&gt;voyeg3r&lt;/a&gt; publicou um artigo curtinho e muito legal sobre como criar uma calculadora científica no &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt; usando &lt;a href="http://python.org/"&gt;Python&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;O artigo pode ser encontrado no &lt;a href="http://vivaotux.blogspot.com/2009/03/calculadora-cientifica-com-o-vim.html"&gt;vivaotux&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Boa leitura!&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-3333194749440288105?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/3333194749440288105/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=3333194749440288105' title='2 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/3333194749440288105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/3333194749440288105'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/03/calculadora-cientifica-com-o-vim.html' title='Calculadora científica com o Vim'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-6235602295320517129</id><published>2009-01-29T23:30:00.008-03:00</published><updated>2009-08-26T22:06:08.116-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='OO'/><title type='text'>Propriedades e acessores</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" alt="" /&gt; Em &lt;a href="http://java.sun.com"&gt;Java&lt;/a&gt; e em &lt;a href="http://http://www.cplusplus.com/"&gt;C++&lt;/a&gt; há um bom motivo para que os atributos sejam sempre privados: preservar a interface das classes.&lt;br /&gt;&lt;br /&gt;Por exemplo, imagine que temos uma classe que representa o registro de uma pessoa. Nela temos a idade. Sendo um número inteiro, poderia ser um atributo público:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;Person person;&lt;br /&gt;person.age = 23;&lt;br /&gt;std::cout &amp;lt;&amp;lt; person.age &amp;lt;&amp;lt; std::endl;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Faz sentido. Agora imagine que mais tarde descobrimos que é preciso fazer um tratamento do valor recebido &amp;ndash; para estar numa faixa aceitável, por exemplo&amp;hellip;&lt;br /&gt;&lt;br /&gt;Sem alterar a interface &amp;ndash; e efetuar uma refatoração total de todo código onde ocorre instância &amp;ndash; é impossível.&lt;br /&gt;&lt;br /&gt;Então, em Java e C++ é &lt;strong&gt;importante&lt;/strong&gt; usar métodos acessores e manter os atributos privados. Dessa forma qualquer alteração futura pode ser feita na classe sem alterar o restante do código:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;Person person;&lt;br /&gt;person.setAge(23);&lt;br /&gt;std::cout &amp;lt;&amp;lt; person.getAge() &amp;lt;&amp;lt; std::endl;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Propriedades&lt;/h3&gt;&lt;br /&gt;Já em &lt;a href="http://python.org/"&gt;Python&lt;/a&gt; isso não faz sentido!&lt;br /&gt;&lt;br /&gt;Em Python, além de atributos e métodos, há as propriedades. Então atributos podem ser públicos e, caso seja necessário adicionar alguma lógica na leitura ou gravação do atributo, basta substituí-lo por uma propriedade, sem prejudicar a interface.&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Person:&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.name = ""&lt;br /&gt;        self.age = 0&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Substituindo por propriedades:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Person:&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.name = ""&lt;br /&gt;        self.__age = 0&lt;br /&gt;&lt;br /&gt;    def _get_age(self):&lt;br /&gt;        return self.__age&lt;br /&gt;&lt;br /&gt;    def _set_age(self, age):&lt;br /&gt;        if 0 &amp;lt;= age &amp;lt; 150:&lt;br /&gt;            self.__age = age&lt;br /&gt;&lt;br /&gt;    age = property(_get_age, _set_age)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E a interface permanece imutável!&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Aviso:&lt;/strong&gt; não use propriedade quando não for necessário! Use atributo público. Um pouco de desempenho não faz mal a ninguém, mesmo em &lt;em&gt;scripts&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Aviso&amp;sup2;: testei esse código no &lt;em&gt;prompt&lt;/em&gt; e não funciona, mas funciona em &lt;em&gt;script&lt;/em&gt;. Se alguém puder descobrir o que está acontecendo, agradeço.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;[update 2009-08-26]&lt;/tt&gt;Usando &lt;a href="http://ipython.scipy.org/moin/"&gt;IPython&lt;/a&gt; funcionou corretamente, portanto não sei o que causou o erro. =P&lt;br /&gt;&lt;br /&gt;Assim assim, valeu &lt;a href="http://thiagoc.net/"&gt;Thiago Coutinho&lt;/a&gt; por tê-lo identificado (acho que ainda ocorre durante a interpretação em linha do CPython tradicional).&lt;tt&gt;[/update]&lt;/tt&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Usando metaclasse&lt;/h3&gt;&lt;br /&gt;Uma forma de implementar automaticamente autopropriedades foi sugerida por Guido van Rossum em &lt;a href="http://www.pythonbrasil.com.br/moin.cgi/UnificandoTiposClasses"&gt;Unificando Tipos e Classes&lt;/a&gt; (&lt;a href="http://python.org/download/releases/2.2.3/descrintro/"&gt;original&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Usaremos uma metaclasse:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class autoprop(type):&lt;br /&gt;&lt;br /&gt;    def __init__(cls, name, base, dict):&lt;br /&gt;        super(autoprop, cls).__init__(name, base, dict)&lt;br /&gt;        props = {}&lt;br /&gt;        for method in dict:&lt;br /&gt;            if method.startswith("_get_") \&lt;br /&gt;                or method.startswith("_set_") \&lt;br /&gt;                or method.startswith("_del_"):&lt;br /&gt;                props[method[5:]] = True&lt;br /&gt;        for prop in props:&lt;br /&gt;            fget = getattr(cls, "_get_" + prop, None)&lt;br /&gt;            fset = getattr(cls, "_set_" + prop, None)&lt;br /&gt;            fdel = getattr(cls, "_del_" + prop, None)&lt;br /&gt;            setattr(cls, prop, property(fget, fset, fdel))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A ideia por trás dessa metaclasse é identificar métodos iniciados por &lt;code&gt;_get_&lt;/code&gt;, &lt;code&gt;_set_&lt;/code&gt; ou &lt;code&gt;_del_&lt;/code&gt; e criar propriedades a partir daí. O método iniciado por &lt;code&gt;_get_&lt;/code&gt; representa a leitura, &lt;code&gt;_set_&lt;/code&gt; representa a escrita e &lt;code&gt;_del_&lt;/code&gt; representa a remoção.&lt;br /&gt;&lt;br /&gt;Nossa classe então ficaria assim:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Person:&lt;br /&gt;    __metaclass__ = autoprop&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.name = ""&lt;br /&gt;        self.__age = 0&lt;br /&gt;&lt;br /&gt;    def _get_age(self):&lt;br /&gt;        return self.__age&lt;br /&gt;&lt;br /&gt;    def _set_age(self, age):&lt;br /&gt;        if 0 &amp;lt;= age &amp;lt; 150:&lt;br /&gt;            self.__age = age&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Usando decoradores&lt;/h3&gt;&lt;br /&gt;Mas realmente, ao contrário da metaclasse para &lt;a href="http://kodumaro.blogspot.com/2009/01/s-ingleton.html"&gt;&lt;em&gt;singleton&lt;/em&gt;&lt;/a&gt;, usar metaclasse para autopropriedade é como usar uma escopeta para espantar uma mosca.&lt;br /&gt;&lt;br /&gt;Vamos usar decoradores!&lt;br /&gt;&lt;br /&gt;O decorador &lt;code&gt;@property&lt;/code&gt; pode ser usado para criar propriedades para apenas leitura. Como precisamos de leitura e gravação, podemos usar &lt;code&gt;@apply&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;É um pouco &lt;em&gt;gambiarrático&lt;/em&gt;, mas funciona muito bem e deixa o código relativamente limpo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Person:&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.name = ""&lt;br /&gt;        self.__age = 0&lt;br /&gt;&lt;br /&gt;    @apply&lt;br /&gt;    def age():&lt;br /&gt;        def fget(self):&lt;br /&gt;            return self.__age&lt;br /&gt;&lt;br /&gt;        def fset(self, age):&lt;br /&gt;            if 0 &amp;lt;= age &amp;lt; 150:&lt;br /&gt;                self.__age = age&lt;br /&gt;&lt;br /&gt;        return property(**locals())&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A função deve ter o nome da propriedade. O método de escrita deve chamar-se &lt;code&gt;fset&lt;/code&gt;, o de leitura &lt;code&gt;fget&lt;/code&gt; e o de remoção &lt;code&gt;fdel&lt;/code&gt;. A parte mais feia desse código é o retorno. =)&lt;br /&gt;&lt;br /&gt;**&lt;br /&gt;&lt;br /&gt;Fica aqui a dica!&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-6235602295320517129?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/6235602295320517129/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=6235602295320517129' title='14 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/6235602295320517129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/6235602295320517129'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/01/propriedades.html' title='Propriedades e acessores'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-329129268178961671</id><published>2009-01-28T20:53:00.008-03:00</published><updated>2009-01-29T08:42:04.557-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='OO'/><title type='text'>Interface fluente</title><content type='html'>Outro &lt;a href="http://en.wikipedia.org/wiki/Design_pattern"&gt;&lt;em&gt;pattern&lt;/em&gt;&lt;/a&gt; interessante é conhecido como &lt;a href="http://en.wikipedia.org/wiki/Fluent_interface"&gt;&lt;em&gt;carrying return&lt;/em&gt;&lt;/a&gt; (não confundir com &lt;em&gt;carriage return&lt;/em&gt;, carácter com código ASCII 13).&lt;br /&gt;&lt;blockquote&gt;&lt;tt&gt;[update 2009-01-29]&lt;/tt&gt;Esse era o nome dado há uns anos atrás, quando conheci esse &lt;em&gt;pattern&lt;/em&gt;. Porém ele não ganhou espaço entre os programadores na época e poucos continuaram usando (como eu). =P&lt;br /&gt;&lt;br /&gt;Hoje em dia ele voltou com o nome &lt;em&gt;Fluent Interface&lt;/em&gt;, Interface Fluente.&lt;br /&gt;&lt;br /&gt;A propósito, troquei o título deste artigo para usar uma linguagem mais nova e mais fácil de ser reconhecida.&lt;br /&gt;&lt;br /&gt;Valeu &lt;a href="http://devlog.waltercruz.com/"&gt;Walter&lt;/a&gt; e &lt;a href="http://www.blogger.com/profile/06234409817785100127"&gt;Lucas&lt;/a&gt;!&lt;tt&gt;[/update]&lt;/tt&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;del&gt;Há outros nomes, mas não consigo encontrar no &lt;a href="http://www.google.com/search?q=fluent+interface"&gt;São Google&lt;/a&gt;, pois não é um &lt;em&gt;pattern&lt;/em&gt; muito usado.&lt;/del&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Parecido com Smalltalk&lt;/h3&gt;&lt;br /&gt;Imagine que você tem uma classe &lt;a href="http://java.sun.com/"&gt;Java&lt;/a&gt; que recebe muitos parâmetros na instanciação:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;Person person = new Person(&lt;br /&gt;    aString, aDate, anotherString, aLoad, aPerson, anotherPerson&lt;br /&gt;);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A quantidade de argumentos pode explodir ao extremo. &lt;a href="http://python.org/"&gt;Python&lt;/a&gt; pode apresentar maior visibilidade quanto ao significado dos parâmetros:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;person = Person(&lt;br /&gt;    name=aString,&lt;br /&gt;    birthdate=aDate,&lt;br /&gt;    id=anotherString,&lt;br /&gt;    load=aLoad,&lt;br /&gt;    father=aPerson,&lt;br /&gt;    mother=anotherPerson&lt;br /&gt;)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://smalltalk.org/"&gt;Smalltalk&lt;/a&gt;, uma linguagem bem mais antiga do que Python ou Java, já tinha uma abordagem bem mais elegante:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;person := Person new.&lt;br /&gt;person&lt;br /&gt;    setName:      aString;&lt;br /&gt;    setBirthdate: aDate;&lt;br /&gt;    setId:        anotherString;&lt;br /&gt;    setLoad:      aLoad;&lt;br /&gt;    setFather:    aPerson;&lt;br /&gt;    setMother:    anotherPerson.&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;É possível conseguir um código similar em Java usando acessores tipo &lt;em&gt;setter&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;Person person = new Person();&lt;br /&gt;person.setName(aString);&lt;br /&gt;person.setBirthdate(aDate);&lt;br /&gt;person.setId(anotherString);&lt;br /&gt;person.setLoad(aLoad);&lt;br /&gt;person.setFather(aPerson);&lt;br /&gt;person.setMother(anotherPerson);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Finalmente&lt;/h3&gt;&lt;br /&gt;Mas é possível obter um código ainda mais elegante usando o &lt;em&gt;pattern&lt;/em&gt; em questão.&lt;br /&gt;&lt;br /&gt;A ideia é simples: em vez dos acessores &lt;em&gt;setter&lt;/em&gt; não terem retorno (&lt;code&gt;void&lt;/code&gt;), basta eles retornarem &lt;code&gt;this&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Person {&lt;br /&gt;    private String name;&lt;br /&gt;    private Date birthdate;&lt;br /&gt;    private String id;&lt;br /&gt;    private Load load;&lt;br /&gt;    private Person father;&lt;br /&gt;    private Person mother;&lt;br /&gt;&lt;br /&gt;    public Person() {&lt;br /&gt;        name = null;&lt;br /&gt;        birthdate = null;&lt;br /&gt;        id = null;&lt;br /&gt;        load = null;&lt;br /&gt;        father = null;&lt;br /&gt;        mother = null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getName() {&lt;br /&gt;        return name;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Person setName(String name) {&lt;br /&gt;        this.name = name;&lt;br /&gt;        return this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Date getBirthdate() {&lt;br /&gt;        return birthdate;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Person setBirthdate(Date birthdate) {&lt;br /&gt;        this.birthdate = birthdate;&lt;br /&gt;        return this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Load getLoad() {&lt;br /&gt;        return load;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Person setLoad(Load load) {&lt;br /&gt;        this.load = load;&lt;br /&gt;        return this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Person getFather() {&lt;br /&gt;        return father;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Person setFather(Person father) {&lt;br /&gt;        this.father = father;&lt;br /&gt;        return this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Person getMother() {&lt;br /&gt;        return mother;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Person setMother(Person mother) {&lt;br /&gt;        this.mother = mother;&lt;br /&gt;        return this;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora podemos usar uma estrutura de código similar à de Smalltalk:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;Person person = new Person()&lt;br /&gt;    .setName(aString)&lt;br /&gt;    .setBirthdate(aDate)&lt;br /&gt;    .setId(anotherString)&lt;br /&gt;    .setLoad(aLoad)&lt;br /&gt;    .setFather(aPerson)&lt;br /&gt;    .setMother(anotherPerson);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-329129268178961671?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/329129268178961671/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=329129268178961671' title='9 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/329129268178961671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/329129268178961671'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/01/return-this.html' title='Interface fluente'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-4157282883139547208</id><published>2009-01-27T21:39:00.006-03:00</published><updated>2009-01-28T20:52:18.942-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='OO'/><title type='text'>Singleton</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" alt="" /&gt; Um &lt;a href="http://en.wikipedia.org/wiki/Design_pattern"&gt;&lt;em&gt;design pattern&lt;/em&gt;&lt;/a&gt; bastante conhecido na engenharia de &lt;em&gt;software&lt;/em&gt; é &lt;a href="http://pt.wikipedia.org/wiki/Singleton"&gt;&lt;em&gt;singleton&lt;/em&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Singleton&lt;/em&gt; é quando uma classe possui apenas uma instância e não se deseja que em uma mesma aplicação haja mais de uma.&lt;br /&gt;&lt;br /&gt;Exemplos de classes desejadamente &lt;em&gt;singleton&lt;/em&gt; são &lt;em&gt;pools&lt;/em&gt; e carregadores.&lt;br /&gt;&lt;br /&gt;Em &lt;a href="http://www.cplusplus.com/"&gt;C++&lt;/a&gt; a saída para criar uma classe &lt;em&gt;singleton&lt;/em&gt; é tornar protegido seu método construtor e criar um método &lt;code&gt;getInstance&lt;/code&gt; para retornar a instância única:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Loader {&lt;br /&gt;    protected:&lt;br /&gt;        Loader();&lt;br /&gt;&lt;br /&gt;    public:&lt;br /&gt;        ~Loader();&lt;br /&gt;&lt;br /&gt;        static Loader&amp;amp; getInstance();&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O método &lt;code&gt;getInstance&lt;/code&gt; deve guardar uma referência estática para a instância:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;static Loader&amp;amp; Loader::getInstance() {&lt;br /&gt;    static Loader *instance = 0;&lt;br /&gt;    if (!instance)&lt;br /&gt;        instance = new Loader();&lt;br /&gt;    return *instance;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://java.sun.com/"&gt;Java&lt;/a&gt; utiliza a mesma abordagem, já outras linguagens, como &lt;a href="http://www.perl.org/"&gt;Perl&lt;/a&gt;, &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; e &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; têm uma abordagem bem mais elegante.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;em&gt;Singleton&lt;/em&gt; em Python&lt;/h3&gt;&lt;br /&gt;A ideia de &lt;em&gt;singleton&lt;/em&gt; em Python &amp;ndash; Perl e Ruby &amp;ndash; é usar o próprio construtor da classe para obter a instância.&lt;br /&gt;&lt;br /&gt;Por exemplo, em vez de (Java):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;Image character = Loader.getInstance().getImage("char.png");&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Teremos (Python):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;character = Loader().getImage("char.png")&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Há três formas de implementar &lt;em&gt;singleton&lt;/em&gt; em Python: &lt;sup&gt;1&lt;/sup&gt;implementando diretamente na classe, &lt;sup&gt;2&lt;/sup&gt;herdando um classe pai ou &lt;sup&gt;3&lt;/sup&gt;usando metaclasse (o mais divertido!).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Implementação direta na classe&lt;/h3&gt;&lt;br /&gt;Você pode implementar uma classe &lt;em&gt;singleton&lt;/em&gt; diretamente, usando os metamétodos &lt;code&gt;__new__&lt;/code&gt; (construtor real) e &lt;code&gt;__init__&lt;/code&gt; (construtor de inicialização).&lt;br /&gt;&lt;br /&gt;A classe ainda precisa ter um atributo de classe para armazenar a instância.&lt;br /&gt;&lt;br /&gt;A ideia mais simples é implementar &lt;code&gt;__new__&lt;/code&gt; para devolver a instância em vez de uma nova a cada vez:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Loader:&lt;br /&gt;&lt;br /&gt;    __instance = None&lt;br /&gt;    __initialized = False&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    def __new__(cls, *args, **keyw):&lt;br /&gt;        if cls.__instance is None:&lt;br /&gt;            cls.__instance = object.__new__(cls)&lt;br /&gt;        return cls.__instance&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Repare no atributo &lt;code&gt;__initialized&lt;/code&gt;&amp;hellip; isso é porque ainda temos um problema: o construtor de inicialização (&lt;code&gt;__init__&lt;/code&gt;) será chamado novamente a cada tentativa de obter a instância.&lt;br /&gt;&lt;br /&gt;Então precisamos verificar se a inicialização já foi executada:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    def __init__(self, *args, **keyw):&lt;br /&gt;        if not self.__initialized:&lt;br /&gt;            self.__initialized = True&lt;br /&gt;            # Restante do método...&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pronto! Nossa classe já é &lt;em&gt;singleton&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Herança&lt;/h3&gt;&lt;br /&gt;Podemos usar uma classe pai que implemente unicidade e estendê-la:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Singleton:&lt;br /&gt;&lt;br /&gt;    __instance = None&lt;br /&gt;    __initialized = False&lt;br /&gt;&lt;br /&gt;    def __new__(cls, *args, **keyw):&lt;br /&gt;        if cls.__instance is None:&lt;br /&gt;            cls.__instance = object.__new__(cls)&lt;br /&gt;        return cls.__instance&lt;br /&gt;&lt;br /&gt;    def __init__(self, *args, **keyw):&lt;br /&gt;        if not self.__initialized:&lt;br /&gt;            self.__initialized = True&lt;br /&gt;            self._init(*args, **keyw)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Assim, para implementar uma classe &lt;em&gt;singleton&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Loader(Singleton):&lt;br /&gt;&lt;br /&gt;    def _init(self, *args, **keyw):&lt;br /&gt;        # Este será o construtor...&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A vantagem desta abordagem é sua capacidade de reaproveitamento: é possível reutilizar a classe &lt;code&gt;Singleton&lt;/code&gt; como classe pai de cada nova classe &lt;em&gt;singleton&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;No entanto traz dois inconvenientes: primeiro os métodos podem conflitar com métodos de outras classes pai em herança múltipla; segundo é preciso prestar atenção à implementação estranha (uso de &lt;code&gt;_init&lt;/code&gt; em vez de &lt;code&gt;__init__&lt;/code&gt;) e ter cuidado com a sobrescrita de métodos.&lt;br /&gt;&lt;br /&gt;A solução para tornar isso mais transparente é usar uma metaclasse.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Metaclasse&lt;/h3&gt;&lt;br /&gt;Metaclasse é um classe cujas instâncias são classes. Vamos criar uma metaclasse cujas classes sejam &lt;em&gt;singleton&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class singleton(type):&lt;br /&gt;&lt;br /&gt;    def __init__(cls, name, base, dict):&lt;br /&gt;        super(singleton, cls).__init__(name, base, dict)&lt;br /&gt;        cls.__instance = None&lt;br /&gt;        cls.__copy__ = lambda self: self&lt;br /&gt;        cls.__deepcopy__ = lambda self, memo=None: self&lt;br /&gt;&lt;br /&gt;    def __call__(cls, *args, **keyw):&lt;br /&gt;        if cls.__instance is None:&lt;br /&gt;            cls.__instance = \&lt;br /&gt;                super(singleton, cls).__call__(*args, **keyw)&lt;br /&gt;        return cls.__instance&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora vem a beleza da metaclasse: para criar uma classe &lt;em&gt;singleton&lt;/em&gt; basta fazer:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Loader:&lt;br /&gt;    __metaclass__ = singleton&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nada mais! Todo o resto da classe pode ser implementado sem preocupações.&lt;br /&gt;&lt;br /&gt;A única dúvida que pode ocorrer é: e se a classe tiver outra metaclasse?&lt;br /&gt;&lt;br /&gt;É fácil resolver! Por exemplo: imagine uma classe &lt;em&gt;singleton&lt;/em&gt; que implemente autopropriedades:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Loader:&lt;br /&gt;&lt;br /&gt;    class __metaclass__(autoprop, singleton):&lt;br /&gt;        pass&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;**&lt;br /&gt;&lt;br /&gt;Está aqui outra dica! Mais sobre &lt;em&gt;singleton&lt;/em&gt; pode ser encontrado nas &lt;a href="http://montegasppa.blogspot.com/2006/09/metaclasses-singleton.html"&gt;Reflexões de Monte Gasppa e Giulia C.&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-4157282883139547208?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/4157282883139547208/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=4157282883139547208' title='6 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/4157282883139547208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/4157282883139547208'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/01/s-ingleton.html' title='S&lt;em&gt;ingleton&lt;/em&gt;'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-7744110868985511599</id><published>2009-01-27T11:06:00.017-03:00</published><updated>2009-01-28T09:08:08.678-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><title type='text'>Mostrando o status e o branch de repositórios git no console</title><content type='html'>Com uma função de &lt;em&gt;shell script&lt;/em&gt; e a ajuda da variável &lt;code&gt;PS1&lt;/code&gt; podemos fazer uma configuração bem interessante: exibir no próprio console em qual &lt;em&gt;branch&lt;/em&gt; estamos e qual o estado dele.&lt;br /&gt;&lt;br /&gt;Um exemplo de como fica:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3107/3231618838_62e0b90b3b_o.png"&gt;&lt;img style="display: block; margin: 0pt 10px 10px 0pt; text-align: center; cursor: hand; width: 500px; height: 200px;" src="http://farm4.static.flickr.com/3107/3231618838_ce16c91c0a.jpg" alt="Git no terminal" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Esse é um &lt;em&gt;screenshot&lt;/em&gt; do meu &lt;em&gt;desktop&lt;/em&gt;, mostrando o repositório do &lt;a href="http://getontracks.org/"&gt;tracks&lt;/a&gt; (um aplicativo interessante para quem pretende usar a metodologia GTD). Em amarelo, o caminho do repositório. Entre os colchetes, o &lt;em&gt;branch&lt;/em&gt; no qual estamos, e finalmente, um &lt;code&gt;*&lt;/code&gt; indicando se o repositório contém modificações ainda não confirmadas no repositório.&lt;br /&gt;&lt;br /&gt;Para configurar, basta adicionar ao seu &lt;code&gt;.bashrc&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;function parse_git_dirty {&lt;br /&gt;    [[ $(git status 2&gt; /dev/null | tail -n1) \&lt;br /&gt;        != "nothing to commit (working directory clean)" \&lt;br /&gt;    ]] &amp;amp;&amp;amp; echo "*"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function parse_git_branch {&lt;br /&gt;    git branch --no-color 2&gt; /dev/null | \&lt;br /&gt;    sed -e '/^[^*]/d' \&lt;br /&gt;        -e "s/* \(.*\)/[\1$(parse_git_dirty)]/"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;export PS1='\u@\h \[\033[1;33m\]\w\[\033[0m\]$(parse_git_branch)$'&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Visto originalmente &lt;a href="http://henrik.nyh.se/2008/12/git-dirty-prompt"&gt;aqui&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;- Walter Cruz&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-7744110868985511599?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/7744110868985511599/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=7744110868985511599' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/7744110868985511599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/7744110868985511599'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/01/mostrando-o-status-e-o-branch-de.html' title='Mostrando o status e o branch de repositórios git no console'/><author><name>Walter Cruz</name><uri>http://www.blogger.com/profile/10836863572075307104</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04770379102815352458'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-97797765010199340</id><published>2009-01-24T13:11:00.007-03:00</published><updated>2009-01-27T12:46:30.962-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Pyglet</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://photos1.blogger.com/blogger/6505/3295/200/python.png" alt="" /&gt; Há alguns módulos em &lt;a href="http://python.org/"&gt;Python&lt;/a&gt; de interface com a biblioteca de mídia &lt;a href="http://www.libsdl.org/"&gt;SDL&lt;/a&gt;, sendo o mais conhecido &lt;a href="http://pygame.org/"&gt;PyGame&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;PyGame é legal, lembra a mim a antiga API gráfica do Colour BASIC do &lt;a href="http://pt.wikipedia.org/wiki/MSX"&gt;MSX&lt;/a&gt; (eita saudosismo!).&lt;br /&gt;&lt;br /&gt;No entanto o &lt;a href="http://fazerjogos.org/"&gt;Kao Félix&lt;/a&gt; apresentou recentemente um outro módulo menos conhecido, chamado &lt;a href="http://www.pyglet.org/"&gt;Pyglet&lt;/a&gt;, que, a primeira vista, achei mais &lt;em&gt;pythónica&lt;/em&gt;. =D&lt;br /&gt;&lt;br /&gt;Gostaria então de sugirir dois tutoriais do Kao Félix:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;&lt;a href="http://fazerjogos.org/?p=107"&gt;Introdução à pyglet&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://fazerjogos.org/?p=117"&gt;Movimentação Suave e NPC’s na Pyglet&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Instalando Pyglet&lt;/h3&gt;&lt;br /&gt;Se você possui o &lt;a href="http://peak.telecommunity.com/DevCenter/EasyInstall"&gt;EasyInstall&lt;/a&gt;, basta executar:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;bash$&lt;/em&gt; &lt;strong&gt;sudo easy_install -U pyglet&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Primeira aplicação&lt;/h3&gt;&lt;br /&gt;Resolvi fazer minha primeira aplicação segundo as dicas do Kao Félix, mas adaptando a meu jeito próprio de programar.&lt;br /&gt;&lt;br /&gt;Iniciaremos com o &lt;em&gt;hash-bang&lt;/em&gt;, as peculiaridades de Python e os &lt;code&gt;import&lt;/code&gt;s dos submódulos de Pyglet que vamos precisar:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#!/usr/bin/env python&lt;br /&gt;# coding: UTF-8&lt;br /&gt;&lt;br /&gt;from __future__ import division&lt;br /&gt;__metaclass__ = type&lt;br /&gt;&lt;br /&gt;from pyglet import app, clock, resource, sprite&lt;br /&gt;from pyglet.window import key, Window&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Carregando os recursos iniciais&lt;/h3&gt;&lt;br /&gt;Esta é classe &lt;a href="http://montegasppa.blogspot.com/2006/09/metaclasses-singleton.html"&gt;&lt;em&gt;singleton&lt;/em&gt;&lt;/a&gt; para carregar os recursos de mídia que precisaremos.&lt;br /&gt;&lt;br /&gt;Fiz o seguinte: baixei a &lt;a href="http://fazerjogos.org/wp-content/uploads/2008/11/char.png"&gt;bola&lt;/a&gt; do Kao, mas pode também baixar &lt;a href="http://cacilhas.info/imagens/char.png"&gt;daqui mesmo&lt;/a&gt; &amp;ndash; preferível, para não sobrecarregar o &lt;em&gt;link&lt;/em&gt; dele.&lt;br /&gt;&lt;br /&gt;O arquivo de som está no pacote do KDE, mas você pode baixar &lt;a href="http://cacilhas.info/imagens/pop.wav"&gt;daqui&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Nessa classe &lt;em&gt;singleton&lt;/em&gt;, implementaremos o método &lt;code&gt;__new__&lt;/code&gt; (apenas para &lt;em&gt;singleton&lt;/em&gt;) e &lt;code&gt;__init__&lt;/code&gt; para carregar as mídias.&lt;br /&gt;&lt;br /&gt;Para carregar uma imagem usamos &lt;code&gt;resource.image()&lt;/code&gt;. Para áudio, &lt;code&gt;resource.media()&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Loader:&lt;br /&gt;    """Singleton class for loading resources"""&lt;br /&gt;&lt;br /&gt;    __inst = None&lt;br /&gt;    __initialized = False&lt;br /&gt;&lt;br /&gt;    def __new__(cls, *args, **keyw):&lt;br /&gt;        if not cls.__inst:&lt;br /&gt;            cls.__inst = object.__new__(cls)&lt;br /&gt;        return cls.__inst&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        if not self.__initialized:&lt;br /&gt;            self.__initialzed = True&lt;br /&gt;&lt;br /&gt;            self.images = {}&lt;br /&gt;            self.sounds = {}&lt;br /&gt;&lt;br /&gt;            image = resource.image("char.png")&lt;br /&gt;            image.anchor_x = image.width // 2&lt;br /&gt;            image.anchor_y = image.height // 2&lt;br /&gt;            self.images["ball"] = image&lt;br /&gt;&lt;br /&gt;            self.sounds["pop"] = resource.media(&lt;br /&gt;                "pop.wav",&lt;br /&gt;                streaming=False&lt;br /&gt;            )&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O parâmetro &lt;code&gt;streaming=False&lt;/code&gt; indica que o arquivo de áudio deve ser completamente carregado para a memória &amp;ndash; e não tratado como um fluxo (&lt;em&gt;stream&lt;/em&gt;).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Gerenciando o teclado&lt;/h3&gt;&lt;br /&gt;Uma nova classe será usada para gerenciar o teclado. O construtor armazenará uma referência para a janela principal e o método &lt;code&gt;handle_input()&lt;/code&gt; gerenciará as teclas:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class KeyHandler(key.KeyStateHandler):&lt;br /&gt;    """Class for handling key events"""&lt;br /&gt;&lt;br /&gt;    def __init__(self, window):&lt;br /&gt;        super(KeyHandler, self).__init__()&lt;br /&gt;        self.window = window&lt;br /&gt;&lt;br /&gt;    def handle_input(self, dt):&lt;br /&gt;        speed = 320 * dt&lt;br /&gt;        dx, dy = 0, 0&lt;br /&gt;&lt;br /&gt;        if self[key.RIGHT]:&lt;br /&gt;            dx = 1&lt;br /&gt;        elif self[key.LEFT]:&lt;br /&gt;            dx = -1&lt;br /&gt;&lt;br /&gt;        if self[key.UP]:&lt;br /&gt;            dy = 1&lt;br /&gt;        elif self[key.DOWN]:&lt;br /&gt;            dy = -1&lt;br /&gt;&lt;br /&gt;        self.window.ball.x += dx * speed&lt;br /&gt;        self.window.ball.y += dy * speed&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Repare que nosso objeto &lt;code&gt;window&lt;/code&gt; terá um atributo &lt;code&gt;ball&lt;/code&gt;, que é um &lt;a href="http://www.pyglet.org/doc/programming_guide/displaying_images.html#sprites"&gt;&lt;em&gt;sprite&lt;/em&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Agora nosso &lt;em&gt;sprite&lt;/em&gt;&lt;/h3&gt;&lt;br /&gt;Vamos criar agora uma classe que estende &lt;code&gt;sprite.Sprite&lt;/code&gt;, a classe de &lt;em&gt;sprite&lt;/em&gt; de Pyglet.&lt;br /&gt;&lt;br /&gt;O único método que implementaremos será o construtor, que buscará em &lt;code&gt;Loader&lt;/code&gt; a imagem que desejamos:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Ball(sprite.Sprite):&lt;br /&gt;    """Sprite that's a ball"""&lt;br /&gt;&lt;br /&gt;    def __init__(self, *args, **keyw):&lt;br /&gt;        super(Ball, self).__init__(&lt;br /&gt;            Loader().images["ball"],&lt;br /&gt;            *args, **keyw&lt;br /&gt;        )&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Janela principal&lt;/h3&gt;&lt;br /&gt;Finalmente a aplicação!&lt;br /&gt;&lt;br /&gt;Por um mal hábito adquirido programando &lt;a href="http://docs.python.org/library/tkinter.html"&gt;Tkinter&lt;/a&gt;, tenho o hábito de usar a mesma classe para aplicação e janela principal, porém você não precisa fazer &lt;del&gt;esse bacalhau&lt;/del&gt; isso!&lt;br /&gt;&lt;br /&gt;No entanto vou mostrar aqui da forma como estou habituado.&lt;br /&gt;&lt;br /&gt;O construtor:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;ajustará o título da janela (&lt;code&gt;set_caption()&lt;/code&gt;);&lt;/li&gt; &lt;li&gt;criará uma nova bola (classe &lt;code&gt;Ball&lt;/code&gt;);&lt;/li&gt; &lt;li&gt;registrará o manipulador de eventos de teclas (&lt;code&gt;push_handlers()&lt;/code&gt;);&lt;/li&gt; &lt;li&gt;e registrará o método &lt;code&gt;handle_input()&lt;/code&gt; do manipulador de eventos de teclas para execução periódica (&lt;code&gt;clock.schedule_interval()&lt;/code&gt;).&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class MainApplication(Window):&lt;br /&gt;    """Main window and application"""&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        super(MainApplication, self).__init__()&lt;br /&gt;        self.set_caption("Teste de movimento")&lt;br /&gt;&lt;br /&gt;        self.ball = Ball(x=300, y=240)&lt;br /&gt;&lt;br /&gt;        handler = KeyHandler(self)&lt;br /&gt;        self.push_handlers(handler)&lt;br /&gt;        clock.schedule_interval(handler.handle_input, 1/60)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Manipulando outros eventos&lt;/h3&gt;&lt;br /&gt;Os métodos de &lt;code&gt;Window&lt;/code&gt; que manipulam eventos têm nome iniciado por &lt;code&gt;on_&lt;/code&gt;, seguido pelo nome do evento. Por exemplo: &lt;code&gt;on_close&lt;/code&gt;, &lt;code&gt;on_draw&lt;/code&gt;, &lt;code&gt;on_key_press&lt;/code&gt;, &lt;code&gt;on_key_release&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Vamos implementar &lt;code&gt;on_close()&lt;/code&gt; para tocar o som ao sair e &lt;code&gt;on_draw()&lt;/code&gt; para exibir o &lt;em&gt;sprite&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    def on_close(self):&lt;br /&gt;        Loader().sounds["pop"].play()&lt;br /&gt;        super(MainApplication, self).on_close()&lt;br /&gt;&lt;br /&gt;    def on_draw(self):&lt;br /&gt;        self.clear()&lt;br /&gt;        self.ball.draw()&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Fazendo funcionar&lt;/h3&gt;&lt;br /&gt;Para terminar, precisamos instanciar a aplicação e chamar o ciclo principal de Pyglet.&lt;br /&gt;&lt;br /&gt;&lt;small&gt;Veja que esse tipo de programação onde um módulo toma o controle e programamos os métodos que atenderão eventos caracteriza um &lt;em&gt;framework&lt;/em&gt;.&lt;/small&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;if __name__ == "__main__":&lt;br /&gt;    window = MainApplication()&lt;br /&gt;    app.run()&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusão&lt;/h3&gt;&lt;br /&gt;Vemos aqui um ótimo módulo &amp;ndash; ou melhor, &lt;em&gt;framework&lt;/em&gt; &amp;ndash; para criação de aplicações gráficas usando as bibliotecas SDL e &lt;a href="http://opengl.org/"&gt;OpenGL&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-97797765010199340?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/97797765010199340/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=97797765010199340' title='4 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/97797765010199340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/97797765010199340'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/01/pyglet.html' title='Pyglet'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-7843244449481146369</id><published>2009-01-10T07:43:00.003-03:00</published><updated>2009-01-10T10:09:22.493-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><title type='text'>Atributos privados onde?</title><content type='html'>Os programadores de &lt;a href="http://java.sun.com/"&gt;Java&lt;/a&gt; e &lt;a href="http://www.cplusplus.com/"&gt;C++&lt;/a&gt; pregam vigorosamente a favor de métodos e atributos privados, como se isso fosse uma grandíssima vantagem.&lt;br /&gt;&lt;br /&gt;É um recurso&amp;hellip; faz sentido em seu contexto, mas não traz vantagem alguma por si só &amp;ndash; ao contrário da evangelização dos fanáticos.&lt;br /&gt;&lt;br /&gt;De qualquer forma, o C++ não bloqueia tanto o acesso do programador quanto é pregado.&lt;br /&gt;&lt;br /&gt;Por exemplo, voltemos lá atrás no artigo &lt;a href="http://kodumaro.blogspot.com/2008/10/portando-gdbm-para-lua.html"&gt;Portanto GDBM para Lua&lt;/a&gt;: havia uma classe &lt;code&gt;GdbmObject&lt;/code&gt; com um descritor de arquivo de banco de dados privado.&lt;br /&gt;&lt;br /&gt;Digamos que, por alguma razão bizarra, queiramos ter acesso direto ao descritor.&lt;br /&gt;&lt;br /&gt;Mas o atributo é privado!&lt;br /&gt;&lt;br /&gt;Vamos ao &lt;strong&gt;bacalhau&lt;/strong&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class GdbmObjectCorrupting {&lt;br /&gt;    public:&lt;br /&gt;        bool closed;&lt;br /&gt;        GDBM_FILE fd;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Repare que os atributos públicos aqui têm o mesmo tipo e o mesmo nome dos atributos privados da classe original. Isso garantirá que os símbolos gerados sejam idênticos &amp;ndash; e este é o truque.&lt;br /&gt;&lt;br /&gt;Agora imagine que temos a instância &lt;code&gt;obj&lt;/code&gt; de &lt;code&gt;GdbmObject&lt;/code&gt;, da qual queremos acessar os atributos privados. A mágica é:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;GdbmObjectCorrupting *aux =&lt;br /&gt;    reinterpret_cast&amp;lt;GdbmObjectCorrupting *&amp;gt;(obj);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pronto! Já está feit&lt;del&gt;o o bacalhau&lt;/del&gt;a a mágica!&lt;br /&gt;&lt;br /&gt;No escopo de &lt;code&gt;aux&lt;/code&gt;, &lt;code&gt;aux-&amp;gt;fd&lt;/code&gt; dá acesso direto ao descritor de &lt;code&gt;obj&lt;/code&gt;, assim como &lt;code&gt;aux-&amp;gt;closed&lt;/code&gt; dá acesso ao booleano &lt;code&gt;closed&lt;/code&gt; de &lt;code&gt;obj&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Agora, este artigo é uma &lt;strong&gt;prova de conceito&lt;/strong&gt;! Não aconselho ninguém a fazer isso. Aliás &lt;u&gt;o &lt;a href="http://kodumaro.blogspot.com/"&gt;Kodumaro&lt;/a&gt; desaprova fortemente tal prática&lt;/u&gt;: reitero, é apenas uma prova de conceito.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-7843244449481146369?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/7843244449481146369/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=7843244449481146369' title='11 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/7843244449481146369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/7843244449481146369'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2009/01/atributos-privados-onde.html' title='Atributos privados onde?'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-8120201546523373317</id><published>2008-12-10T22:27:00.006-03:00</published><updated>2008-12-11T13:59:52.560-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Perl'/><title type='text'>Perl6</title><content type='html'>&lt;img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; border: none;" src="http://photos1.blogger.com/blogger/6505/3295/200/camel.png" alt="Perl" /&gt; &lt;a href="http://www.wall.org/~larry/"&gt;Larry Wall&lt;/a&gt;, criador do &lt;a href="http://www.perl.org/"&gt;Perl&lt;/a&gt; e cocriador do &lt;a href="http://www.parrot.org/"&gt;Parrot&lt;/a&gt;, declarou que &lt;a href="http://www.computerworld.com.au/article/269758/perl_6_break_compatibility_support_other_interpreters?eid=-6787"&gt;a versão 6 de Perl não será compatível com as versões anteriores&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Realmente dei uma olhada no &lt;a href="http://dev.perl.org/perl6/"&gt;Perl6&lt;/a&gt; e está muito diferente&amp;hellip; só que para melhor. =)&lt;br /&gt;&lt;br /&gt;A única coisa de que não gostei foram das mudanças em &lt;a href="http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html"&gt;expressões regulares&lt;/a&gt;, no mais as mudanças só acrescentam.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Tipagem&lt;/h3&gt;&lt;br /&gt;Uma das maiores reclamações que os programadores fazem de Perl é sua tipagem &lt;em&gt;insanamente&lt;/em&gt; fraca, apenas três tipos: escalar (&lt;code&gt;$&lt;/code&gt;&lt;em&gt;scalar&lt;/em&gt;), vetor (&lt;code&gt;@&lt;/code&gt;&lt;em&gt;array&lt;/em&gt;) e vetor associativo (&lt;code&gt;%&lt;/code&gt;&lt;em&gt;hash&lt;/em&gt;).&lt;br /&gt;&lt;br /&gt;Perl6 traz o suporte a tipos! Pelo que vi na documentação, há seis tipos novos: inteiro (&lt;code&gt;int&lt;/code&gt;), ponto flutuante (&lt;code&gt;num&lt;/code&gt;), &lt;em&gt;string&lt;/em&gt; (&lt;code&gt;str&lt;/code&gt;), booleano (&lt;code&gt;bool&lt;/code&gt;), &lt;em&gt;bit&lt;/em&gt; (&lt;code&gt;bit&lt;/code&gt;) e referência (&lt;code&gt;ref&lt;/code&gt;), de forma estática:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my int $foo = 5;&lt;br /&gt;my str $bar = "foo";&lt;br /&gt;my num $baz = 5.3;&lt;br /&gt;my bool $foobar = 1;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Conversão:&lt;pre&gt;&lt;code class="prettyprint"&gt;print str 5;&lt;br /&gt;print scalar @list;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Passagem de parâmetros&lt;/h3&gt;&lt;br /&gt;Em Perl a passagem de parâmetros sempre foi por cópia, agora passa a ser por referência, exceto para tipos primitivos.&lt;br /&gt;&lt;br /&gt;No caso de atribuição de referência de tipos primitivos, em vez do tradicional:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt; my $b = &amp;#92;$a;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt; my $b := $a;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Mudanças em vetores&lt;/h3&gt;&lt;br /&gt;A criação de vetor passa a suportar um formato mais simples.&lt;br /&gt;&lt;br /&gt;Temos o tradicional:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my @fruits = ("apple", "pear", "banana");&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Que passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my @fruits = "apple", "pear", "banana";&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E a lista:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my @fruits = qw/apple pear banana/;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my @fruits = &amp;lt;apple pear banana&amp;gt;;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Em Perl5, para se obter um item de um vetor, o primeiro carácter mudava de &lt;code&gt;@&lt;/code&gt; para &lt;code&gt;$&lt;/code&gt;: &lt;code&gt;$fruits[0]&lt;/code&gt;. Agora, em Perl6, não há mais alteração: &lt;code&gt;@fruits[0]&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;A quantidade de elementos de um vetor era dada por:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my $count = $#fruits + 1;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora, em Perl6 passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my int $count = @fruits.elems;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Repara que o famigerado &lt;code&gt;-&amp;gt;&lt;/code&gt; virou um simples ponto!&lt;br /&gt;&lt;br /&gt;Também para obter o último elemento do vetor, que era:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my $last = $fruit[$#fruit];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my $last = @fruit[@fruit.end];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ou ainda:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my $last = @fruit[*-1];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para se obter um vetor em um contexto &lt;em&gt;string&lt;/em&gt;, Perl6 oferece o atalho &lt;code&gt;~&lt;/code&gt;. Para numérico &lt;code&gt;+&lt;/code&gt; e para booleano &lt;code&gt;?&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my str $str_fruits = ~@fruits;&lt;br /&gt;my num $num_fruits = +@fruits;&lt;br /&gt;my bool $bool_fruits = ?@fruits;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Tratamento de exceções&lt;/h3&gt;&lt;br /&gt;Em Perl5 era usado &lt;code&gt;eval&lt;/code&gt; para avaliar um bloco com possível exceção e &lt;code&gt;$@&lt;/code&gt; recebia os dados de exceção:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;eval {&lt;br /&gt;    &amp;hellip;&lt;br /&gt;};&lt;br /&gt;if ($@) {&lt;br /&gt;    warn "exception: $@";&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Perl6 passa a usar &lt;code&gt;try&lt;/code&gt;-&lt;code&gt;CATCH&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;try {&lt;br /&gt;    &amp;hellip;&lt;br /&gt;    CATCH {&lt;br /&gt;        warn "exception: $!";&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Repare que a mensagem de exceção passa a ser capturada em &lt;code&gt;$!&lt;/code&gt; e o bloco &lt;code&gt;CATCH&lt;/code&gt; fica dentro do bloco &lt;code&gt;try&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Repetições&lt;/h3&gt;&lt;br /&gt;Não há uma forma menos dolorosa de dizer isso: &lt;code&gt;foreach&lt;/code&gt; vira &lt;code&gt;for&lt;/code&gt;, que também passa a suportar algumas construções de &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt; vira &lt;code&gt;loop&lt;/code&gt;, que também passa a suportar algumas construções de &lt;code&gt;while&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Então:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;foreach (@fruits) {&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Vira:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;for @fruits {&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;foreach my $fruit (@fruits) {&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Vira:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;for @fruits -&amp;gt; $fruit {&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora, olha o &lt;code&gt;while&lt;/code&gt; aí:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;while (my($age, $sex, $location) = splice @whatever, 0, 3) {&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Vira:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;for @whatever -&amp;gt; $age, $sex, $location {&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Contando até dez em Perl5:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;for (my $i = 1; $i &amp;lt;=10; $i++) {&lt;br /&gt;    print "$i\n";&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Contando até dez em Perl6:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;loop (my $i = 1; $i &amp;lt;=10; $i++) {&lt;br /&gt;    say $i;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E &lt;code&gt;loop { &amp;hellip; }&lt;/code&gt; funciona como &lt;code&gt;while (1) { &amp;hellip; }&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Vetor associativo&lt;/h3&gt;&lt;br /&gt;Sofre alterações parecidas com as de vetor.&lt;br /&gt;&lt;br /&gt;Por exemplo, em Perl5:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;my $c = $days{February};&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Em Perl6 vira:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;my int $c = %days{'February'};&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ou ainda:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;my int $c = %days&amp;lt;February&amp;gt;;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Alguns métodos&lt;/h3&gt;&lt;br /&gt;Para se obter o tamanho de uma &lt;em&gt;string&lt;/em&gt; em Perl5:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;my $len = length $string;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Em Perl6 fica:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;my int $len = $string.chars;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para exibir um vetor de modo ordenado em Perl5:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;print sort(@fruits);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Em Perl6:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;say @array.sort;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ou ainda:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;@array.sort.print;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Variáveis de sistema&lt;/h3&gt;&lt;br /&gt;Para se obter o valor da variável &lt;code&gt;HOME&lt;/code&gt; em Perl5:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;print $ENV{HOME};&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Em Perl6 passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;print %*ENV&amp;lt;HOME&amp;gt;;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ou ainda:&lt;br /&gt;&lt;pre&gt;&lt;code="prettyprint"&gt;print $+HOME;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Orientação a objetos&lt;/h3&gt;&lt;br /&gt;Criar uma classe em Perl5 era uma &lt;a href="http://montegasppa.blogspot.com/2006/09/orientao-objetos-em-perl.html"&gt;aventura&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Você criava um pacote (&lt;code&gt;package&lt;/code&gt;) e «abençoava» um escalar com o pacote&amp;hellip; pronto: aí tinha uma instância cuja classe era o pacote.&lt;br /&gt;&lt;br /&gt;Um tremendo &lt;strong&gt;bacalhau&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Em Perl6 temos as palavras reservadas &lt;code&gt;class&lt;/code&gt;, &lt;code&gt;has&lt;/code&gt; (para atributos) e &lt;code&gt;method&lt;/code&gt; (para métodos), para criar classes reais.&lt;br /&gt;&lt;br /&gt;Métodos privados precisam começar com &lt;code&gt;!&lt;/code&gt;, por exemplo, &lt;code&gt;$!age&lt;/code&gt;, e métodos públicos precisam começar com &lt;code&gt;.&lt;/code&gt;, como por exemplo &lt;code&gt;$.name&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;A passagem de parâmetros também mudou. Além de ser por referência, como citado, passa a suportar parâmetros nominais e parâmetros excedentes &amp;ndash; como &lt;code&gt;*args&lt;/code&gt; de &lt;a href="http://python.org/"&gt;Python&lt;/a&gt;, mas com a sintaxe &lt;code&gt;*@args&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Se o argumento for mutável precisa ser seguido de &lt;code&gt;is&amp;nbsp;rw&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;O que era:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;package Square;&lt;br /&gt;@ISA = qw/ Rectangle /;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class Square is Rectangle {&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E o que era:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my $rect = new Rectangle(4, 5);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Passa a ser:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;my Rectangle $rect .= new(4, 5);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusão&lt;/h3&gt;&lt;br /&gt;Há muito mais! Consulte a página &lt;a href="http://feather.perl6.nl/syn/Differences.html"&gt;Perl6::Perl5::Differences&lt;/a&gt;, mas o que já sabemos é: quem trabalha com Perl &lt;strong&gt;vai precisar aprender de novo&lt;/strong&gt;!&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-8120201546523373317?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/8120201546523373317/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=8120201546523373317' title='11 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/8120201546523373317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/8120201546523373317'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2008/12/perl6.html' title='Perl6'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-5444979955200612086</id><published>2008-12-05T15:18:00.002-03:00</published><updated>2008-12-05T15:20:02.918-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='OO'/><title type='text'>Persistência de dados entre execuções em OpenStep</title><content type='html'>&lt;img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; width: 100px; height: 105px; border: none;" src="http://1.bp.blogspot.com/_rGfO7DAuOSE/SRT62RK9EZI/AAAAAAAAAKg/53tVzG0MiP8/s200/gnustep.jpg" alt="GNUstep" /&gt; &lt;a href="http://pt.wikipedia.org/wiki/OpenStep"&gt;OpenStep&lt;/a&gt; facilita a persistência de dados entre uma execução e outra do programa através da classe &lt;code&gt;NSUserDefaults&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Para persistir dados para a próxima execução, basta criar um dicionário (&lt;code&gt;NSDictionary&lt;/code&gt;) representando um &lt;em&gt;hash&lt;/em&gt; dos dados a serem persistidos.&lt;br /&gt;&lt;br /&gt;Digamos que o dicionário seja &lt;code&gt;defaults&lt;/code&gt; e &lt;code&gt;APP_NAME&lt;/code&gt; é uma &lt;em&gt;string&lt;/em&gt; (&lt;code&gt;NSString&lt;/code&gt;) representando o nome da aplicação:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;[[NSUserDefaults standardUserDefaults]&lt;br /&gt;    setPersistentDomain: defaults&lt;br /&gt;    forName: APP_NAME&lt;br /&gt;];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E para recuperar os dados persistidos da última execução:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;NSDictionary *defaults = [&lt;br /&gt;    [NSUserDefaults standardUserDefaults]&lt;br /&gt;    persistentDomainForName: APP_NAME&lt;br /&gt;];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Então &lt;code&gt;defaults&lt;/code&gt; será um dicionário contendo os dados persistidos!&lt;br /&gt;&lt;br /&gt;Simples assim. =)&lt;br /&gt;&lt;br /&gt;Referência: &lt;a href="http://www.gnustep.org/resources/documentation/Developer/Base/Reference/"&gt;GNUstep Base&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-5444979955200612086?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/5444979955200612086/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=5444979955200612086' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/5444979955200612086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/5444979955200612086'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2008/12/persistencia-de-dados-em-openstep.html' title='Persistência de dados entre execuções em OpenStep'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_rGfO7DAuOSE/SRT62RK9EZI/AAAAAAAAAKg/53tVzG0MiP8/s72-c/gnustep.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-1718094671209626306</id><published>2008-11-20T09:38:00.011-03:00</published><updated>2009-11-27T20:32:13.359-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Lua'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Base64</title><content type='html'>De vez enquando, não tem como não, nós programadores sempre esbarramos na &lt;a href="http://pt.wikipedia.org/wiki/Base64"&gt;Base64&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Base64 é um protocolo de codificação que usa apenas seis &lt;em&gt;bits&lt;/em&gt;, o que significa um conjunto de sessenta e quatro (64) elementos &amp;ndash; daí Base&lt;strong&gt;64&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;A conversão de oito (&lt;em&gt;byte&lt;/em&gt;) para seis &lt;em&gt;bits&lt;/em&gt; é feita da seguinte forma:&lt;br /&gt;&lt;center&gt;&lt;code&gt;xxxxxx.xx xxxx.xxxx xx.xxxxxx&lt;/code&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Ou ainda:&lt;br /&gt;&lt;center&gt;&lt;code&gt;aaaaaabb bbbbcccc ccdddddd&lt;/code&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Os elementos usados são caracteres simples, começando com as letras maiúsculas, &lt;code&gt;A&lt;/code&gt; (0) a &lt;code&gt;Z&lt;/code&gt; (25), então as letras minúsculas, &lt;code&gt;a&lt;/code&gt; (26) a &lt;code&gt;z&lt;/code&gt; (51), os números, &lt;code&gt;0&lt;/code&gt; (52) a &lt;code&gt;9&lt;/code&gt; (61), e os caracteres &lt;code&gt;+&lt;/code&gt; (62) e &lt;code&gt;/&lt;/code&gt; (63).&lt;br /&gt;&lt;br /&gt;Na conversão de &lt;em&gt;bytes&lt;/em&gt; (8b) para Base64 (6b), cada três &lt;em&gt;bytes&lt;/em&gt; é convertido em quatro dígitos, então um código Base64 é sempre pensado em grupos de quatro. Se o tamanho de um código Base64 não for múltiplo de quatro, caracteres &lt;code&gt;=&lt;/code&gt; são acrescentados ao final até que o tamanho seja múltiplo de quatro.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Python&lt;/h3&gt;&lt;br /&gt;Em &lt;a href="http://python.org/"&gt;Python&lt;/a&gt;, Base64 é tão simples que nem tem graça:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/em&gt; &lt;strong&gt;print "Kodumaro".encode("base64")&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;S29kdW1hcm8=&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/em&gt; &lt;strong&gt;print "S29kdW1hcm8=".decode("base64")&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;Kodumaro&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Lua&lt;/h3&gt;&lt;br /&gt;Em &lt;a href="http://www.lua.org/"&gt;Lua&lt;/a&gt;, é preciso baixar o módulo &lt;a href="http://www.tecgraf.puc-rio.br/~diego/professional/luasocket/mime.html"&gt;Mime&lt;/a&gt; do &lt;a href="http://www.tecgraf.puc-rio.br/~diego/professional/luasocket/"&gt;LuaSocket&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; &lt;strong&gt;require "mime"&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; &lt;strong&gt;print(mime.b64 "Kodumaro")&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;S29kdW1hcm8=&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; &lt;strong&gt;print(mime.unb64 "S29kdW1hcm8=")&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;Kodumaro&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Smalltalk&lt;/h3&gt;&lt;br /&gt;Sendo muito sincero sobre o assunto, &lt;strong&gt;não sei&lt;/strong&gt; como fazer conversão de Base64 em &lt;a href="http://smalltalk.org/"&gt;Smalltalk&lt;/a&gt;. =(&lt;br /&gt;&lt;br /&gt;Mas sei que os módulos do &lt;a href="http://seaside.st/"&gt;Seaside&lt;/a&gt; providenciam isso!&lt;br /&gt;&lt;br /&gt;Se alguém souber, por favor informe!&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;tt&gt;[update 2009-11-27]&lt;/tt&gt;&lt;br /&gt;Sugestão do &lt;a href="http://www.blogger.com/profile/06182924594031018840"&gt;Hugo&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;No Squeak tem isso aqui:&lt;/em&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;(Base64MimeConverter mimeEncode: 'base64' readStream) contents&lt;br /&gt;(Base64MimeConverter mimeDecode: 'S29kdW1hcm8' as: ByteString) contents&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;E no Pharo tem métodos para &lt;/em&gt;strings&lt;em&gt;:&lt;/em&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;'base64' base64Encoded&lt;br /&gt;'S29kdW1hcm8' base64Decoded&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;A implementação usa as coisas do Squeak:&lt;/em&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;String&amp;gt;&amp;gt;base64Decoded&lt;br /&gt;↑ (Base64MimeConverter mimeDecode: self as: self class)&lt;br /&gt;&lt;br /&gt;String&amp;gt;&amp;gt;base64Encoded&lt;br /&gt;↑ (Base64MimeConverter mimeEncode: self readStream) contents&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Para outros Smalltalks eu não sei…&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Legal né? =)&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Muito legal sim, Hugo, valeu!&lt;br /&gt;&lt;tt&gt;[/update]&lt;/tt&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;C&lt;/h3&gt;&lt;br /&gt;Aha! Aqui começa de verdade a brincadeira!&lt;br /&gt;&lt;br /&gt;É claro que você pode usar as funcionalidades de Base64 da &lt;em&gt;gLibC&lt;/em&gt;, mas descobri que nem todas as versões dela apresentam tais funcionalidades:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;glib/gbase64.h&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Vamos precisar usar os cabeçalhos &lt;code&gt;stdlib.h&lt;/code&gt;, &lt;code&gt;string.h&lt;/code&gt; e &lt;code&gt;sys/types.h&lt;/code&gt;. Como também vamos criar um cabeçalho para «compartilhar» algumas funções, ele também será incluído no início de nosso arquivo &lt;code&gt;base64.c&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;string.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;#include "base64.h"&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora vamos criar um &lt;em&gt;array&lt;/em&gt; com todos os possíveis caracteres Base64 em sua ordem natural:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;static const char b64all[] =&lt;br /&gt;    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"&lt;br /&gt;    "ghijklmnopqrstuvwxyz0123456789+/";&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Também vamos precisar de três funções locais: uma para obter o índice de um elemento (&lt;code&gt;_getindex&lt;/code&gt;), outra para codificar para Base64 um grupo de três &lt;em&gt;bytes&lt;/em&gt; (&lt;code&gt;_encode&lt;/code&gt;) e mais uma para decodificar um grupo de quatro elementos Base64 (&lt;code&gt;_decode&lt;/code&gt;):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int _decode(u_int8_t *, const u_int8_t *);&lt;br /&gt;void _encode(u_int8_t *, const u_int8_t *, int);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Não é preciso uma função para &lt;code&gt;_getindex&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#define _getindex(c) (int) (index(b64all, c) - b64all)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Repara que, em vez de &lt;code&gt;char&lt;/code&gt;, estamos usando &lt;code&gt;u_int8_t&lt;/code&gt;, que é mais conveniente quando queremos lidar com &lt;em&gt;bytes&lt;/em&gt; enquanto &lt;em&gt;bytes&lt;/em&gt;, não caracteres.&lt;br /&gt;&lt;br /&gt;A partir daqui, se preferir, organize as funções em ordem alfabética &amp;ndash; ou na ordem que quiser.&lt;br /&gt;&lt;br /&gt;A primeira função que implementaremos será para codificar uma &lt;em&gt;string&lt;/em&gt; C (&lt;code&gt;const char *&lt;/code&gt;) para Base64. Como a &lt;em&gt;string&lt;/em&gt; pode não ser bem formada, a função deverá receber também seu tamanho:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;const char *b64encode(const char *original, int length) {&lt;br /&gt;    // Se o tamanho não for informado, consideramos uma string bem&lt;br /&gt;    // formada&lt;br /&gt;    if (length == 0)&lt;br /&gt;        length = strlen(original);&lt;br /&gt;&lt;br /&gt;    // Inteiro com o tamanho do código a ser gerado&lt;br /&gt;    int b64length = ((length + 2) / 3) * 4 + 1;&lt;br /&gt;&lt;br /&gt;    // Contadores para percorrer as strings&lt;br /&gt;    int i=0, j=0;&lt;br /&gt;&lt;br /&gt;    // Alocando memória para o código&lt;br /&gt;    char *b64 = (char *) malloc(sizeof(char) * b64length);&lt;br /&gt;    memset(b64, 0, b64length);&lt;br /&gt;&lt;br /&gt;    while (i &amp;lt; length) {&lt;br /&gt;        // Codifica um grupo de três bytes...&lt;br /&gt;        _encode(&lt;br /&gt;            (u_int8_t *) b64 + j,&lt;br /&gt;            (const u_int8_t *) original + i,&lt;br /&gt;            (length - i)&lt;br /&gt;        );&lt;br /&gt;&lt;br /&gt;        // E segue para o próximo grupo&lt;br /&gt;        i += 3;&lt;br /&gt;        j += 4;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Retorna o código&lt;br /&gt;    return (const char *) b64;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A próxima função deve fazer o contrário, converter um código Base64 para uma &lt;em&gt;string&lt;/em&gt;. Como a &lt;em&gt;string&lt;/em&gt; resultante pode não ser bem formada &amp;ndash; pode não ser terminada em carácter nulo ou possuir caracteres nulos no meio &amp;ndash;, é preciso uma forma de informar seu tamanho, então ela receberá um ponteiro para um inteiro:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;const char *b64decode(const char *b64, int *length) {&lt;br /&gt;    // Inteiro com o tamanho do código&lt;br /&gt;    int b64length = strlen(b64);&lt;br /&gt;&lt;br /&gt;    // Se não for múltiplo de quatro, há algo errado&lt;br /&gt;    if (b64length % 4 != 0)&lt;br /&gt;        return NULL;&lt;br /&gt;&lt;br /&gt;    // Tamanho máximo da string decifrada&lt;br /&gt;    int prob = (b64length / 4) * 3 + 1;&lt;br /&gt;&lt;br /&gt;    // Contadores para percorrer as strings&lt;br /&gt;    int i=0, j=0;&lt;br /&gt;&lt;br /&gt;    // Alocando memória para o resultado&lt;br /&gt;    char *s = (char *) malloc(sizeof(char) * prob);&lt;br /&gt;&lt;br /&gt;    while (j &amp;lt; b64length) {&lt;br /&gt;        // Decifra um grupo de quatro elementos&lt;br /&gt;        // e conta o resultado&lt;br /&gt;        i += _decode(&lt;br /&gt;            (u_int8_t *) s + i,&lt;br /&gt;            (const u_int8_t *) b64 + j&lt;br /&gt;        );&lt;br /&gt;&lt;br /&gt;        // Segue para o próximo grupo&lt;br /&gt;        j += 4;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Se foi fornecido um inteiro para contagem, informa o tamanho&lt;br /&gt;    if (length != NULL)&lt;br /&gt;        *length = i;&lt;br /&gt;&lt;br /&gt;    // Retorna a string decifrada&lt;br /&gt;    return (const char *) s;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora precisamos das funções específica para as conversões.&lt;br /&gt;&lt;br /&gt;Primeiro para codificar:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;void _encode(u_int8_t *dest, const u_int8_t *src, int len) {&lt;br /&gt;    // Menor que 1, nada a fazer&lt;br /&gt;    if (len &amp;lt; 1)&lt;br /&gt;        return;&lt;br /&gt;&lt;br /&gt;    // Dados a serem retornados&lt;br /&gt;    int aux[] = { 0, 0, 0, 0 };&lt;br /&gt;&lt;br /&gt;    // Primeiro elemento: os 6 bits mais significativos do primeiro&lt;br /&gt;    // byte&lt;br /&gt;    aux[0] = src[0] &amp;gt;&amp;gt; 2;&lt;br /&gt;&lt;br /&gt;    // Segundo elemento: os 2 bits menos significativos do primeiro e&lt;br /&gt;    // os quatro bits mais significativos do segundo byte&lt;br /&gt;    aux[1] = (src[0] &amp;amp; 0x03) &amp;lt;&amp;lt; 4;&lt;br /&gt;&lt;br /&gt;    if (len &amp;gt; 1) {&lt;br /&gt;        // SE houver um segundo...&lt;br /&gt;        aux [1] |= (src[1] &amp;amp; 0xf0) &amp;gt;&amp;gt; 4;&lt;br /&gt;&lt;br /&gt;        // Terceiro elemento: os quatro bits menos significativos do&lt;br /&gt;        // segundo e os dois mais significativos do terceiro byte&lt;br /&gt;        aux [2] = (src[1] &amp;amp; 0x0f) &amp;lt;&amp;lt; 2;&lt;br /&gt;&lt;br /&gt;        if (len &amp;gt; 2) {&lt;br /&gt;            // Se houver um terceiro...&lt;br /&gt;            aux[2] |= src[2] &amp;gt;&amp;gt; 6;&lt;br /&gt;&lt;br /&gt;            // Quarto elemento: os seis bits menos significatos do&lt;br /&gt;            // terceiro byte&lt;br /&gt;            aux[3] = src[2] &amp;amp; 0x3f;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Codifica agora os valores numéricos para string&lt;br /&gt;    dest[0] = b64all[aux[0]];&lt;br /&gt;    dest[1] = b64all[aux[1]];&lt;br /&gt;    dest[2] = '=';&lt;br /&gt;    dest[3] = '=';&lt;br /&gt;    if (len &amp;gt; 1) {&lt;br /&gt;        dest[2] = b64all[aux[2]];&lt;br /&gt;        if (len &amp;gt; 2)&lt;br /&gt;            dest[3] = b64all[aux[3]];&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int _decode(u_int8_t *dest, const u_int8_t *src) {&lt;br /&gt;    // Representação numérica do código&lt;br /&gt;    int aux[] = { 0, 0, 0, 0 };&lt;br /&gt;&lt;br /&gt;    // Contador&lt;br /&gt;    int i, c = 1;&lt;br /&gt;&lt;br /&gt;    // Converte código para valores numéricos&lt;br /&gt;    for (i = 0; i &amp;lt; 4; ++i)&lt;br /&gt;        aux[i] = _getindex(src[i]);&lt;br /&gt;&lt;br /&gt;    // Primeiro byte: primeiro elemento seguido dos quatro bits mais&lt;br /&gt;    // significativos do segundo&lt;br /&gt;    dest[0] = (u_int8_t) (aux[0] &amp;lt;&amp;lt; 2) | ((aux[1] &amp;amp; 0x30) &amp;gt;&amp;gt; 4);&lt;br /&gt;&lt;br /&gt;    // Zera os bytes seguintes&lt;br /&gt;    dest[1] = '\0';&lt;br /&gt;    dest[2] = '\0';&lt;br /&gt;&lt;br /&gt;    if (aux[2] != -1) {&lt;br /&gt;        // Se houver um terceiro elemento...&lt;br /&gt;        ++c;&lt;br /&gt;&lt;br /&gt;        // Segundo byte: quatro bits menos significativos do segundo&lt;br /&gt;        // elemento seguidos pelos quatro bits mais significativos do&lt;br /&gt;        // terceiro&lt;br /&gt;        dest[1] = (u_int8_t) ((aux[1] &amp;amp; 0x0f) &amp;lt;&amp;lt; 4) | (aux[2] &amp;gt;&amp;gt; 2);&lt;br /&gt;&lt;br /&gt;        if (aux[3] != -1) {&lt;br /&gt;            // Se houver um quarto elemento...&lt;br /&gt;            ++c;&lt;br /&gt;&lt;br /&gt;            // Terceiro byte: dois bits menos significativos do&lt;br /&gt;            // terceiro elemento seguidos pelo quarto elemento&lt;br /&gt;            dest[2] = (u_int8_t)&lt;br /&gt;              ((aux[2] &amp;amp; 0x03) &amp;lt;&amp;lt; 6) |&lt;br /&gt;              aux[3];&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Retorna o tamanho da string&lt;br /&gt;    return c;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Cabeçalho&lt;/h3&gt;&lt;br /&gt;Por último criamos o cabeçalho &lt;code&gt;base64.h&lt;/code&gt;, tornando públicas as duas funções de codificação e decodificação:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#ifndef _BASE64_H&lt;br /&gt;#define _BASE64_H&lt;br /&gt;&lt;br /&gt;const char *b64decode(const char *, int *);&lt;br /&gt;const char *b64encode(const char *, int);&lt;br /&gt;&lt;br /&gt;#endif&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusão&lt;/h3&gt;&lt;br /&gt;Mesmo que ninguém vá implementar uma biblioteca de conversão Base64, espero que este artigo sirva para ajudar a entender melhor do que se trata Base64.&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;tt&gt;[update]&lt;/tt&gt;&lt;/center&gt;&lt;br /&gt;Se quiser acrescentar algum açucar sintático, coloque em &lt;code&gt;base64.c&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#ifdef C_PLUS_PLUS&lt;br /&gt;const char *b64decode(const char *b64, int &amp;length) {&lt;br /&gt;    return b64decode(b64, &amp;length);&lt;br /&gt;}&lt;br /&gt;#endif&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E mude o conteúdo de &lt;code&gt;base64.h&lt;/code&gt; para:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#ifndef _BASE64_H&lt;br /&gt;#define _BASE64_H&lt;br /&gt;&lt;br /&gt;#ifdef C_PLUS_PLUS&lt;br /&gt;extern "C" {&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;const char *b64decode(const char *, int *);&lt;br /&gt;const char *b64encode(const char *, int);&lt;br /&gt;&lt;br /&gt;#ifdef C_PLUS_PLUS&lt;br /&gt;}&lt;br /&gt;const char *b64decode(const char *, int &amp;);&lt;br /&gt;#else&lt;br /&gt;#define _b64decode(s, len) b64decode(s, &amp;len)&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;#endif&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;center&gt;&lt;tt&gt;[/update]&lt;/tt&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-1718094671209626306?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/1718094671209626306/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=1718094671209626306' title='8 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/1718094671209626306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/1718094671209626306'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2008/11/base64.html' title='Base64'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-7582239185123234603</id><published>2008-11-13T21:52:00.011-03:00</published><updated>2009-01-16T13:37:21.626-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='OO'/><title type='text'>Objective C</title><content type='html'>&lt;img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; width: 100px; height: 105px; border: none;" src="http://1.bp.blogspot.com/_rGfO7DAuOSE/SRT62RK9EZI/AAAAAAAAAKg/53tVzG0MiP8/s200/gnustep.jpg" alt="GNUstep" /&gt; Escrevi recentemente um &lt;a href="http://kodumaro.blogspot.com/2008/11/desenvolvendo-aplicacoes-gnustep.html"&gt;artigo&lt;/a&gt; com um exemplo bem simples de desenvolvimento de uma aplicação para ambiente &lt;a href="http://gnustep.org/"&gt;GNUstep&lt;/a&gt;, mas cometi a gafe de não dedicar algum tempo falando da linguagem de programação em questão, &lt;a href="http://pt.wikipedia.org/wiki/Objective-C"&gt;Objective C&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Objective C, ou Objective-C, ou ObjC, é uma linguagem de programação &lt;a href="http://pt.wikipedia.org/wiki/Reflexão_(programação)"&gt;reflectiva&lt;/a&gt; orientada a objetos criada nos idos da década de 1980 &amp;ndash; mais ou menos na mesma época que o &lt;a href="http://www.cplusplus.com/"&gt;C++&lt;/a&gt; &amp;ndash; pelos fundadores da &lt;a href="http://en.wikipedia.org/wiki/Stepstone"&gt;Stepstone&lt;/a&gt;, mais tarde adquirida pela &lt;a href="http://pt.wikipedia.org/wiki/NeXT"&gt;NeXT&lt;/a&gt;. É na verdade uma &lt;strong&gt;camada bem fina&lt;/strong&gt; sobre a linguagem C padrão.&lt;br /&gt;&lt;br /&gt;Isso significa que, se você sabe programar em C, conseguirá programar em ObjC sem muito esforço.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Diferenças para C&lt;/h3&gt;&lt;br /&gt;Sobre a linguagem C, ObjC adiciona os seguintes recursos:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;Orientação a objetos, adaptada de &lt;a href="http://smalltalk.org/"&gt;Smalltalk&lt;/a&gt;.&lt;/li&gt; &lt;li&gt;Tipo boleano &amp;ndash; &lt;code&gt;BOOL&lt;/code&gt;. Verdadeiro é &lt;code&gt;YES&lt;/code&gt; e falso é &lt;code&gt;NO&lt;/code&gt;.&lt;/li&gt; &lt;li&gt;Comentário de linha, iniciado por &lt;code&gt;//&lt;/code&gt; (na época C não suportava).&lt;/li&gt; &lt;li&gt;A diretiva de preprocessador &lt;code&gt;#import&lt;/code&gt;, que funciona como &lt;code&gt;#include&lt;/code&gt;, mas só inclui o cabeçalho &lt;strong&gt;se&lt;/strong&gt; ele não foi incluído ainda.&lt;/li&gt; &lt;li&gt;O tipo &lt;code&gt;id&lt;/code&gt;, similar a &lt;code&gt;void&amp;nbsp;*&lt;/code&gt; de C/C++.&lt;/li&gt; &lt;li&gt;A constante &lt;code&gt;nil&lt;/code&gt;, que é um objeto &lt;code&gt;id&lt;/code&gt; sem valor: &lt;code&gt;(id)0&lt;/code&gt;.&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;A maior parte dos comandos referentes a orientação a objetos começam com &lt;code&gt;@&lt;/code&gt;, como &lt;code&gt;@interface&lt;/code&gt;, &lt;code&gt;@implementation&lt;/code&gt;, &lt;code&gt;@end&lt;/code&gt;, &lt;code&gt;@private&lt;/code&gt;, &lt;code&gt;@protected&lt;/code&gt;, &lt;code&gt;@public&lt;/code&gt;, &lt;code&gt;@protocol&lt;/code&gt;, etc.&amp;hellip; Entre colchetes é avaliado o ambiente de mensagem, com uma sintaxe muito parecida com a de Smalltalk.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Criando uma classe&lt;/h3&gt;&lt;br /&gt;Como exemplo, vamos criar a classe &lt;code&gt;Point&lt;/code&gt;, com os atributos &lt;code&gt;x&lt;/code&gt; e &lt;code&gt;y&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Para tanto, primeiro criamos a interface no arquivo &lt;code&gt;Point.h&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#ifndef _POINT_H&lt;br /&gt;#define _POINT_H&lt;br /&gt;&lt;br /&gt;#import &amp;lt;Foundation/Foundation.h&amp;gt;&lt;br /&gt;&lt;br /&gt;@interface Point : NSObject&lt;br /&gt;{&lt;br /&gt;    int x;&lt;br /&gt;    int y;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;+ (id) newWithX: (int)valuex Y: (int)valuey;&lt;br /&gt;- (id) initWithX: (int)valuex Y: (int)valuey;&lt;br /&gt;- (int) diagonal;&lt;br /&gt;- (int) getX;&lt;br /&gt;- (int) getY;&lt;br /&gt;- (void) setX: (int)value;&lt;br /&gt;- (void) setY: (int)value;&lt;br /&gt;&lt;br /&gt;@end&lt;br /&gt;&lt;br /&gt;#endif&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As diretivas &lt;code&gt;#ifndef&lt;/code&gt;, &lt;code&gt;#define&lt;/code&gt; e &lt;code&gt;#endif&lt;/code&gt; já são velhas conhecidas dos programadores C/C++. O &lt;code&gt;#import&lt;/code&gt; já foi explicado, funciona parecido com &lt;code&gt;#include&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;O cabeçalho &lt;code&gt;Foundation/Foundation.h&lt;/code&gt; inclui a classe &lt;code&gt;NSObject&lt;/code&gt;, definida pela API &lt;a href="http://www.gnustep.org/resources/OpenStepSpec/OpenStepSpec.html"&gt;OpenStep&lt;/a&gt;, usada aqui como classe pai de nossa classe &lt;code&gt;Point&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;O comando &lt;code&gt;@interface&lt;/code&gt; inicia a descrição da interface e o comando &lt;code&gt;@end&lt;/code&gt; encerra. O pequeno escopo entre chaves define os atributos de instância, protegidos por padrão &amp;ndash; para defini-los como públicos a sintaxe &lt;strong&gt;seria&lt;/strong&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;{&lt;br /&gt;    @public&lt;br /&gt;        int x;&lt;br /&gt;        int y;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As linhas começadas por um sinal de menos (&lt;code&gt;-&lt;/code&gt;) indicam métodos de instância &amp;ndash; métodos de classe são iniciados por &lt;code&gt;+&lt;/code&gt;. Por exemplo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;- (id) initWithX: (int)valuex Y: (int)valuey;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Significa um método de instância que recebe dois atributos inteiros &amp;ndash; &lt;code&gt;valuex&lt;/code&gt; e &lt;code&gt;valuey&lt;/code&gt;, e retorna um &lt;code&gt;id&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Agora precisamos implementar a interface. Para isso vamos criar o arquivo &lt;code&gt;Point.m&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;math.h&amp;gt;&lt;br /&gt;#import "Point.h"&lt;br /&gt;&lt;br /&gt;@implementation Point&lt;br /&gt;&lt;br /&gt;+ (id) newWithX: (int)valuex Y: (int)valuey {&lt;br /&gt;    return [[Point alloc]&lt;br /&gt;        initWithX: valuex Y: valuey];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (id) initWithX: (int)valuex Y: (int)valuey {&lt;br /&gt;    if ((self = [super init])) {&lt;br /&gt;        x = valuex;&lt;br /&gt;        y = valuey;&lt;br /&gt;    }&lt;br /&gt;    return self;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (int) diagonal {&lt;br /&gt;    return (int) sqrt((double) ((x * x) + (y * y)));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (int) getX {&lt;br /&gt;    return x;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (int) getY {&lt;br /&gt;    return y;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (void) setX: (int)value {&lt;br /&gt;    x = value;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (void) setY: (int)value {&lt;br /&gt;    y = value;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O código é muito parecido com C, e até mesmo com C++, cabendo apenas alguns comentários:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;&lt;code&gt;self&lt;/code&gt; é uma palavra reservada que representa a instância, como &lt;code&gt;this&lt;/code&gt; de Java e C++.&lt;/li&gt; &lt;li&gt;&lt;code&gt;super&lt;/code&gt; referencia a classe pai, como em Java.&lt;/li&gt; &lt;li&gt;Repare no comando &lt;code&gt;[super&amp;nbsp;init]&lt;/code&gt;: aqui é passada uma mensagem para &lt;code&gt;super&lt;/code&gt; e o valor retornado é atribuído a &lt;code&gt;self&lt;/code&gt;.&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Para instanciar um objeto, a sintaxe é:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;id point = [Point newWithX: 4 Y: 5];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ou, com tipagem estática:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;Point *point = [Point newWithX: 4 Y: 5];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para obter o valor de &lt;code&gt;x&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;printf("x = %d&amp;#92;n", [point getX]);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E para mudar seu valor:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;[point setX: 2];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;OpenStep&lt;/h3&gt;&lt;br /&gt;OpenStep é a API aberta para desenvolvimento de aplicações para &lt;a href="http://pt.wikipedia.org/wiki/NEXTSTEP"&gt;NEXTSTEP&lt;/a&gt;, resultado de um trabalho colaborativo da NeXT com a &lt;a href="http://www.sun.com"&gt;SUN Microsystems&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Diversos sistemas e ambientes oferecem suporte a OpenStep, como &lt;a href="http://www.apple.com/macosx/"&gt;OS X&lt;/a&gt; e GNUstep.&lt;br /&gt;&lt;br /&gt;Diversos recursos interessantes são oferecidos nessa API, desde vantagens semelhantes à &lt;a href="http://www.cplusplus.com/reference/"&gt;STL&lt;/a&gt; de C++, até conjunto de &lt;em&gt;widgets&lt;/em&gt; para construção de janelas, &lt;em&gt;toolkit&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;Já vimos uma classe dessa API, &lt;code&gt;NSObject&lt;/code&gt;. Outra interessante é &lt;code&gt;NSString&lt;/code&gt;, cuja finalidade é a mesma de &lt;code&gt;std::string&lt;/code&gt; de C++ e &lt;code&gt;String&lt;/code&gt; de Java.&lt;br /&gt;&lt;br /&gt;A criação de uma &lt;code&gt;NSString&lt;/code&gt; é:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;id url = [NSString stringWithCString: "http://kodumaro.blogspot.com/"];&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Há ainda um apelido sintático:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;id url = @"http://kodumaro.blogspot.com/";&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Um forma legal de conhecer mais sobre OpenStep é ler os manuais de referência do &lt;a href="http://www.gnustep.org/resources/documentation/Developer/Base/Reference/"&gt;GNUstep&lt;/a&gt; (&lt;em&gt;toolkit&lt;/em&gt; &lt;a href="http://www.gnustep.org/resources/documentation/Developer/Gui/Reference/"&gt;aqui&lt;/a&gt;) e do &lt;a href="http://developer.apple.com/documentation/Cocoa/ObjectiveCLanguage-date.html"&gt;OS X&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-7582239185123234603?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/7582239185123234603/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=7582239185123234603' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/7582239185123234603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/7582239185123234603'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2008/11/objective-c.html' title='Objective C'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_rGfO7DAuOSE/SRT62RK9EZI/AAAAAAAAAKg/53tVzG0MiP8/s72-c/gnustep.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-4168562966807122189</id><published>2008-11-07T23:29:00.019-03:00</published><updated>2009-08-25T22:50:11.998-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='OO'/><title type='text'>Desenvolvendo aplicações GNUstep</title><content type='html'>&lt;img style="float: left; margin: 0 10px 10px 0; cursor: crosshair; width: 100px; height: 105px; border: none;" src="http://1.bp.blogspot.com/_rGfO7DAuOSE/SRT62RK9EZI/AAAAAAAAAKg/53tVzG0MiP8/s200/gnustep.jpg" alt="GNUstep" id="BLOGGER_PHOTO_ID_5266109674532180370" /&gt; Sempre fui fascinado pelo &lt;a href="http://pt.wikipedia.org/wiki/NEXTSTEP"&gt;NeXTSTEP&lt;/a&gt; e gostaria muito tivesse dado certo. Por mais que a &lt;a href="http://www.apple.com/"&gt;Apple&lt;/a&gt; negue, seu &lt;a href="http://pt.wikipedia.org/wiki/Mac_OS_X"&gt;Mac OS X&lt;/a&gt; não é muito mais do que uma versão nova de um NeXTSTEP portado para equipamentos &lt;a href="http://pt.wikipedia.org/wiki/Macintosh"&gt;MacIntosh&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Mas não só o OS X herdou os recursos do NeXTSTEP. No começo da década de 1990, em colaboração com a &lt;a href="http://www.sun.com/"&gt;SUN Microsystems&lt;/a&gt; a NeXT lançou o &lt;a href="http://pt.wikipedia.org/wiki/OpenStep"&gt;OpenStep&lt;/a&gt;, uma especificação aberta que define a &lt;a href="http://pt.wikipedia.org/wiki/API"&gt;API&lt;/a&gt; para o NeXTSTEP.&lt;br /&gt;&lt;br /&gt;Assim ambientes baseados em NeXTSTEP podem rodar em quaisquer sistemas operacionais e aplicações portáteis podem ser criadas.&lt;br /&gt;&lt;br /&gt;A &lt;a href="http://www.fsf.org/"&gt;Free Software Foundation&lt;/a&gt; lançou um projeto de implementação da API OpenStep para sistemas &lt;a href="http://www.gnu.org/"&gt;GNU&lt;/a&gt;, o &lt;a href="http://gnustep.org/"&gt;GNUstep&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Mais do que uma API de programação, GNUstep é todo um ambiente, desde a API até aplicações e ambiente operacional.&lt;br /&gt;&lt;br /&gt;Inicialmente o ambiente gráfico / &lt;a href="http://pt.wikipedia.org/wiki/Gerenciador_de_janela"&gt;geranciador de janelas&lt;/a&gt; era o &lt;a href="http://afterstep.org/"&gt;AfterStep&lt;/a&gt;. Certo dia, na lista de discussão para definir os rumos da versão 2 do AfterStep, um brasileiro chamado &lt;a href="http://pt.wikipedia.org/wiki/Alfredo_Kojima"&gt;Alfredo Kojima&lt;/a&gt; sugeriu a reescrita do código do zero.&lt;br /&gt;&lt;br /&gt;Enquanto o grupo continuava debadendo, Kojima decidiu iniciar o desenvolvimento da versão 2 do AfterStep, codinome WindowMaker, por conta própria e depois apresentou-o à comunidade. O &lt;a href="http://windowmaker.info/"&gt;Window Maker&lt;/a&gt; então substituiu o AfterStep como gerenciador de janelas do projeto GNUstep e o AfterStep continuou seu desenvolvimento a parte.&lt;br /&gt;&lt;br /&gt;Diversas versões do Window Maker foram lançadas, apesar de nunca ter chegado a uma versão 1.0, um eterno &lt;em&gt;beta&lt;/em&gt; &amp;ndash; atualmente se encontra na versão 0.92. Porém seu desenvolvimento esfriou gradativamente.&lt;br /&gt;&lt;br /&gt;Ano passado o projeto voltou a esquentar e promessas de novas versões estão no ar, o que me inspirou a escrever este artigo.&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;small&gt;Consulte o &lt;a href="http://wmaker.cyaneus.net/"&gt;&lt;em&gt;blog&lt;/em&gt; do Bardo&lt;/a&gt;.&lt;/small&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;GNUstep&lt;/h3&gt;&lt;br /&gt;Mas este artigo não é sobre Window Maker, e sim sobre GNUstep.&lt;br /&gt;&lt;br /&gt;Para desenvolver aplicações GNUstep, você precisa baixar seu &lt;em&gt;core&lt;/em&gt; antes. Acesse a &lt;a href="http://gnustep.org/resources/downloads.php"&gt;página de recursos&lt;/a&gt;, vá ao tópico &lt;em&gt;GNUstep Core&lt;/em&gt; e baixe as versões estáveis de cada pacote. Descompacte, compile e instale na ordem em que os pacotes aparecem na tabela (&lt;em&gt;startup&lt;/em&gt;, &lt;em&gt;make&lt;/em&gt;, &lt;em&gt;base&lt;/em&gt;, &lt;em&gt;gui&lt;/em&gt; e &lt;em&gt;backend&lt;/em&gt;). O &lt;em&gt;core&lt;/em&gt; do GNUstep deverá ser instalado em &lt;code&gt;/usr/GNUstep/&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Você precisa acrescentar &lt;code&gt;/usr/GNUstep/System/Tools&lt;/code&gt; a seu &lt;em&gt;path&lt;/em&gt; de executáveis, &lt;code&gt;/usr/GNUstep/System/Library/Libraries&lt;/code&gt; a sua lista de diretórios de bibliotecas &amp;ndash; em ambiente GNU/Linux, acrescente esse &lt;em&gt;path&lt;/em&gt; ao arquivo &lt;code&gt;/etc/ld.so.conf&lt;/code&gt; e execute &lt;code&gt;ldconfig&lt;/code&gt; &amp;ndash; e crie uma variável de ambiente &lt;code&gt;GNUSTEP_MAKEFILES&lt;/code&gt; com o valor &lt;code&gt;/usr/GNUstep/System/Library/Makefiles&lt;/code&gt; e outra &lt;code&gt;GNUSTEP_INSTALLATION_DOMAIN&lt;/code&gt; com o valor &lt;code&gt;SYSTEM&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Tendo o GNUstep instalado, podemos partir para as ferramentas de desenvolvimento, &lt;a href="http://www.gnustep.org/experience/Gorm.html"&gt;Gorm&lt;/a&gt; e &lt;a href="http://www.gnustep.org/experience/ProjectCenter.html"&gt;Project Center&lt;/a&gt;. Você também encontrará apontadores para as versões estáveis na mesma máquina de recursos, no tópico &lt;em&gt;GNUstep Development Tools&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Criando um projeto&lt;/h3&gt;&lt;br /&gt;Vamos criar nosso primeiro projeto GNUstep!&lt;br /&gt;&lt;br /&gt;Primeiro abrimos o Project Center com o comando:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;bash$&lt;/em&gt; &lt;strong&gt;openapp ProjectCenter&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Vá em &lt;code&gt;Project&lt;/code&gt; &amp;rarr; &lt;code&gt;New...&lt;/code&gt; (ou pressione &lt;code&gt;M-n&lt;/code&gt;), vai abrir uma janela de diálogo pedindo o nome do projeto. Selecione o tipo &lt;code&gt;Application&lt;/code&gt; e forneça o nome &lt;code&gt;Temperature&lt;/code&gt; e clique &lt;code&gt;Ok&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Por enquanto nossa brincadeira com Project Center acaba por aqui. Pode salvar &amp;ndash; &lt;code&gt;Project&lt;/code&gt; &amp;rarr; &lt;code&gt;Save&lt;/code&gt; ou &lt;code&gt;M-s&lt;/code&gt; &amp;ndash; e sair &amp;ndash; &lt;code&gt;Quit&lt;/code&gt; ou &lt;code&gt;M-q&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Criando uma aplicação&lt;/h3&gt;&lt;br /&gt;Agora vamos trabalhar no Gorm, execute:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;bash$&lt;/em&gt; &lt;strong&gt;openapp Gorm&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Um segredinho: nas versões anteriores você mandava abrir o &lt;code&gt;Temperature.gorm&lt;/code&gt; a partir do Project Center e ele já abria o Gorm para a aplicação atual. Na versão que experimentei &amp;ndash; Gorm 1.2.6 e Project Center 0.5.0 &amp;ndash; há um &lt;em&gt;bug&lt;/em&gt;. O truque é abrir o Gorm a parte e &lt;strong&gt;criar uma nova aplicação&lt;/strong&gt;.&lt;br /&gt;&lt;blockquote&gt;Se quiser testar se está funcionando &amp;ndash; em algumas lugares que testei funcionou &amp;ndash; para abrir o Gorm, na janela principal do Project Center clique em &lt;code&gt;Interfaces&lt;/code&gt; e duplo clique em &lt;code&gt;Temperature.gorm&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;No Gorm, crie uma janela e marque como &lt;code&gt;Visible at launch time&lt;/code&gt;.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;No Gorm então acesse &lt;code&gt;Document&lt;/code&gt; &amp;rarr; &lt;code&gt;New Application&lt;/code&gt;, depois vá em &lt;code&gt;Document&lt;/code&gt; &amp;rarr; &lt;code&gt;Save As...&lt;/code&gt;. Na janela de diálogo encontre seu projeto &lt;code&gt;Temperature&lt;/code&gt;, dentro dele &lt;code&gt;Resources&lt;/code&gt; e, dentro desse, salve como &lt;code&gt;Temperature.gorm&lt;/code&gt; &amp;ndash; confirme o &lt;code&gt;Replace&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Vão abrir três janelas: &lt;code&gt;Main Menu&lt;/code&gt;, &lt;code&gt;My Window&lt;/code&gt; e &lt;code&gt;Temperature.gorm&lt;/code&gt;. Se as janelas &lt;code&gt;Palettes&lt;/code&gt; e &lt;code&gt;Inspector&lt;/code&gt; não estiverem abertas, encontre-as no menu &lt;code&gt;Tools&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Selecione a janela &lt;code&gt;My Window&lt;/code&gt; &amp;ndash; ela representa a janela principal da aplicação &amp;ndash; e veja em &lt;code&gt;Inspector&lt;/code&gt; o campo &lt;code&gt;Title&lt;/code&gt; contendo &lt;code&gt;My Window&lt;/code&gt; &amp;ndash; se não estiver vendo, mude o seletor para &lt;code&gt;Attributes&lt;/code&gt;. Mude o título para &lt;code&gt;Temperature Converter&lt;/code&gt; &amp;ndash; repare que o título da janela &lt;code&gt;My Window&lt;/code&gt; também mudou.&lt;br /&gt;&lt;br /&gt;Repare que na janela &lt;code&gt;Palettes&lt;/code&gt; tem alguns &lt;em&gt;widgets&lt;/em&gt;. Para acrescentar um &lt;em&gt;widget&lt;/em&gt; à janela é só segurar e arrastar (&lt;em&gt;drag'n'drop&lt;/em&gt;). Vamos acrescentar três tipos de &lt;em&gt;widget&lt;/em&gt;: &lt;code&gt;Text&lt;/code&gt;, &lt;code&gt;System Bold&lt;/code&gt; e &lt;code&gt;Button&lt;/code&gt;. Adicione componentes até ficar mais ou menos com a cara deste corte:&lt;br /&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: crosshair; width: 300px; height: 104px; border: none;" src="http://3.bp.blogspot.com/_rGfO7DAuOSE/SRT6oI_4k9I/AAAAAAAAAKY/DJkNA1luv7o/s320/shot-1.jpg" alt="screenshot 1" id="BLOGGER_PHOTO_ID_5266109431820096466" /&gt;&lt;br /&gt;&lt;br /&gt;Para mudar o texto de um &lt;em&gt;widget&lt;/em&gt;, use o duplo clique. Você também pode mudar a borda no &lt;code&gt;Inspector&lt;/code&gt;. Altere os &lt;em&gt;widgets&lt;/em&gt; até ficarem mais ou menos assim:&lt;br /&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: crosshair; width: 248px; height: 121px; border: none;" src="http://4.bp.blogspot.com/_rGfO7DAuOSE/SRT6aGxRzBI/AAAAAAAAAKQ/CyH9pcV14jk/s320/shot-2.jpg" alt="screenshot 2" id="BLOGGER_PHOTO_ID_5266109190703795218" /&gt;&lt;br /&gt;&lt;br /&gt;Agora é hora de criar a classe para gerenciar essa janela! &lt;small&gt;Hora de &lt;em&gt;codar&lt;/em&gt;? Ainda não&amp;hellip;&lt;/small&gt;&lt;br /&gt;&lt;br /&gt;Na janela &lt;code&gt;Temperature.gorm&lt;/code&gt;, na barra principal clique em &lt;code&gt;Classes&lt;/code&gt; e selecione &lt;code&gt;NSObject&lt;/code&gt; &amp;ndash; futuca um pouco que você acha. No menu &lt;code&gt;Operations&lt;/code&gt; selecione &lt;code&gt;SubClass&lt;/code&gt;. Na lista da direita vai aparecer &lt;code&gt;NewClass&lt;/code&gt; e o &lt;code&gt;Inspector&lt;/code&gt; vai selecioná-lo &amp;ndash; veja a caixa &lt;code&gt;Class&lt;/code&gt; com &lt;code&gt;NewClass&lt;/code&gt;. Mude o nome da classe para &lt;code&gt;ConverterManager&lt;/code&gt;. Apenas confirme na janela &lt;code&gt;Modifying Class&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Podemos agora criar os atributos (&lt;em&gt;outlets&lt;/em&gt;) e métodos da classe (&lt;em&gt;actions&lt;/em&gt;).&lt;br /&gt;&lt;br /&gt;Vamos criar um atributo para cada caixa de texto que criamos &amp;ndash; incluside a de Kelvin.&lt;br /&gt;&lt;br /&gt;Na janela &lt;code&gt;Inspector&lt;/code&gt; há a aba &lt;code&gt;Outlets (0)&lt;/code&gt; com o botão &lt;code&gt;Add&lt;/code&gt;. Clique nesse botão e teremos &lt;code&gt;NewOutlet&lt;/code&gt; com um duplo clique você será capaz de mudar seu nome para &lt;code&gt;degreeC&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Crie mais dois atributos: &lt;code&gt;degreeF&lt;/code&gt; e &lt;code&gt;kelvin&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Para criar o primeiro método acesse a aba &lt;code&gt;Actions (0)&lt;/code&gt; e siga o mesmo procedimento anterior. Os métodos serão chamados &lt;code&gt;convertC2F:&lt;/code&gt; e &lt;code&gt;convertF2C:&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;E a classe já está pronta!&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Instanciando a classe&lt;/h3&gt;&lt;br /&gt;Mantendo a classe &lt;code&gt;ConverterManager&lt;/code&gt;, no menu principal do Gorm selecione &lt;code&gt;Classes&lt;/code&gt; &amp;rarr; &lt;code&gt;Instantiate&lt;/code&gt;. Na janela &lt;code&gt;Temperature.gorm&lt;/code&gt; aparecerá um objeto &lt;code&gt;ConverterManager&lt;/code&gt;: é agora que vem parte da mágica&amp;hellip;&lt;br /&gt;&lt;br /&gt;Precisamos inicialmente ligar o atributo &lt;code&gt;degreeC&lt;/code&gt; dessa instância à primeira caixa de texto da janela (ao lado do rótulo &lt;code&gt;&amp;deg;C&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;Segure a tecla &lt;code&gt;Ctrl&lt;/code&gt;, clique sobre a instância, segure e arraste, solte sobre a caixa de diálogo &amp;ndash; vai aparecer um &lt;code&gt;T&lt;/code&gt; na caixa &amp;ndash;, então, na janela &lt;code&gt;Inspector&lt;/code&gt; selecione &lt;code&gt;degreeC&lt;/code&gt; e clique no botão &lt;code&gt;Connect&lt;/code&gt;. Vai aparecer um &lt;code&gt;S&lt;/code&gt; sobre a instância e, na janela &lt;code&gt;Inspector&lt;/code&gt;, em &lt;code&gt;Connections&lt;/code&gt;, vai aparecer: &lt;code&gt;degreeC (TextField(0))&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Faça o mesmo para as outras caixas ligando cada caixa a um atributo.&lt;br /&gt;&lt;br /&gt;Agora precisamos fazer com que os botões acionem métodos da instância, para isso o procedimento é o inverso: segurando a tecla &lt;code&gt;Ctrl&lt;/code&gt; clique sobre o botão &lt;code&gt;Celsius to Fahrenheit&lt;/code&gt;, segure, arraste e solte sobre a instância de &lt;code&gt;ConverterManager&lt;/code&gt; na janela &lt;code&gt;Temperature.gorm&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Na janela &lt;code&gt;Inspector&lt;/code&gt; clique em &lt;code&gt;target&lt;/code&gt; &amp;rarr; &lt;code&gt;convertC2F:&lt;/code&gt; e então clique no botão &lt;code&gt;Connect&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Faça o mesmo para conectar o outro botão ao outro método. Agora todas as ações estão conectadas!&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Salvando tudo&lt;/h3&gt;&lt;br /&gt;Na janela &lt;code&gt;Temperature.gorm&lt;/code&gt;, selecione &lt;code&gt;Classes&lt;/code&gt; e encontre a classe &lt;code&gt;ConverterManager&lt;/code&gt;. Selecione-a, então, no menu principal do Gorm clique em &lt;code&gt;Classes&lt;/code&gt; &amp;rarr; &lt;code&gt;Create Class Files&lt;/code&gt;. Apenas confirme as duas janelas de diálogo. Isso criará os dois arquivos &lt;code&gt;ConverterManager.m&lt;/code&gt; e &lt;code&gt;ConverterManager.h&lt;/code&gt; dentro de &lt;code&gt;Resources&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Agora clique em &lt;code&gt;Document&lt;/code&gt; &amp;rarr; &lt;code&gt;Save All&lt;/code&gt; e &lt;code&gt;Quit&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;De volta ao Project Center&lt;/h3&gt;&lt;br /&gt;Volte ao Project Center e clique em &lt;code&gt;Project&lt;/code&gt; &amp;rarr; &lt;code&gt;Open...&lt;/code&gt; e abra o arquivo &lt;code&gt;PC.project&lt;/code&gt; do projeto &lt;code&gt;Temperature&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Na janela principal do projeto dê um duplo clique em &lt;code&gt;Classes&lt;/code&gt; e depois em &lt;code&gt;ConverterManager.m&lt;/code&gt;, isso adicionará o código ao projeto do Project Center.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Finalmente o código!&lt;/h3&gt;&lt;br /&gt;Precisamos finalmente editar o conteúdo dos métodos. Duplo clique sobre &lt;code&gt;ConverterManager.m&lt;/code&gt; na janela principal e vai abrir a janela do editor:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;/* All Rights reserved */&lt;br /&gt;&lt;br /&gt;#include &amp;lt;AppKit/AppKit.h&amp;gt;&lt;br /&gt;#include "ConverterManager.h"&lt;br /&gt;&lt;br /&gt;@implementation ConverterManager&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;- (void) convertC2F: (id)sender&lt;br /&gt;{&lt;br /&gt;  /* insert your code here */&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;- (void) convertF2C: (id)sender&lt;br /&gt;{&lt;br /&gt;  /* insert your code here */&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O código é &lt;a href="http://pt.wikipedia.org/wiki/Objective-C"&gt;Objective C&lt;/a&gt;, um variante orientado a objetos de C que lembra um pouco &lt;a href="http://smalltalk.org/"&gt;Smalltalk&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;O método &lt;code&gt;covertC2F&lt;/code&gt; deve obter o valor do atributo &lt;code&gt;degreeC&lt;/code&gt; &amp;ndash; que está ligado à caixa de diálogo com o valor em graus Celsius &amp;ndash;, calcular e ajustar os valores em Fahrenreit e Kelvin:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;- (void) convertC2F: (id)sender&lt;br /&gt;{&lt;br /&gt;  float celsius = [degreeC floatValue];&lt;br /&gt;  float fahrenreit = (9.0f * celsius / 5.0f) + 32.0f;&lt;br /&gt;&lt;br /&gt;  [degreeF setStringValue: [NSString stringWithFormat: @"%1.2f",&lt;br /&gt;    fahrenreit]];&lt;br /&gt;&lt;br /&gt;  [kelvin setStringValue: [NSString stringWithFormat: @"%1.2fK",&lt;br /&gt;    (celsius + 273.15f)]];&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O método &lt;code&gt;convertF2C&lt;/code&gt; deve fazer o contrário:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;- (void) convertF2C: (id)sender&lt;br /&gt;{&lt;br /&gt;  float fahrenreit = [degreeF floatValue];&lt;br /&gt;  float celsius = 5.0f * (fahrenreit - 32.0f) / 9.0f;&lt;br /&gt;&lt;br /&gt;  [degreeC setStringValue: [NSString stringWithFormat: @"%1.2f",&lt;br /&gt;    celsius]];&lt;br /&gt;&lt;br /&gt;  [kelvin setStringValue: [NSString stringWithFormat: @"%1.2fK",&lt;br /&gt;    (celsius + 273.15f)]];&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Salve agora (&lt;code&gt;M-s&lt;/code&gt;) e feche o editor. Clique no ícone com a chave de fenda para compilar:&lt;br /&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: crosshair; width: 44px; height: 43px; border: none;" src="http://4.bp.blogspot.com/_rGfO7DAuOSE/SRT6D8HyoII/AAAAAAAAAKI/gaevTgCX-7o/s320/shot-3.jpg" alt="Build" id="BLOGGER_PHOTO_ID_5266108809888309378" /&gt;&lt;br /&gt;&lt;br /&gt;Na janela de &lt;em&gt;build&lt;/em&gt; há outro ícone igual, clique nele para compilar. Se tudo correr bem você verá uma bela mensagem:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;=== Build succeeded! ===&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Se falhar, volte e veja o que está errado.&lt;br /&gt;&lt;br /&gt;Clique então no ícone do foguete para rodar:&lt;br /&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: crosshair;width: 43px; height: 43px; border: none;" src="http://1.bp.blogspot.com/_rGfO7DAuOSE/SRT5yacRN5I/AAAAAAAAAKA/ujrdNQJQzPE/s320/shot-4.jpg" alt="Launch" id="BLOGGER_PHOTO_ID_5266108508789618578" /&gt;&lt;br /&gt;&lt;br /&gt;Na janela &lt;code&gt;Launch&lt;/code&gt; clique no mesmo ícone e a janela irá abrir. Faça alguns testes para ver se funciona bem.&lt;br /&gt;&lt;br /&gt;Para sair clique com o botão direito e escolha &lt;code&gt;Quit&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Se tudo funcionar bem, seu programa está pronto! Salve tudo em &lt;code&gt;Project&lt;/code&gt; &amp;rarr; &lt;code&gt;Save&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Instalando a aplicação&lt;/h3&gt;&lt;br /&gt;Para instalar, abra um terminal:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;bash$&lt;/em&gt; &lt;strong&gt;cd Temperature/&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;bash$&lt;/em&gt; &lt;strong&gt;make&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;bash$&lt;/em&gt; &lt;strong&gt;sudo make install&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Assim sua aplicação estará instalada em &lt;code&gt;/usr/GNUstep/System/Applications/Temperature.app&lt;/code&gt; &amp;ndash; ou &lt;code&gt;/usr/GNUstep/Local/Applications/Temperature.app&lt;/code&gt;, se você se esqueceu de ajustar o conteúdo da variável de ambiente &lt;code&gt;GNUSTEP_INSTALLATION_DOMAIN&lt;/code&gt; &amp;ndash; e você executá-la com o comando:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;bash$&lt;/em&gt; &lt;strong&gt;openapp Temperature&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusão&lt;/h3&gt;&lt;br /&gt;Espero que com este artigo algumas pessoas se interessem pelo desenvolvimento de aplicações para ambiente GNUstep, que aliás roda sobre Mac OS X também &amp;ndash; em plataforma OS X, o &lt;a href="http://www.windowmaker.info/development.php?show=wings"&gt;WINGs&lt;/a&gt; (&lt;em&gt;toolkit&lt;/em&gt; de &lt;em&gt;widgets&lt;/em&gt; para Window Maker) e o GNUstep são abstrações do &lt;a href="http://pt.wikipedia.org/wiki/Cocoa"&gt;Cocoa&lt;/a&gt;, &lt;em&gt;toolkit&lt;/em&gt; de &lt;em&gt;widgets&lt;/em&gt; do OS X.&lt;br /&gt;&lt;br /&gt;A facilidade de desenvolvimento de aplicações gráficas para GNUstep com Project Center e Gorm é incrível, apesar de seu jeitão esquisito e do uso da tremendamente estranha linguagem de programação Objective C.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas&lt;br /&gt;&lt;br /&gt;&lt;small&gt;PS: Eu já estava morrendo de sono quando escrevi este artigo, portanto alguns erros de português podem ocorrer. Por favor me avisem!&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-4168562966807122189?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/4168562966807122189/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=4168562966807122189' title='4 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/4168562966807122189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/4168562966807122189'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2008/11/desenvolvendo-aplicacoes-gnustep.html' title='Desenvolvendo aplicações GNUstep'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_rGfO7DAuOSE/SRT62RK9EZI/AAAAAAAAAKg/53tVzG0MiP8/s72-c/gnustep.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-1735364715635785801</id><published>2008-10-16T21:21:00.015-03:00</published><updated>2008-10-23T22:59:50.821-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><category scheme='http://www.blogger.com/atom/ns#' term='Lua'/><title type='text'>Portando GDBM para Lua</title><content type='html'>&lt;img style="border: medium none ; margin: 0pt 10px 10px 0pt; float: left; cursor: crosshair;" src="http://photos1.blogger.com/x/blogger/6505/3295/200/690565/lua.jpg" alt="Lua" /&gt; Espero que este artigo seja interessante. =)&lt;br /&gt;&lt;br /&gt;Além de ser um linguagem de programação brasileira, desenvolvida na &lt;a href="http://www.puc-rio.br/"&gt;PUC Rio&lt;/a&gt;, &lt;a href="http://www.lua.org/portugues.html"&gt;Lua&lt;/a&gt; possui uma &lt;a href="http://www.lua.org/pil/24.html"&gt;poderosa API com C&lt;/a&gt;, na minha opinião, sua maior vantagem.&lt;br /&gt;&lt;br /&gt;A outra parte importante deste artigo é &lt;a href="http://www.gnu.org/software/gdbm/gdbm.html"&gt;GDBM&lt;/a&gt;, um conjunto de sub-rotinas de banco de dados baseado em &lt;em&gt;hash&lt;/em&gt;, uma alternativa livre ao Unix DBM.&lt;br /&gt;&lt;br /&gt;A ideia aqui é demonstrar um pouco dos recursos da biblioteca GDBM e como é simples estender a linguagem Lua.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;O objeto&lt;/h3&gt;&lt;br /&gt;Pessoalmente, quando crio extensões para Lua, gosto de criar primeiro uma classe que represente meu objeto principal, ou uma classe para cada tipo de objeto que será usado nos &lt;em&gt;scripts&lt;/em&gt;; depois crio um módulo que porta cada recurso para Lua.&lt;br /&gt;&lt;br /&gt;Neste caso vamos criar uma classe &lt;code&gt;GdbmObject&lt;/code&gt; que faça a interface com a base de dados, &lt;code&gt;GDBM_FILE&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;É claro que poderia ter usado direto &lt;code&gt;GDBM_FILE&lt;/code&gt;, aliás comecei fazendo assim, mas acabei voltando ao procedimento que me é natural.&lt;br /&gt;&lt;br /&gt;Quanto a objetos &lt;code&gt;datum&lt;/code&gt;, não vi necessidade de criar uma interface, já que &lt;code&gt;datum&lt;/code&gt; não passa de uma representação mais flexível de &lt;em&gt;string&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;O cabeçalho, &lt;code&gt;gdbmobj.h&lt;/code&gt;, começa então com as instruções de preprocessamento triviais e a inclusão do cabeçalho &lt;code&gt;gdbm.h&lt;/code&gt;, essencial para lidar com GDBM:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#ifndef _GDBMOBJ_H_&lt;br /&gt;#define _GDBMOBJ_H_&lt;br /&gt;&lt;br /&gt;#include &amp;lt;gdbm.h&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podemos então criar a classe e começar os métodos públicos pelo construtor e o destruidor.&lt;br /&gt;&lt;br /&gt;O Construtor precisa criar o &lt;code&gt;GDBM_FILE&lt;/code&gt;. Para tanto, temos a função &lt;code&gt;gdbm_open&lt;/code&gt;, que recebe cinco parâmetros:&lt;br /&gt;&lt;ol&gt; &lt;li&gt;o nome do arquivo&lt;/li&gt; &lt;li&gt;o tamanho de blocos para leitura e gravação em &lt;em&gt;bytes&lt;/em&gt; (mínimo 512)&lt;/li&gt; &lt;li&gt;o modo de leitura e gravação&lt;/li&gt; &lt;li&gt;as permissões do arquivo, para caso ele seja criado&lt;/li&gt; &lt;li&gt;uma função de &lt;em&gt;callback&lt;/em&gt; a ser chamada quando ocorrer um erro fatal&lt;/li&gt; &lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Assim, pelo menos alguns desses parâmetros precisam ser argumentos do construtor. Para simplificar, vamos reduzir: caso o &lt;em&gt;callback&lt;/em&gt; seja nulo, é usada uma função padrão. Vamos ficar com ela:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;class GdbmObject {&lt;br /&gt;    public:&lt;br /&gt;        GdbmObject(&lt;br /&gt;            const char *name,&lt;br /&gt;            int block=512,&lt;br /&gt;            int mode=GDBM_READER,&lt;br /&gt;            int perm=0644&lt;br /&gt;        );&lt;br /&gt;        ~GdbmObject();&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nosso construtor então recebe os elementos essencias para &lt;code&gt;gdbm_open&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Os outros métodos públicos importantes precisam representar as funções de &lt;code&gt;gdbm.h&lt;/code&gt; que queremos acessar, em ordem alfabética: &lt;code&gt;gdbm_close&lt;/code&gt;, &lt;code&gt;gdbm_delete&lt;/code&gt;, &lt;code&gt;gdbm_exists&lt;/code&gt;, &lt;code&gt;gdbm_fetch&lt;/code&gt;, &lt;code&gt;gdbm_firstkey&lt;/code&gt;, &lt;code&gt;gdbm_nextkey&lt;/code&gt;, &lt;code&gt;gdbm_reorganize&lt;/code&gt;, &lt;code&gt;gdbm_setopt&lt;/code&gt;, &lt;code&gt;gdbm_store&lt;/code&gt; e &lt;code&gt;gdbm_sync&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;        bool gclose(void);&lt;br /&gt;        bool gdelete(const char *);&lt;br /&gt;        bool gexists(const char *);&lt;br /&gt;        double gfetch_number(const char *);&lt;br /&gt;        const char *gfetch_string(const char *);&lt;br /&gt;        const char *gnext(const char *key=NULL);&lt;br /&gt;        bool greorganize(void);&lt;br /&gt;        bool gsetopt(int, int);&lt;br /&gt;        bool gstore(const char *, const char *);&lt;br /&gt;        bool gstore(const char *, double);&lt;br /&gt;        bool gsync(void);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora um método para verificar se a base está fechada um método para retornar a última mensagem de erro:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;        bool isclosed(void) const;&lt;br /&gt;        const char *last_error(void) const;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Entrando em território privado, precisamos de dois atributos: um &lt;em&gt;flag&lt;/em&gt; que indique se a base está fechada e o &lt;code&gt;GDBM_FILE&lt;/code&gt; em si:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    private:&lt;br /&gt;        bool closed;&lt;br /&gt;        GDBM_FILE fd;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Então um método privado para converter &lt;code&gt;datum&lt;/code&gt; em &lt;em&gt;string&lt;/em&gt; e outro para fazer o &lt;code&gt;gdbm_fetch&lt;/code&gt; comum a &lt;code&gt;gfetch_number&lt;/code&gt; e &lt;code&gt;gfetch_string&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;        static const char *get_string(datum);&lt;br /&gt;        datum gfetch(const char *);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;#endif /* _GDBMOBJ_H_ */&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Código dos métodos&lt;/h3&gt;&lt;br /&gt;A lógica em si vai no arquivo &lt;code&gt;gdbmobj.cc&lt;/code&gt;, que deve iniciar incluindo nosso cabeçalho e o cabeçalho &lt;code&gt;cstring&lt;/code&gt;, para que possamos usar &lt;code&gt;strlen&lt;/code&gt; nas conversões entre &lt;em&gt;strings&lt;/em&gt; e &lt;code&gt;datum&lt;/code&gt;.&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;cstring&amp;gt;&lt;br /&gt;#include "gdbmobj.h"&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O código do construtor é simples: basta pegar os argumentos e passá-lo como parâmetro para &lt;code&gt;gdbm_close&lt;/code&gt; &amp;ndash; não esqueça de ajudar &lt;code&gt;closed&lt;/code&gt; como &lt;code&gt;false&lt;/code&gt;!&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;GdbmObject::GdbmObject(&lt;br /&gt;    const char *name, int block, int mode, int perm&lt;br /&gt;): closed(false)&lt;br /&gt;{&lt;br /&gt;    this-&amp;gt;fd = gdbm_open(&lt;br /&gt;        const_cast&amp;lt;char *&amp;gt;(name),&lt;br /&gt;        block, mode, perm, NULL&lt;br /&gt;    );&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O destruidor deve apenas fechar a base, caso esqueçam de fazê-lo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;GdbmObject::~GdbmObject() {&lt;br /&gt;    this&amp;gt;gclose();&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Precisamos fazer o &lt;code&gt;gclose&lt;/code&gt;. Ele deve:&lt;br /&gt;&lt;ol&gt; &lt;li&gt;verificar se a base já não está fechada&lt;/li&gt; &lt;li&gt;fechar a base&lt;/li&gt; &lt;li&gt;verificar se não houve erro&lt;/li&gt; &lt;li&gt;marcar o objeto como fechado&lt;/li&gt; &lt;/ol&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;bool GdbmObject::gclose(void) {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return false;&lt;br /&gt;&lt;br /&gt;    gdbm_close(this-&amp;gt;fd);&lt;br /&gt;&lt;br /&gt;    if (gdbm_errno == GDBM_NO_ERROR) {&lt;br /&gt;        this-&amp;gt;closed = true;&lt;br /&gt;        return true;&lt;br /&gt;    } else&lt;br /&gt;        return false;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora o método &lt;code&gt;gdelete&lt;/code&gt;: primeiro verificar se já não está fechado &amp;ndash; todos os métodos precisam verificar isso &amp;ndash;, em seguida converter a chave &lt;em&gt;string&lt;/em&gt; em &lt;code&gt;datum&lt;/code&gt; &amp;ndash; para isso o cabeçalho &lt;code&gt;cstring&lt;/code&gt; &amp;ndash; e então fazer o que tem de ser feito:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;bool GdbmObject::gdelete(const char *key) {&lt;br /&gt;    if (this-&amp;gt;close)&lt;br /&gt;        return false;&lt;br /&gt;&lt;br /&gt;    datum dkey;&lt;br /&gt;    dkey.dptr = const_cast&amp;lt;char *&amp;gt;(key);&lt;br /&gt;    dkey.dsize = strlen(key);&lt;br /&gt;&lt;br /&gt;    gdbm_delete(this-&amp;gt;fd, dkey);&lt;br /&gt;&lt;br /&gt;    return gdbm_errno == GDBM_NO_ERROR;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O próximo método verifica se uma chave existe e funciona similar ao &lt;code&gt;gdelete&lt;/code&gt;, só o retorno é que tem um significado diferente:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;bool GdbmObject::gexists(const char *key) {&lt;br /&gt;    if (this-&amp;gt;close)&lt;br /&gt;        return false;&lt;br /&gt;&lt;br /&gt;    datum dkey;&lt;br /&gt;    dkey.dptr = const_cast&amp;lt;char *&amp;gt;(key);&lt;br /&gt;    dkey.dsize = strlen(key);&lt;br /&gt;&lt;br /&gt;    return static_cast&amp;lt;bool&amp;gt;(gdbm_exists(this-&amp;gt;fd, dkey));&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Os métodos &lt;code&gt;gfetch_number&lt;/code&gt; e &lt;code&gt;gfetch_string&lt;/code&gt; devem retornar um valor para uma chave, um retornando &lt;code&gt;double&lt;/code&gt; e outro &lt;em&gt;string&lt;/em&gt; (&lt;code&gt;const char *&lt;/code&gt;), ambos usando o método privado &lt;code&gt;gfetch&lt;/code&gt; para obter a chave em formato &lt;code&gt;datum&lt;/code&gt; antes:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;double GdbmObject::gfetch_number(const char *key) {&lt;br /&gt;    datum data = this-&amp;gt;gfetch(key);&lt;br /&gt;    double resp = -1.;&lt;br /&gt;&lt;br /&gt;    if (data.dsize == sizeof(double)) {&lt;br /&gt;        double *aux = reinterpret_cast&amp;lt;double *&amp;gt;(data.ptr);&lt;br /&gt;        resp = *aux;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    delete[] data.dptr;&lt;br /&gt;    return resp;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;const char *GdbmObject::gfetch_string(const char *key) {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return NULL;&lt;br /&gt;&lt;br /&gt;    datum data = this-&amp;gt;gfetch(key);&lt;br /&gt;    const char *aux = get_string(data);&lt;br /&gt;&lt;br /&gt;    delete[] data.dptr;&lt;br /&gt;    return aux;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O método &lt;code&gt;gnext&lt;/code&gt; é mais complexo, pois faz interface com &lt;code&gt;gdbm_firstkey&lt;/code&gt; (quando a chave for nula) e com &lt;code&gt;gdbm_nextkey&lt;/code&gt;.&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;const char *GdbmObject::gnext(const char *key) {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return NULL;&lt;br /&gt;&lt;br /&gt;    datum next;&lt;br /&gt;    next.dptr = NULL;&lt;br /&gt;    next.dsize = 0;&lt;br /&gt;&lt;br /&gt;    if (key == NULL)&lt;br /&gt;        next = gdbm_firstkey(this-&amp;gt;fd);&lt;br /&gt;&lt;br /&gt;    else {&lt;br /&gt;        datum current;&lt;br /&gt;        current.dptr = const_cast&amp;lt;char *&amp;gt;(key);&lt;br /&gt;        current.dsize = strlen(key);&lt;br /&gt;        next = gdbm_nextkey(this-&amp;gt;fd, current);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (next.dptr != NULL) {&lt;br /&gt;        const char *aux = get_string(next);&lt;br /&gt;&lt;br /&gt;        delete[] next.dptr;&lt;br /&gt;        return aux;&lt;br /&gt;    } else&lt;br /&gt;        return NULL;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O método &lt;code&gt;greorganize&lt;/code&gt; é similar a &lt;code&gt;gclose&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;bool GdbmObject::greorganize(void) {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return false;&lt;br /&gt;&lt;br /&gt;    gdbm_reorganize(this-&amp;gt;fd);&lt;br /&gt;    return gdbm_errno == GDBM_NO_ERROR;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O método &lt;code&gt;gsetopt&lt;/code&gt; precisa tornar transparente algumas peculiaridades de &lt;code&gt;gdbm_setopt&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;bool GdbmObject::gsetopt(int option, int value) {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return false;&lt;br /&gt;&lt;br /&gt;    gdbm_setopt(this-&amp;gt;fd, option, &amp;amp;value, sizeof(int));&lt;br /&gt;    return gdbm_errno == GDBM_NO_ERROR;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Temos dois métodos &lt;code&gt;gstore&lt;/code&gt;: um para armazenar números, outro para &lt;em&gt;strings&lt;/em&gt;, mas a lógica é a mesma: converter tudo pra &lt;code&gt;datum&lt;/code&gt; e usar &lt;code&gt;gdbm_store&lt;/code&gt; para armazenar. Vamos usar apenas o &lt;em&gt;flag&lt;/em&gt; &lt;code&gt;GDBM_REPLACE&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;bool GdbmObject::gstore(const char *key, double value) {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return false;&lt;br /&gt;&lt;br /&gt;    datum dkey, data;&lt;br /&gt;&lt;br /&gt;    dkey.dptr = const_cast&amp;lt;char *&amp;gt;(key);&lt;br /&gt;    dkey.dsize = strlen(key);&lt;br /&gt;    data.dptr = reinterpret_cast&amp;lt;char *&amp;gt;(&amp;amp;value);&lt;br /&gt;    data.dsize = sizeof(double);&lt;br /&gt;&lt;br /&gt;    gdbm_store(this-&amp;gt;fd, dkey, data, GDBM_REPLACE);&lt;br /&gt;    return gdbm_errno == GDBM_NO_ERROR;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool GdbmObject::gstore(const char *key, const char *value) {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return false;&lt;br /&gt;&lt;br /&gt;    datum dkey, data;&lt;br /&gt;&lt;br /&gt;    dkey.dptr = const_cast&amp;lt;char *&amp;gt;(key);&lt;br /&gt;    dkey.dsize = strlen(key);&lt;br /&gt;    data.dptr = const_cast&amp;lt;char *&amp;gt;(&amp;amp;value);&lt;br /&gt;    data.dsize = sizeof(double);&lt;br /&gt;&lt;br /&gt;    gdbm_store(this-&amp;gt;fd, dkey, data, GDBM_REPLACE);&lt;br /&gt;    return gdbm_errno == GDBM_NO_ERROR;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O método &lt;code&gt;gsync&lt;/code&gt; é quase idêntico a &lt;code&gt;greorganize&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;bool GdbmObject::gsync(void) {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return false;&lt;br /&gt;&lt;br /&gt;    gdbm_sync(this-&amp;gt;fd);&lt;br /&gt;    return gdbm_errno == GDBM_NO_ERROR;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora os métodos constantes, &lt;code&gt;isclosed&lt;/code&gt; (está fechado) e &lt;code&gt;last_error&lt;/code&gt; (último erro):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;bool GdbmObject::isclosed(void) const {&lt;br /&gt;    return this-&amp;gt;closed;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;const char *GdbmObject::last_error(void) const {&lt;br /&gt;    if (this-&amp;gt;closed)&lt;br /&gt;        return "database closed";&lt;br /&gt;&lt;br /&gt;    else&lt;br /&gt;        return const_cast&amp;lt;const char *&amp;gt;(gdbm_strerror(gdbm_errno));&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O método &lt;code&gt;gfetch&lt;/code&gt; faz a verdadeira interface com &lt;code&gt;gdbm_fetch&lt;/code&gt; para &lt;code&gt;gfetch_number&lt;/code&gt; e &lt;code&gt;gfetch_string&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;datum GdbmObject::gfetch(const char *key) {&lt;br /&gt;    datum data;&lt;br /&gt;    data.dptr = NULL;&lt;br /&gt;    data.dsize = 0;&lt;br /&gt;&lt;br /&gt;    if (!this-&amp;gt;closed) {&lt;br /&gt;        datum dkey;&lt;br /&gt;        dkey.dptr = const_cast&amp;lt;char *&amp;gt;(key);&lt;br /&gt;        dkey.dsize = strlen(key);&lt;br /&gt;&lt;br /&gt;        data = gdbm_fetch(this-&amp;gt;fd, dkey);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return data;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O método estático &lt;code&gt;get_string&lt;/code&gt; precisa converter &lt;code&gt;datum&lt;/code&gt; em &lt;em&gt;string&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;const char *GdbmObject::get_string(datum data) {&lt;br /&gt;    if (data.dptr == NULL)&lt;br /&gt;        return NULL;&lt;br /&gt;&lt;br /&gt;    char *aux = new char[data.dsize + 1];&lt;br /&gt;&lt;br /&gt;    for (int i=0; i&amp;lt;data.dsize; ++i)&lt;br /&gt;        aux[i] = data.dptr[i];&lt;br /&gt;    aux[data.dsize] = '\0';&lt;br /&gt;&lt;br /&gt;    return const_cast&amp;lt;const char *&amp;gt;(aux);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Aqui cabe um comentário para justificar o uso de &lt;code&gt;for&lt;/code&gt; em lugar de &lt;code&gt;strcpy&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;O ponteiro de &lt;code&gt;datum&lt;/code&gt; &lt;strong&gt;não é uma &lt;em&gt;string&lt;/em&gt;&lt;/strong&gt;, é um ponteiro para um grupo de &lt;em&gt;bytes&lt;/em&gt; &amp;ndash; mais ou menos similiar a uma &lt;em&gt;string&lt;/em&gt; de Pascal, que tem a vantagem de suportar carácter nulo como parte. Portanto pode não ter um carácter nulo ou ter caracteres nulos dentro do grupo de &lt;em&gt;bytes&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;Então a função &lt;code&gt;strcpy&lt;/code&gt; não é aplicável.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Que entre a Lua!&lt;/h3&gt;&lt;br /&gt;Vamos introduzir então a API com Lua, no arquivo &lt;code&gt;luagdbm.cc&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;O código precisa começar incluindo o cabeçalho de nossa classe e o cabeçalho de Lua para C++:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#include &amp;lt;lua.hpp&amp;gt;&lt;br /&gt;#include "gdbmobj.h"&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Algumas configurações importantes são dados de versão e nome do módulo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;#define VERSION "1.0"&lt;br /&gt;#define MODULE "gdbm"&lt;br /&gt;const char *modulename = MODULE;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Quando Lua carrega uma extensão, chama a função &lt;code&gt;luaopen_&lt;em&gt;nome_da_função&lt;/em&gt;&lt;/code&gt;, no caso &lt;code&gt;luaopen_gdbm&lt;/code&gt;, que deve receber um ponteiro para um estado Lua e deve responder com um inteiro representando a quantidade de elementos empilhados para o estado Lua ao final.&lt;br /&gt;&lt;br /&gt;Outra função interessante é &lt;code&gt;set_info&lt;/code&gt;, que serve para separar de &lt;code&gt;luaopen_*&lt;/code&gt; os dados de diretos, &lt;em&gt;strings&lt;/em&gt; e números.&lt;br /&gt;&lt;br /&gt;Também vamos criar uma função para empilhar um objeto &lt;code&gt;GdbmObject&lt;/code&gt; para o estado Lua:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;extern "C" int luaopen_gdbm(lua_State *);&lt;br /&gt;static void set_info(lua_State *);&lt;br /&gt;static void pushdb(lua_State *, GdbmObject *);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora vamos declarar uma função para cada método público de &lt;code&gt;GdbmObject&lt;/code&gt; &amp;ndash; é nossa interface com Lua:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;extern "C" {&lt;br /&gt;    static int luagdbm_close(lua_State *);&lt;br /&gt;    static int luagdbm_delete(lua_State *);&lt;br /&gt;    static int luagdbm_exists(lua_State *);&lt;br /&gt;    static int luagdbm_fetch_number(lua_State *);&lt;br /&gt;    static int luagdbm_fetch_string(lua_State *);&lt;br /&gt;    static int luagdbm_isclosed(lua_State *);&lt;br /&gt;    static int luagdbm_next(lua_State *);&lt;br /&gt;    static int luagdbm_open(lua_State *);&lt;br /&gt;    static int luagdbm_reorganize(lua_State *);&lt;br /&gt;    static int luagdbm_setopt(lua_State *);&lt;br /&gt;    static int luagdbm_store(lua_State *);&lt;br /&gt;    static int luagdbm_sync(lua_State *);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podemos implementar cada uma dessas funções.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Função de carregamento&lt;/h3&gt;&lt;br /&gt;Como já foi dito, a função de carrgamento é &lt;code&gt;luaopen_gdbm&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Ela deve criar um vetor de &lt;code&gt;luaL_reg&lt;/code&gt; relacionando cada função com as chaves no módulo em lua, terminando com nulo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luaopen_gdbm(lua_State *L) {&lt;br /&gt;    static const luaL_reg gdbm_funcs[] = {&lt;br /&gt;        {"close", luagdbm_close },&lt;br /&gt;        {"delete", luagdbm_delete },&lt;br /&gt;        {"exists", luagdbm_exists },&lt;br /&gt;        {"fetch_number", luagdbm_fetch_number },&lt;br /&gt;        {"fetch_string", luagdbm_fetch_string },&lt;br /&gt;        {"isclosed", luagdbm_isclosed },&lt;br /&gt;        {"next", luagdbm_next },&lt;br /&gt;        {"open", luagdbm_open },&lt;br /&gt;        {"reorganize", luagdbm_reorganize },&lt;br /&gt;        {"setopt", luagdbm_setopt },&lt;br /&gt;        {"store", luagdbm_store },&lt;br /&gt;        {"sync", luagdbm_sync },&lt;br /&gt;        { NULL, NULL }&lt;br /&gt;    };&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Então o módulo deve ser registrado com as funções. Para poder usar o módulo como metatabela para os objetos &lt;code&gt;GdbmObject&lt;/code&gt;, vamos também criar também a chave &lt;code&gt;__index&lt;/code&gt; apontando para o próprio módulo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    luaLregister(L, modulename, gdbm_funcs);&lt;br /&gt;    lua_pushliteral(L, "__index");&lt;br /&gt;    lua_getglobal(L, modulename);&lt;br /&gt;    lua_settable(L, -3);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora só falta chamar &lt;code&gt;set_info&lt;/code&gt; e informar que uma estrutura &amp;ndash; o módulo &amp;ndash; foi empilhada:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    set_info(L);&lt;br /&gt;    return 1;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Função para empilhar um objeto de banco de dados&lt;/h3&gt;&lt;br /&gt;É a função &lt;code&gt;pushdb&lt;/code&gt;, que recebe a pilha e um ponteiro para o objeto a ser empilhado.&lt;br /&gt;&lt;br /&gt;A função também deve associar ao objeto o próprio módulo como metatabela:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;void pushdb(lua_State *L, GdbmObject *db) {&lt;br /&gt;    lua_pushlightuserdata(L, db);&lt;br /&gt;    lua_getglobal(L, modulename);&lt;br /&gt;    lua_setmetatable(L, -2);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Vamos deixar &lt;code&gt;set_info&lt;/code&gt; para o final&amp;hellip;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Funções de interface com os métodos público&lt;/h3&gt;&lt;br /&gt;Praticamente todas funções devem:&lt;br /&gt;&lt;ol&gt; &lt;li&gt;carregar o ponteiro para objeto &lt;code&gt;GdbmObject&lt;/code&gt; do estado&lt;/li&gt; &lt;li&gt;verificar se ele ele não está nulo&lt;/li&gt; &lt;li&gt;fazer o que tem de ser feito&lt;/li&gt; &lt;li&gt;retornar o que foi solicitado ou uma mensagem de erro&lt;/li&gt; &lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Repare que todas as funções retornam a quantidade de elementos empilhados (&lt;code&gt;lua_push*&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;Assim como começamos pelo método &lt;code&gt;gclose&lt;/code&gt;, vamos começar pela função &lt;code&gt;luagdbm_close&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_close(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (db-&amp;gt;gclose()) {&lt;br /&gt;        delete db;&lt;br /&gt;        lua_pushboolean(L, 1);&lt;br /&gt;        return 1;&lt;br /&gt;&lt;br /&gt;    } else {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A função &lt;code&gt;luagdbm_delete&lt;/code&gt; ainda precisa recuperar a chave a ser deletada:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_delete(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const char *key = lua_tostring(L, 2);&lt;br /&gt;&lt;br /&gt;    if (db-&amp;gt;gdelete(key)) {&lt;br /&gt;        lua_pushboolean(L, 1);&lt;br /&gt;        return 1;&lt;br /&gt;&lt;br /&gt;    } else {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A função &lt;code&gt;luagdbm_exists&lt;/code&gt; é similar à anterior, só que mais simples:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_exists(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const char *key = lua_tostring(L, 2);&lt;br /&gt;&lt;br /&gt;    lua_pushboolean(L, static_cast&amp;lt;int&amp;gt;(db-&amp;gt;gexists(key)));&lt;br /&gt;    return 1;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As funções &lt;code&gt;luagdbm_fetch_number&lt;/code&gt; e &lt;code&gt;luagdbm_fetch_string&lt;/code&gt; são similares, só que, assim como os métodos &lt;code&gt;gfetch_number&lt;/code&gt; e &lt;code&gt;gfetch_string&lt;/code&gt;, retornam número e &lt;em&gt;string&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_fetch_number(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const char *key = lua_tostring(L, 2);&lt;br /&gt;    double value = db-&amp;gt;getch_number(key);&lt;br /&gt;&lt;br /&gt;    lua_pushnumber(L, value);&lt;br /&gt;&lt;br /&gt;    if (value == -1.) {&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;&lt;br /&gt;    } else&lt;br /&gt;        return 1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int luagdbm_fetch_string(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const char *key = lua_tostring(L, 2);&lt;br /&gt;    const char *value = db-&amp;gt;getch_string(key);&lt;br /&gt;&lt;br /&gt;    if (value == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;&lt;br /&gt;    } else {&lt;br /&gt;        lua_pushstring(L, value);&lt;br /&gt;        return 1;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A função &lt;code&gt;luagdbm_isclose&lt;/code&gt; é extremamente simples:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_isclosed(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    lua_pushboolean(L, static_cast&amp;lt;int&amp;gt;(db-&amp;gt;isclosed()));&lt;br /&gt;    return 1;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A função &lt;code&gt;luagdbm_next&lt;/code&gt; também não é complicada, apenas é preciso verificar se o parâmetro chave foi fornecido:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_next(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const char *key = NULL;&lt;br /&gt;    if (lua_type(L, 2) == LUA_TSTRING)&lt;br /&gt;        key = lua_tostring(L, 2);&lt;br /&gt;&lt;br /&gt;    const char *value = db-&amp;gt;gnext(key);&lt;br /&gt;&lt;br /&gt;    if (value == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;&lt;br /&gt;    } else {&lt;br /&gt;        lua_pushstring(L, value);&lt;br /&gt;        return 1;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Vamos deixar a função &lt;code&gt;luagdbm_open&lt;/code&gt;, devido a sua complexidade, então passamos direto para &lt;code&gt;luagdbm_reorganize&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_reorganize(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (db-&amp;gt;greorganize()) {&lt;br /&gt;        lua_pushboolean(L, 1);&lt;br /&gt;        return 1;&lt;br /&gt;&lt;br /&gt;    } else {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A função &lt;code&gt;luagdbm_setopt&lt;/code&gt; precisa obter dois inteiros, representando a opção e o valor a ser ajustado:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_setopt(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    int option = static_cast&amp;lt;int&amp;gt;(lua_tonumber(L, 2));&lt;br /&gt;    int value = static_cast&amp;lt;int&amp;gt;(lua_tonumber(L, 3));&lt;br /&gt;&lt;br /&gt;    if (db-&amp;gt;gsetopt(option, value)) {&lt;br /&gt;        lua_pushboolean(L, 1);&lt;br /&gt;        return 1;&lt;br /&gt;    } else {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Outra função um pouco mais complicada é &lt;code&gt;luagdbm_store&lt;/code&gt;, que deve armazenar um par chave-valor.&lt;br /&gt;&lt;br /&gt;A complexidade não está no armazenamento em si, mas na tomada de decisão do tipo da chave, número ou &lt;em&gt;string&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;Começamos como as outras funções:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_store(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const char *key = lua_tostring(L, 2);&lt;br /&gt;    bool resp = false;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Então precisamos decidir se o próximo parâmetro é número ou &lt;em&gt;string&lt;/em&gt; e usar uma variável do tipo conveniente:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    switch (lua_type(L, 3)) {&lt;br /&gt;        case LUA_TSTRING: {&lt;br /&gt;            const char *aux = lua_tostring(L, 3);&lt;br /&gt;            resp = db-&amp;gt;gstore(key, aux);&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        case LUA_TNUMBER: {&lt;br /&gt;            double aux = lua_tonumber(L, 3);&lt;br /&gt;            resp = db-&amp;gt;gstore(key, aux);&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        default:&lt;br /&gt;            lua_pushnil(L);&lt;br /&gt;            lua_pushstring(L, "not compatible data");&lt;br /&gt;            return 2;&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podemos então retornar convenientemente:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    if (resp) {&lt;br /&gt;        lua_pushboolean(L, 1);&lt;br /&gt;        return 1;&lt;br /&gt;&lt;br /&gt;    } else {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A última função é &lt;code&gt;luagdbm_sync&lt;/code&gt;, que não tem segredos:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_sync(lua_State *L) {&lt;br /&gt;    GdbmObject *db =&lt;br /&gt;        reinterpret_cast&amp;lt;GdbmObject *&amp;gt;(lua_touserdata(L, 1));&lt;br /&gt;&lt;br /&gt;    if (db == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "no database");&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (db-&amp;gt;gsync()) {&lt;br /&gt;        lua_pushboolean(L, 1);&lt;br /&gt;        return 1;&lt;br /&gt;&lt;br /&gt;    } else {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, db-&amp;gt;last_error());&lt;br /&gt;        return 2;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Abertura de uma base de dados&lt;/h3&gt;&lt;br /&gt;Finalmente chegamos à função &lt;code&gt;luagdbm_open&lt;/code&gt;!&lt;br /&gt;&lt;br /&gt;Ela é bem complexa, pois pode receber parâmetros diferentes.&lt;br /&gt;&lt;br /&gt;Se o parâmetro for &lt;em&gt;string&lt;/em&gt;, será considerada como o nome do arquivo de base de dados e para todas as demais configurações são usados os valores por defeito.&lt;br /&gt;&lt;br /&gt;Se for uma tabela:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;o valor para a chave &lt;code&gt;name&lt;/code&gt; representará o nome do arquivo;&lt;/li&gt; &lt;li&gt;o valor para a chave &lt;code&gt;block&lt;/code&gt; representará o tamanho do bloco;&lt;/li&gt; &lt;li&gt;o valor para a chave &lt;code&gt;mode&lt;/code&gt; representará o modo de leitura e/ou gravação;&lt;/li&gt; &lt;li&gt;o valor para a chave &lt;code&gt;permission&lt;/code&gt; representará as permissões para a criação do arquivo.&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;No entanto, mais de um parâmetros podem ser passados para o modo, como por exemplo &lt;code&gt;GDBM_WRCREAT&lt;/code&gt; e &lt;code&gt;GDBM_SYNC&lt;/code&gt;. Para esses casos, o valor para a chave &lt;code&gt;mode&lt;/code&gt; deve ser uma tabela indexada contendo os modos desejados &amp;ndash; e a função precisa estar preparada para processar isso!&lt;br /&gt;&lt;br /&gt;A primeira parte da função é carregar os valores por defeito:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;int luagdbm_open(lua_State *L) {&lt;br /&gt;    const char *name = NULL;&lt;br /&gt;    int block = 512;&lt;br /&gt;    int mode = GDBM_READER;&lt;br /&gt;    int perm = 0644;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Então precisamos verificar se o parâmetro é &lt;em&gt;string&lt;/em&gt; (nome do arquivo, tudo mais ajustado por defeito) ou tabela:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    switch(lua_type(L, 1)) {&lt;br /&gt;        case LUA_TSTRING:&lt;br /&gt;            name = lua_tostring(L, 1);&lt;br /&gt;            break;&lt;br /&gt;&lt;br /&gt;        case LUA_TTABLE: {&lt;br /&gt;            lua_getfield(L, 1, "name");&lt;br /&gt;&lt;br /&gt;            if (lua_type(L, -1) == LUA_TSTRING) {&lt;br /&gt;                name = lua_tostring(L, -1);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora precisamos pegar o valor de &lt;code&gt;block&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;                lua_getfield(L, 1, "block");&lt;br /&gt;                if (lua_type(L, -1) == LUA_TNUMBER)&lt;br /&gt;                    block = static_cast&amp;lt;int&amp;gt;(lua_tonumber(L, -1));&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ao trazermos o valor de &lt;code&gt;mode&lt;/code&gt; para cima, precisamos ainda verificar seu tipo:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;                lua_getfield(L, 1, "mode");&lt;br /&gt;                switch (lua_type(L, -1)) {&lt;br /&gt;                    case LUA_TNUMBER:&lt;br /&gt;                        mode = static_cast&amp;lt;int&amp;gt;(lua_tonumber(L, -1));&lt;br /&gt;                        break;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora, caso seja uma tabela, é preciso percorrer seus valores enquantos estes forem números:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;                    case LUA_TTABLE: {&lt;br /&gt;                        int i = 1;&lt;br /&gt;                        lua_rawgeti(L, -1, i);&lt;br /&gt;                        mode = 0;&lt;br /&gt;                        while (lua_type(L, -1) == LUA_TNUMBER) {&lt;br /&gt;                            mode |= static_cast&amp;lt;int&amp;gt;(&lt;br /&gt;                                lua_tonumber(L, -1)&lt;br /&gt;                            );&lt;br /&gt;                            lua_pop(L, 1);&lt;br /&gt;                            lua_rawgeti(L, -1, ++i);&lt;br /&gt;                        }&lt;br /&gt;&lt;br /&gt;                        mode = (mode == 0) ? GDBM_READER : mode;&lt;br /&gt;                        break;&lt;br /&gt;                    }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Repare que &lt;code&gt;lua_rawgeti(L,&amp;nbsp;-1,&amp;nbsp;i)&lt;/code&gt; empilha o &lt;code&gt;i&lt;/code&gt;-ésimo elemento da tabela no fim da pilha (-1) e &lt;code&gt;lua_pop(L,&amp;nbsp;1)&lt;/code&gt; desempilha para voltarmos à tabela.&lt;br /&gt;&lt;br /&gt;Agora, caso não seja nem número, nem tabela, ignora:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;                    default:&lt;br /&gt;                        break;&lt;br /&gt;                }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Obter as permissões é tão simples quanto obter o tamanho do bloco. Aproveitamos e já encerramos o &lt;code&gt;switch&lt;/code&gt; o parâmetro ignorando outros tipos:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;                lua_getfield(L, 1, "permission");&lt;br /&gt;                if (lua_type(L, -1) == LUA_TNUMBER)&lt;br /&gt;                    perm = static_cast&amp;lt;int&amp;gt;(lua_tonumber(L, -1));&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        default:&lt;br /&gt;            break;&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Repare bem em uma coisa: &lt;code&gt;lua_to*(L,&amp;nbsp;1)&lt;/code&gt; retorna o primeiro parâmetro passado à função, &lt;code&gt;lua_to*(L,&amp;nbsp;2)&lt;/code&gt; retorna o segundo parâmetro. &lt;code&gt;lua_to*(L,&amp;nbsp;-1)&lt;/code&gt; retorna o último elemento empilhado por &lt;code&gt;lua_push*&lt;/code&gt;, &lt;code&gt;lua_getglobal&lt;/code&gt;, &lt;code&gt;lua_getfield&lt;/code&gt;, &lt;code&gt;lua_rawget&lt;/code&gt;, &lt;code&gt;lua_rawgeti&lt;/code&gt; ou qualquer outra função da API que empilhe elementos.&lt;br /&gt;&lt;br /&gt;Agora é preciso verificar se, após todo esse trabalho, o nome do arquivo foi realmente ajustado:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    if (name == NULL) {&lt;br /&gt;        lua_pushnil(L);&lt;br /&gt;        lua_pushstring(L, "file not supplied");&lt;br /&gt;        return 2;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finalmente podemos abrir o arquivo de banco de dados e, se tudo correr bem, retorná-lo para o estado Lua &amp;ndash; caso contrário, retornar um erro:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;    } else {&lt;br /&gt;        GdbmObject *db = new GdbmObject(name, block, mode, perm);&lt;br /&gt;&lt;br /&gt;        if (gdbm_errno == GDBM_NO_ERROR) {&lt;br /&gt;            if (db == NULL) {&lt;br /&gt;                lua_pushnil(L);&lt;br /&gt;                lua_pushstring(L,&lt;br /&gt;                    "no error, but no database returned"&lt;br /&gt;                );&lt;br /&gt;                return 2;&lt;br /&gt;&lt;br /&gt;            } else {&lt;br /&gt;                pushdb(L, db);&lt;br /&gt;                return 1;&lt;br /&gt;            }&lt;br /&gt;        } else {&lt;br /&gt;            delete db;&lt;br /&gt;            lua_pushnil(L);&lt;br /&gt;            lua_pushstring(L, gdbm_strerror(gdbm_errno));&lt;br /&gt;            return 2;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Informações&lt;/h3&gt;&lt;br /&gt;A função &lt;code&gt;set_info&lt;/code&gt; é na verdade a mais chata: primeiro ajusta dados padrão sobre o módulo, depois carrega as constantes usadas pelo GDBM com nomes similares.&lt;br /&gt;&lt;br /&gt;É bastante extenso e se não quiser, não precisa ler agora. Está aqui apenas para quem quiser programá-lo.&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;void set_info(lua_State *L) {&lt;br /&gt;    lua_pushliteral(L, "_COPYRIGHT");&lt;br /&gt;    lua_pushliteral(L, "Copyright (C) 2008 Rodrigo Cacilhas");&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "_DESCRIPTION");&lt;br /&gt;    lua_pushliteral(L, "GDBM interface");&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "_NAME");&lt;br /&gt;    lua_pushliteral(L, MODULE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "_VERSION");&lt;br /&gt;    lua_pushliteral(L, VERSION);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;&lt;br /&gt;    lua_pushliteral(L, "READER");&lt;br /&gt;    lua_pushnumber(L, GDBM_READER);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "WRITER");&lt;br /&gt;    lua_pushnumber(L, GDBM_WRITER);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "WRCREAT");&lt;br /&gt;    lua_pushnumber(L, GDBM_WRCREAT);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "NEWDB");&lt;br /&gt;    lua_pushnumber(L, GDBM_NEWDB);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "FAST");&lt;br /&gt;    lua_pushnumber(L, GDBM_FAST);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "SYNC");&lt;br /&gt;    lua_pushnumber(L, GDBM_SYNC);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "NOLOCK");&lt;br /&gt;    lua_pushnumber(L, GDBM_NOLOCK);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;&lt;br /&gt;    lua_pushliteral(L, "INSERT");&lt;br /&gt;    lua_pushnumber(L, GDBM_INSERT);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "REPLACE");&lt;br /&gt;    lua_pushnumber(L, GDBM_REPLACE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    lua_pushliteral(L, "CACHESIZE");&lt;br /&gt;    lua_pushnumber(L, GDBM_CACHESIZE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "FASTMODE");&lt;br /&gt;    lua_pushnumber(L, GDBM_FASTMODE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "SYNCMODE");&lt;br /&gt;    lua_pushnumber(L, GDBM_SYNCMODE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "CENTFREE");&lt;br /&gt;    lua_pushnumber(L, GDBM_CENTFREE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "COALESCEBLKS");&lt;br /&gt;    lua_pushnumber(L, GDBM_COALESCEBLKS);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    lua_pushliteral(L, "NO_ERROR");&lt;br /&gt;    lua_pushnumber(L, GDBM_NO_ERROR);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "MALLOC_ERROR");&lt;br /&gt;    lua_pushnumber(L, GDBM_MALLOC_ERROR);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "BLOCK_SIZE_ERROR");&lt;br /&gt;    lua_pushnumber(L, GDBM_BLOCK_SIZE_ERROR);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "FILE_OPEN_ERROR");&lt;br /&gt;    lua_pushnumber(L, GDBM_FILE_OPEN_ERROR);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "FILE_WRITE_ERROR");&lt;br /&gt;    lua_pushnumber(L, GDBM_FILE_WRITE_ERROR);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "FILE_SEEK_ERROR");&lt;br /&gt;    lua_pushnumber(L, GDBM_FILE_SEEK_ERROR);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "FILE_READ_ERROR");&lt;br /&gt;    lua_pushnumber(L, GDBM_FILE_READ_ERROR);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "BAD_MAGIC_NUMBER");&lt;br /&gt;    lua_pushnumber(L, GDBM_BAD_MAGIC_NUMBER);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "EMPTY_DATABASE");&lt;br /&gt;    lua_pushnumber(L, GDBM_EMPTY_DATABASE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "CANT_BE_READER");&lt;br /&gt;    lua_pushnumber(L, GDBM_CANT_BE_READER);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "CANT_BE_WRITER");&lt;br /&gt;    lua_pushnumber(L, GDBM_CANT_BE_WRITER);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "READER_CANT_DELETE");&lt;br /&gt;    lua_pushnumber(L, GDBM_READER_CANT_DELETE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "READER_CANT_STORE");&lt;br /&gt;    lua_pushnumber(L, GDBM_READER_CANT_STORE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "READER_CANT_REORGANIZE");&lt;br /&gt;    lua_pushnumber(L, GDBM_READER_CANT_REORGANIZE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "UNKNOWN_UPDATE");&lt;br /&gt;    lua_pushnumber(L, GDBM_UNKNOWN_UPDATE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "ITEM_NOT_FOUND");&lt;br /&gt;    lua_pushnumber(L, GDBM_ITEM_NOT_FOUND);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "REORGANIZE_FAILED");&lt;br /&gt;    lua_pushnumber(L, GDBM_REORGANIZE_FAILED);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "CANNOT_REPLACE");&lt;br /&gt;    lua_pushnumber(L, GDBM_CANNOT_REPLACE);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "ILLEGAL_DATA");&lt;br /&gt;    lua_pushnumber(L, GDBM_ILLEGAL_DATA);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "OPT_ALREADY_SET");&lt;br /&gt;    lua_pushnumber(L, GDBM_OPT_ALREADY_SET);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;    lua_pushliteral(L, "OPT_ILLEGAL");&lt;br /&gt;    lua_pushnumber(L, GDBM_OPT_ILLEGAL);&lt;br /&gt;    lua_settable(L, -3);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Compilando&lt;/h3&gt;&lt;br /&gt;Uma forma legal de compilar é através de um arquivo &lt;code&gt;Makefile&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Esse arquivo começa com um comentário informando data e seu criador, e logo em seguida os recursos usados: compilador (&lt;code&gt;CC&lt;/code&gt;), &lt;em&gt;link&lt;/em&gt;-editor (&lt;code&gt;LD&lt;/code&gt;), &lt;em&gt;flags&lt;/em&gt; de compilação (&lt;code&gt;CFLAGS&lt;/code&gt;) e bibliotecas envolvidas (&lt;code&gt;LIBS&lt;/code&gt;), no caso:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;# $Id: luagdbm,v 1.0 2008/10/16 23:25:31 cacilhas Exp $&lt;br /&gt;&lt;br /&gt;CC ?= c++&lt;br /&gt;LD ?= c++&lt;br /&gt;RM ?= rm -f&lt;br /&gt;&lt;br /&gt;CFLAGS ?= &lt;br /&gt;LIBS ?= -lm -llua -lgdbm -lstdc++&lt;br /&gt;&lt;br /&gt;# **********************************************************************&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Então os procedimentos de compilação.&lt;br /&gt;&lt;br /&gt;O procedimento para compilar os arquivos fontes (&lt;code&gt;*.cc&lt;/code&gt;) em objetos (&lt;code&gt;*.o&lt;/code&gt;) é:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;.cc.o:&lt;br /&gt;    $(CC) -c $&amp;lt; $(CFLAGS) -o $@&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finalmente fazemos a &lt;em&gt;link&lt;/em&gt;-edição de tudo na biblioteca compartilhada &lt;code&gt;gdbm.so&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;gdbm.so: gdbmobj.o luagdbm.o&lt;br /&gt;    $(LD) -shared $? ($LIBS) -o $@&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agora precisamos informar ao &lt;em&gt;make&lt;/em&gt; o que fazer por defeito:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;all: gdbm.so&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E como limpar a bagunça:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;clean:&lt;br /&gt;    $(RM) luagdbm.o&lt;br /&gt;    $(RM) gdbmobj.o&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Feito isso já podemos compilar:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;bash$&lt;/em&gt; make&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Se tudo correu bem, a biblioteca &lt;code&gt;gdbm.so&lt;/code&gt; terá sido gerada, se não, verifique os erros e volte corrigindo-os. Caso encontre algum erro neste artigo, por favor informe para que eu possa corrigi-lo!&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Fazendo funcionar&lt;/h3&gt;&lt;br /&gt;Agora mova a biblioteca para um diretório onde Lua possa encontrá-la. Aqui para mim é &lt;code&gt;/usr/lib/lua/5.1/&lt;/code&gt;, mas aí para você pode ser qualquer coisa. O conteúdo da variável de ambiente &lt;code&gt;LUA_CPATH&lt;/code&gt; pode dar uma dica.&lt;br /&gt;&lt;br /&gt;Na ausência dessa variável, entrando no interpretador Lua, a chave &lt;code&gt;package.cpath&lt;/code&gt; informa o local correto.&lt;br /&gt;&lt;br /&gt;Feito isso, podemos iniciar um interpretador Lua e fazer testes:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;bash$&lt;/em&gt; lua&lt;br /&gt;&lt;em&gt;Lua 5.1.3  Copyright (C) 1994-2008 Lua.org, PUC-Rio&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; require "gdbm"&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; db = assert(gdbm.open { name = "dbtest.db", mode = gdbm.WRCREAT })&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; db:store("first", "a")&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; db:store("second", "b")&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; db:store("thirt", "c")&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; db:close()&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Saindo do interpretador, você poderá ver o arquivo &lt;code&gt;dbtest.db&lt;/code&gt; criado. Vamos reler seu conteúdo:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; db = assert(gdbm.open "dbtest.db")&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; k = db:next()&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; while k do print(k, db:fetch_string(k)) k = db:next(k) end&lt;br /&gt;&lt;em&gt;first   a&lt;/em&gt;&lt;br /&gt;&lt;em&gt;second  b&lt;/em&gt;&lt;br /&gt;&lt;em&gt;thirt   c&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&amp;gt;&lt;/em&gt; db:close()&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A ordem de &lt;code&gt;gdbm_next&lt;/code&gt; não é necessariamente a ordem de registro.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusão&lt;/h3&gt;&lt;br /&gt;Acho que este artigo está cheio de informações e é bastante longo, mas se você conseguiu lê-lo até aqui, significa que consegui fazê-lo útil.&lt;br /&gt;&lt;br /&gt;Para saber mais, leia a &lt;em&gt;manpage&lt;/em&gt; de &lt;code&gt;gdbm&lt;/code&gt; e o &lt;a href="http://www.lua.org/pil/"&gt;PiL&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;tt&gt;[update 2008-10-23]&lt;/tt&gt;Valeu pela divulgação no &lt;a href="http://br-linux.org/2008/kodumaro-portando-o-gdbm-para-lua/"&gt;BR-Linux.org&lt;/a&gt;, Augusto!&lt;tt&gt;[/update]&lt;/tt&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-1735364715635785801?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/1735364715635785801/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=1735364715635785801' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/1735364715635785801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/1735364715635785801'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2008/10/portando-gdbm-para-lua.html' title='Portando GDBM para Lua'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1387996720436450649.post-6765803184619517544</id><published>2008-10-15T21:08:00.002-03:00</published><updated>2008-10-15T21:15:04.848-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tcl'/><category scheme='http://www.blogger.com/atom/ns#' term='Conceitual'/><title type='text'>Tcl/Tk</title><content type='html'>&lt;img style="border: none; margin: 0pt 10px 10px 0pt; float: left;" src="http://photos1.blogger.com/blogger/6505/3295/200/tcl.jpg" alt="tcl.jpg" /&gt; Uma linguagem de &lt;em&gt;script&lt;/em&gt; muito subestimada é &lt;a href="http://wiki.tcl.tk/"&gt;Tcl/Tk&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tcl significa &lt;em&gt;Tool Command Language&lt;/em&gt; e foi criada por &lt;a href="http://pt.wikipedia.org/wiki/John_Ousterhout"&gt;John Ousterhout&lt;/a&gt; para ser uma extensão de C, uma linguagem de agregação de componentes, mais ou menos como o &lt;a href="http://pt.wikipedia.org/wiki/Shell_script"&gt;Shell Script&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tk é uma extensão gráfica para Tcl escrita em C. É um acrónimo para &lt;em&gt;toolkit&lt;/em&gt;, nome comumente usado para &lt;em&gt;frameworks&lt;/em&gt; gráficos. Em cada plataforma operacional, Tk oferece uma interface homogénia com o sistema de janelas. Outras linguagens também pode acessar a biblioteca Tk &amp;ndash; como por exemplo &lt;a href="http://wiki.python.org/moin/TkInter"&gt;Tkinter&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tcl e Tk são de código aberto.&lt;br /&gt;&lt;br /&gt;Vamos a alguns exemplos:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;em&gt;bash$&lt;/em&gt; tclsh&lt;br /&gt;&lt;em&gt;%&lt;/em&gt; puts stdout {Olá Mundo!}&lt;br /&gt;&lt;em&gt;Olá Mundo!&lt;/em&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Uma característica fortíssima de Tcl/Tk é que &lt;strong&gt;tudo são &lt;em&gt;strings&lt;/em&gt;&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Cada &lt;em&gt;token&lt;/em&gt; é uma &lt;em&gt;string&lt;/em&gt; e &lt;em&gt;strings&lt;/em&gt; não precisam de delimitadores, mas aspas (&lt;code&gt;"&lt;/code&gt;) e chaves (&lt;code&gt;{&lt;/code&gt; e &lt;code&gt;}&lt;/code&gt;) podem ser usados como.&lt;br /&gt;&lt;br /&gt;No exemplo acima, &lt;code&gt;puts&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt; e &lt;code&gt;{Olá&amp;nbsp;Mundo!}&lt;/code&gt; são &lt;em&gt;strings&lt;/em&gt;. A primeira &lt;em&gt;string&lt;/em&gt; da linha referencia o comando a ser executado, no caso &lt;code&gt;puts&lt;/code&gt; «coloca» uma &lt;em&gt;string&lt;/em&gt; em um fluxo (&lt;em&gt;stream&lt;/em&gt;).&lt;br /&gt;&lt;br /&gt;A segunda &lt;em&gt;string&lt;/em&gt; (&lt;code&gt;stdout&lt;/code&gt;) indica qual o fluxo de saída, no caso a saída padrão.&lt;br /&gt;&lt;br /&gt;A terceira &lt;em&gt;string&lt;/em&gt; é aquela que será direcionada para a saída selecionada. No caso exibe &lt;code&gt;Olá Mundo!&lt;/code&gt; na saída padrão.&lt;br /&gt;&lt;br /&gt;Vamos a um exemplo um pouco mais complicado:&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;puts -nonewline stdout {Informe um número: }&lt;br /&gt;gets stdin num&lt;br /&gt;set dob [expr [set num] * 2]&lt;br /&gt;puts stdout "O dobro é [set dob]"&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como já vimos, &lt;code&gt;puts&lt;/code&gt; exibe uma &lt;em&gt;string&lt;/em&gt; em uma saída, no caso novamente na saída padrão (&lt;code&gt;stdout&lt;/code&gt;). A &lt;em&gt;string&lt;/em&gt; &lt;code&gt;-nonewline&lt;/code&gt; é um parâmetro que indica a &lt;code&gt;puts&lt;/code&gt; para não inserir mudança de linha ao final.&lt;br /&gt;&lt;br /&gt;O comando &lt;code&gt;gets&lt;/code&gt; recebe uma &lt;em&gt;string&lt;/em&gt; de uma entrada &amp;ndash; no caso &lt;code&gt;stdin&lt;/code&gt;, entrada padrão: o teclado &amp;ndash; e a atribui a uma variável referenciada pela última &lt;em&gt;string&lt;/em&gt;, &lt;code&gt;num&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;O comando &lt;code&gt;set&lt;/code&gt; retorna o conteúdo de uma variável, se receber uma terceira &lt;em&gt;string&lt;/em&gt;, atribui esta à variável e retorna.&lt;br /&gt;&lt;br /&gt;Os colchetes executam o comando interno e tudo é substituído pela &lt;em&gt;string&lt;/em&gt; retornada.&lt;br /&gt;&lt;br /&gt;O comando &lt;code&gt;expr&lt;/code&gt; trata todas as &lt;em&gt;strings&lt;/em&gt; como uma expressão matemática, retornando o resultado.&lt;br /&gt;&lt;br /&gt;Assim, &lt;code&gt;[set&amp;nbsp;num]&lt;/code&gt; retorna o valor da variável &lt;code&gt;num&lt;/code&gt;, o &lt;code&gt;expr&lt;/code&gt; pega esse valor de &lt;code&gt;num&lt;/code&gt;, tratado como um número, e múltiplica por dois (2), retornando.&lt;br /&gt;&lt;br /&gt;Daí os colchetes substituem novamente toda a expressão pelo valor retornado, ou seja, uma &lt;em&gt;string&lt;/em&gt; representando o dobro do valor de &lt;code&gt;num&lt;/code&gt;, então o &lt;code&gt;set&lt;/code&gt; mais externo atribui essa valor à variável &lt;code&gt;dob&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;No final o último comando exibe na saída padrão a &lt;em&gt;string&lt;/em&gt;, substituindo o que estiver entre colchetes. Como &lt;code&gt;set&amp;nbsp;dob&lt;/code&gt; retorna o valor de &lt;code&gt;dob&lt;/code&gt;, acho que é óbvio o que é exibido.&lt;br /&gt;&lt;br /&gt;Só que Tcl/Tk suporta um «apelido» para &lt;code&gt;set&lt;/code&gt;, que é o cifrão (&lt;code&gt;$&lt;/code&gt;), como em Shell e &lt;a href="http://perl.com/"&gt;Perl&lt;/a&gt; (não como em PHP):&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;puts -nonewline stdout {Informe um número: }&lt;br /&gt;gets stdin num&lt;br /&gt;set dob [expr $num * 2]&lt;br /&gt;puts stdout "O dobro é $dob"&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Isso deixa o código bem mais limpo. =)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Outras extensões&lt;/h3&gt;&lt;br /&gt;Há ainda outras linguagens baseadas em Tcl/Tk que valem a pena serem citadas.&lt;br /&gt;&lt;br /&gt;A primeira é &lt;a href="http://incrtcl.sourceforge.net/itcl/"&gt;&lt;code&gt;[incr Tcl]&lt;/code&gt;&lt;/a&gt;, uma variação orientada a objetos.&lt;br /&gt;&lt;br /&gt;Outra é &lt;a href="http://sourceforge.net/projects/tclx"&gt;TclX&lt;/a&gt; (Tcl estendido), que, além de suportar todas os recursos de Tcl/Tk ainda suporta outros similares ao &lt;a href="http://pt.wikipedia.org/wiki/Bash"&gt;bash&lt;/a&gt;, como &lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;loop&lt;/code&gt; e &lt;code&gt;&amp;amp;&lt;/code&gt; (para execução paralela).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Finalizando&lt;/h3&gt;&lt;br /&gt;Este artigo é apenas um esboço. Outro mais completo pode ser encontrado nas &lt;a href="http://montegasppa.blogspot.com/2006/10/tcltk.html"&gt;Reflexões de Monte Gasppa e Giulia C.&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[]'s&lt;br /&gt;Cacilhas, La Batalema&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1387996720436450649-6765803184619517544?l=kodumaro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kodumaro.blogspot.com/feeds/6765803184619517544/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1387996720436450649&amp;postID=6765803184619517544' title='2 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/6765803184619517544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1387996720436450649/posts/default/6765803184619517544'/><link rel='alternate' type='text/html' href='http://kodumaro.blogspot.com/2008/10/tcltk.html' title='Tcl/Tk'/><author><name>La Batalema</name><uri>http://www.blogger.com/profile/14265747724618147106</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10953762007827215556'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry></feed>