Páginas

Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Thursday, September 15, 2011

Perl, Ruby, Python & Racket: time matters

Estava aqui pensando em duas coisas:

  1. Qual o comportamento de diversas linguagens de programação quando fazemos um "import" ou "require", e o que acontece se um mesmo arquivo for requirido várias vezes na árvore de dependências.
  2. Qual o tempo que leva para executar um script mínimo.
A motivação vem da diferença que dá usar #lang racket x #lang racket/base em Racket. Quando usamos a linguagem completa, temos todas as baterias em nossas mãos, e como penalização carregamos um monte de código pra memória sem que este seja efetivamente necessário. A segunda opção é mais leve, tem apenas definido elementos mais centrais da linguagem, ideal para usar quando estamos criando nossas bibliotecas.

Há uns anos atrás já havia feito experimentos similares (provavelmente não documentados) com Python. Agora fiz pequenos scripts em Python, Racket, Ruby e Perl para comparar. Atenção não leve em consideração os números deste post como "benchmarks" ou classificadores/qualificadores de uma ou outra linguagem.

O procedimento experimental

Para reproduzir este experimento, crie 4 diretórios:
mkdir t{python,ruby,racket,perl}
(Não entendeu a linha acima? Veja meu post sobre o uso de chaves no Bash)

Em cada um, crie 3 arquivos, "a", "b" e "c", com a extensão da respectiva linguagem.
O resultado final fica assim:

./tperl
├── a.pl
├── b.pl
└── c.pl
./tracket
├── a.rkt
├── b.rkt
└── c.rkt
./truby
├── a.rb
├── b.rb
└── c.rb
./tpython
├── a.py
├── b.py
└── c.py

Cada arquivo contém:
tpython/a.py
::::::::::::::
print "a"

tpython/b.py
::::::::::::::
import a
print "b"

tpython/c.py
::::::::::::::
import a, b
print "c"

Para as outras linguagens é similar, veja:

c.pl (Perl)

require "a.pl";
require "b.pl";
print "c\n";
c.rkt (Racket)
#lang racket/base
(require "a.rkt" "b.rkt")
(displayln "c")
c.rb (Ruby)
require 'a.rb'
require 'b.rb'
puts 'c'

Resultado 1

Todas as 4 linguagens parecem ser consistentes em:
  1. executar todo o código do corpo de um arquivo importado (incluindo efeitos-colaterais)
  2. não re-executar código já importado anteriormente (mesmo que por dependência indireta)
Ou seja, o resultado visual da execução de todos os exemplos é:

a
b
c

Resultado 2

Entretanto, o tempo de execução é bem diferente. Usando o time, os melhores resultados encontrados após muitas execuções num Core2Duo 2.2GHz com Ubuntu 10.10 64bits:

time perl c.pl
real 0m0.007s
user 0m0.000s
sys 0m0.000s

time ruby c.rb
real 0m0.010s
user 0m0.000s
sys 0m0.000s

time python c.py
real 0m0.015s
user 0m0.010s
sys 0m0.000s

time racket c.rkt
real 0m0.084s
user 0m0.060s
sys 0m0.020s

Se compilarmos o código Racket usando o "raco make", temos:

raco make c.rkt
time racket c.rkt

real 0m0.053s
user 0m0.030s
sys 0m0.020s


Conclusão
  • Racket e Python permitem fazer importação de vários módulos num único comando, enquanto que Ruby e Perl não. (Sim, existe o gem require_all pro Ruby, e certamente existe algo similar pro Perl no milagroso CPAN -- mas pelo que sei não existe solução "built-in" na linguagem)


  • Meus amigos Perl Monges devem ficar felizes porque Perl despontou como o mais rápido, né  Breno, Diogo, Samir, Ronald, e cia?
  • Meus amigos adeptos do Ruby vão ficar felizes e dizer que Ruby é mais rápido do que Python :P
  • Meus amigos Pythonistas, pé no chão, vão concordar que Python é rápido o suficiente e é mais divertido que Ruby (e que a conclusão acima, dos rubistas, não pode ser considerada já que meus resultados não provam nada...)
  • Meus amigos que ainda estão conhecendo Racket podem fazer caretas, normal... não tô nem aí :)
    Não me importo em "pagar o preço" para programar numa linguagem mais poderosa e bonita.

Obs: como as diferentes linguagens usam diferentes terminologias, perdoem o uso nem sempre preciso de "módulo", "arquivo", "importar", "requerer", etc. Espero não causar ambiguidade para o leitor.

Friday, May 27, 2011

Sobre escolhas no projeto de linguagens de programação

Este tópico muito me atrái, e por vezes levanto esta discussão nos nossos encontros semanais do Dojo Rio.

Ontem fiz um post tentando esclarer que num mar de similaridades sintáticas podem existir muitas diferenças semânticas. O caso prático foi uma comparação envolvendo Boo, Python e Ruby.

A discussão seguiu na lista do Dojo, e um outro aspecto que marca a diferença entre escolhas feitas no projeto da linguagem Python e escolhas feitas no projeto da linguagem Boo surgiu num comentário do Juan. Este post é uma reflexão sobre este aspecto.

O Juan disse:
De qualquer forma, a coisa que mais me faz gostar de boo é não escrever "__init__", e sim "constructor".

Taí, gosto é um negócio bem abstrato e indiscutível muitas das vezes.

Seguindo a linha de papos que temos às vezes sobre as escolhas feitas no projeto de linguagens e as consequências que estas escolhas acarretam, ser "__init__" ou "constructor" é mais uma questão de escolha, na qual cabe-nos apenas declarar nosso gosto se o tivermos, e observar consequências.

Talvez por estar acostumado com a filosofia Python, o Zen of Python se quiserem, eu gosto da consistência ortogonal do "__whatever__" como disse o Berrondo.
E falar sobre gosto pára por aqui.


Mas e as consequências das escolhas?

Thursday, May 26, 2011

Boo não é Python

Ontem no Coding Dojo Rio no Centro do Rio de Janeiro tivemos uma nova linguagem para experimentar. Em linhas gerais o dojo foi sensacional, e não só os minutos que estávamos lá programando mas também as discussões que rolaram até tarde. Cheguei a casa já eram 2:40!

O problema que abordamos foi o do Caixa Eletrônico. Graças ao Juan Lopes nós usamos Boo e um super dojo timer novinho em folha. A idéia deste post é apenas discutir brevemente um aspecto da linguagem que me chamou a atenção.

Portanto, que fique claro que, apesar da maior parte da sintaxe ser parecida, as linguagens não são as mesmas, e algumas escolhas semânticas e gramaticais deixam isto claro. Também não se trata do que é melhor e o que é pior.

Ontem fiquei curioso pois numa parte obscura do nosso código tínhamos uma função mais ou menos assim:

def sacar(valor):
    return (valor,) if valor in (2, 5, 10, 20, 50, 100)
    
    raise EntradaInconsistente() if valor <= 0
    
    return (20, 20) if valor == 40
    
    return (2,) + sacar(valor - 2) if (valor - 2) in (2, 5, 10, 20, 50, 100)

Possívelmente não era exatamente isto, mas era algo muito parecido e equivalente. Tínhamos 4 linhas que eram raise ou return, seguido de um valor de retorno, seguido de um if e uma condição.

Não demorou para percebermos que a legibilidade estava ruim, pois para saber o que cada linha fazia era preciso ler a linha inteira. Se os if's estiverem em suas próprias linhas, fica mais fácil ler a condição e "ignorar" o bloco de código (mesmo que uma expressão curta...) que se segue.

    if valor in (2, 5, 10, 20, 50, 100):
        return (valor,)

Mas isto pode ser considerada apenas uma questão estilistica...

O ponto é que eu jurava que "return (20, 20) if valor == 40" não é uma linha válida de Python! Sim, de Python... mas estávamos programando em Boo.

Acabou que nós não testamos lá, e ficou o suspense. Em Ruby reza a lenda que isto funciona e é super normal, mas em Python... em Python a história é outra.
Eu fui testar agora no ipython:

In [1]: def foo(x, y):
   ...:     return "x par" if x%2==0
------------------------------------------------------------
   File "", line 2
     return "x par" if x%2==0
                             ^
SyntaxError: invalid syntax


In [3]: def foo(x, y):
    return "x par" if (x%2==0)
------------------------------------------------------------
   File "", line 2
     return "x par" if (x%2==0)
                               ^
SyntaxError: invalid syntax


In [5]: def foo(x, y):
    return "x par" if (x%2==0) else 0
   ...:

E foram confirmadas minhas expectativas de que isso não funciona em Python :D

Tanto return quanto raise são palavras-chave que formam gramaticalmente uma declaração (statement) em Python. E a declaração é "return truthy_value if condition else falsy_value", como pode ser visto na gramática.

A semântica quando se começa uma linha por return é que a função vai retornar o que quer que seja o valor avaliado para o que vem depois da palavra-chave (a não ser claro que antes disso ocorrer uma exceção seja lançada).

E é só isso...

Nota: não encontrei a gramática do Boo para linkar...
Nota mental: espero fazer mais desses posts ao invés de mandar emails longos :D


[update 26/05/2011 20:08]
O Juan acrescentou na lista do Dojo sobre a gramática de Ruby:

STMT : STMT if EXPR
STMT : EXPR
EXPR : ARG
ARG : PRIMARY
PRIMARY : return [`(' [CALL_ARGS] `)']

E então, comparando com Python (já que eu tinha só linkado antes):

return_stmt: 'return' [testlist]
testlist: test (',' test)* [',']
test: or_test ['if' or_test 'else' test] | lambdef

Agora só fica faltando formalizar a gramática do Boo. Fiz uma busca de novo no Google e no site oficial do Boo, mas não achei! Será que você tem mais sorte?

Saturday, August 22, 2009

Dev in Rio 2009

Que Rock in Rio que nada... o evento de 2009 é o Dev in Rio!
Este evento é diferente de tudo que você já viu, e de todos os eventos que já paticipou. E o que me deixa tão confiante para dizer isso? Bem, o foco nas PESSOAS.

Este não é apenas um evento sobre tecnologias e máquinas, e sim um encontro de PESSOAS com um propósito. Ser diferente, a constante busca em fazer o melhor, vontade de mudar o mundo... se você procura pessoas que compatilham deste interesse, vá ao Dev in Rio 2009.

Os créditos vão para os meus amigos Guilherme Chapiewski e Henrique Bastos, dois dos grandes movimentadores de comunidade de software aqui no Rio de Janeiro, e para todos os outros envolvidos que estão tornando o Dev in Rio uma feliz realidade.

O evento será realizado no próximo mês, na segunda-feira dia 14 de Setembro de 2009. É o início da semana com o pé direito.
Infelizmente eu não vou poder participar, pois estarei iniciando outra coisa: minhas aulas em Lisboa!

Então, se não é Dev in Rio em 2009, será Rock in Rio Lisboa em 2010 e Dev in Rio 2010, já apostando na segunda edição!

Além de palestrantes nacionais e internacionais, vai ter uma arena rolando Dojo Rio durante o evento. Já se conscientizou que é imperdível?

Agora é só correr e fazer logo sua inscrição, pois as vagas são limitadas.

Friday, December 5, 2008

Instalando e usando o Capistrano no Ubuntu Linux - Parte 2

Depois de instalarmos o Capistrano hoje pela manhã [1], chegou a hora de usar!

No momento não estamos desenvolvendo em Rails, o framework que tornaria o uso do Capistrano natural. Porém, o Capistrano não é limitado a framework ou linguagem.
Então, vamos configurar o deploy automático de uma aplicação web em TurboGears / Python.

Primeiro criamos um projeto TG básico:
$ tg-admin quickstart
Enter project name: lifeatmymind
Enter package name [lifeatmymind]:
Do you need Identity (usernames/passwords) in this project? [no]
...
$ cd lifeatmymind/
Criamos o diretório config só para termos um dos arquivos que o Capistrano irá criar:
$ mkdir config
E rodamos o comando para preparar o Capistrano para fazer deploy da aplicação: capify.
$ capify .
[add] writing `./Capfile'
[add] writing `./config/deploy.rb'
[done] capified!

Infelizmente tivemos que interromper nossa tarde por alguns problemas.
Ainda faltam alguns passos para efetivamente colocarmos o Capistrano em ação:
  • Configurar nosso repositório SVN
  • Configurar o apache2 (ou instalar o nginx)
  • Configurar o Capistrano
  • Ver se tudo funciona :D
Por hora, existe um tutorial oficial que pode dar uma noção do que fazer [2].

[1] http://lifeatmymind.blogspot.com/2008/12/instalando-e-usando-o-capistrano-no.html
[2] http://www.capify.org/getting-started/from-the-beginning

Instalando e usando o Capistrano no Ubuntu Linux - Parte 1

Hoje resolvemos testar o Capistrano [1] como nova solução para fazer deploy automático das nossas aplicações web do Labase [2].
Partindo de um Ubuntu 8.04 sem o Ruby [3] instalado, o procedimento é o seguinte:

$ sudo apt-get install ruby irb rdoc rubygems

ou

Sistema > Administração > Synaptic
E procure os pacotes ruby, irb, rdoc e rubygems, marque para instalação e clique em "aplicar" (botão verde).

Agora podemos usar o RubyGems para instalar o Capistrano.
O site do Capistrano é enfático em dizer que basta uma linha.
No terminal, digite:

$ sudo gem install capistrano

Bem, isso deveria ter funcionado! Mas não deu certo, pois o pacote RubyGems do repositório do Ubuntu vem dos mantenedores do Debian, e está numa versão muito antiga (0.9.4). Precisamos da versão 1.3.1, que instalamos assim [4]:

$ wget http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz
$ tar xzf rubygems-1.3.1.tgz
$ cd rubygems-1.3.1
$ sudo ruby setup.rb
$ gem -v
bash: gem: comando não encontrado

Mas...

$ gem1.8 -v
1.3.1

O que aconteceu é que o rubygems instalou o script em /usr/bin/gem1.8, e não /usr/bin/gem como esperado. Então, basta criar um link simbólico:

$ sudo ln -s /usr/bin/gem1.8 /usr/bin/gem
$ gem -v
1.3.1

Com isso, agora conseguiremos instalar o Capistrano:
$ sudo gem install capistrano
Successfully installed net-ssh-2.0.4
Successfully installed net-sftp-2.0.1
Successfully installed net-scp-1.0.1
Successfully installed net-ssh-gateway-1.0.0
Successfully installed highline-1.5.0
Successfully installed capistrano-2.5.2
6 gems installed
Installing ri documentation for net-ssh-2.0.4...
Installing ri documentation for net-sftp-2.0.1...
Installing ri documentation for net-scp-1.0.1...
Installing ri documentation for net-ssh-gateway-1.0.0...
Installing ri documentation for highline-1.5.0...
Installing ri documentation for capistrano-2.5.2...
Installing RDoc documentation for net-ssh-2.0.4...
Installing RDoc documentation for net-sftp-2.0.1...
Installing RDoc documentation for net-scp-1.0.1...
Installing RDoc documentation for net-ssh-gateway-1.0.0...
Installing RDoc documentation for highline-1.5.0...
Installing RDoc documentation for capistrano-2.5.2...

E agora?

Lá vem a parte 2...

[1] http://www.capify.org
[2] http://labase.nce.ufrj.br
[3] http://www.ruby-lang.org
[4] Segundo solução postada aqui: http://intertwingly.net/blog/2008/11/23/RubyGems-1-3-1-on-Ubuntu-8-10

Thursday, August 7, 2008

Python ou Ruby? Turbogears x Django x Rails

Bem, não sou o primeiro a fazer esse questionamento. Comecei a procurar a opinião das pessoas, notadamente em blogs, e a olhar os sites de tutorias de cada opção para formar a minha.

Faz um ano que venho desenvolvendo aplicações web usando o Turbogears, que considero muito legal, comparado a coisas como Java para web, PHP, e qualquer outra coisa mais "burocrática".
O TG me permite trabalhar de forma simples e that just works.

Lembro que antes de usar o TG, depois de algum tempo me divertindo com Python, eu queria experimentar ele ou o Django, que eram os frameworks para Python falados na época. Claro, foi também quando fui ver o que era o tal do Zope (nome que vi no dia que resolvi aprender Python...).

Ultimamente o Ruby on Rails tem cada vez mais "batido à porta", e não falta vontade de cair dentro e desenvolver com ele. Até agora eu só vi screencasts, li bastante, ouvi podcasts e mexi em aplicações prontas.

Mas afinal, porquê todo esse papo furado? Hoje temos mais um projeto de desenvolvimento web. Um projeto que deve durar em torno de dois anos no "rítmo universitário". Para ele, a equipe parou pra pensar no que usaríamos. Essa é uma boa hora para ver algo diferente do Turbogears, conhecer novos mundos... mas, o quão novos? Continuar no Python ou pular pro Ruby?
Eu adoro Python, sim, amo mesmo. Deixamos as outras opções de lado e vamos nos decidir entre TG, Django e RoR.

Nos próximos posts vou relatar minha percepção da relação entre Django x TG e RoR x TG.
Como não tenho experiência prática nos frameworks da esquerda, comentários são muito bem vindos! O que pode parecer bom num primeiro momento, pode esconder fraquezas a longo prazo.