É difícil escrever uma lista balizada demonstrando como o seu código será diferente em Ruby por comparação a C e C++ pois a diferença é tremenda. Uma das razões, é que o Ruby runtime faz muito do trabalho pelo programador.
O Ruby parece estar tão longe quanto possível do principio de “sem mecanismos escondidos” do C — o objectivo principal do Ruby é tornar o trabalho humano mais fácil ás custas de entregar ao runtime um maior volume de trabalho. A menos que, ou até que, se dedique a optimizar o seu código, não terá de se preocupar minimamente em “manter o seu compilador feliz” quando usa o Ruby.
Dito isto, e para começar, deverá esperar que o seu código Ruby seja executado muito mais lentamente do que código “equivalente” em C ou C++. Ao mesmo tempo, ficará espantado com a rapidez com a qual poderá pôr um programa em Ruby a correr, bem como com a quantidade diminuta de linhas de código necessárias para o escrever. O Ruby é muito, muito mais simples que o C++—irá estraga-lo com mimos!
O Ruby é tipado dinamicamente e não estaticamente—o runtime faz tanto trabalho quanto possível em tempo de execução. Por exemplo, o programador não precisará de saber a que módulos o seu programa em Ruby irá “ligar-se” (isto é, carregar e usar) ou saber de antemão que métodos irá chamar.
Felizmente, acontece que o Ruby e o C mantêm uma saudável relação simbiótica. O Ruby suporta os chamados “módulos de expansão”. Estes são um tipo de módulo que se pode usar a partir da sua aplicação em Ruby (e que, vistos do exterior parecem ser e agem como qualquer outro módulo de Ruby), mas que no entanto são escritos em C. Deste modo, poderá dividir as partes do seu projecto em Ruby e utilizar C puro onde a performance é mais critica.
E, claro, o Ruby em si é escrito em C.
Semelhanças com o C
Como em C, no Ruby…
- Poderá programar processualmente (no entanto o código será orientado a objectos por detrás de cena)
- Os operadores são, na sua maioria, os mesmos (inclusive os operadores
de atribuição composta (exe.: a *= b + c) e também os operadores de
lógica binária). No entanto o Ruby não tem os operadores
++
e--
. - Tem o
__FILE__
e o__LINE__
. - Pode usar constantes, no entanto não existe a palavra reservada
const
. A “constância” é garantida por uma convenção de nomenclatura – todos os nomes começados com letra maiúscula são reservados para constantes. - As strings (cadeias de caracteres em C) são delimitadas por aspas.
- As strings são mutáveis.
- Tal como as man pages, poderá ler a maioria da documentação no
terminal – usando para isso o comando
ri
- Tem o mesmo tipo de depuradores em linha de comandos.
Semelhanças com o C++
Como com o C++, em Ruby…
- A maioria dos operadores são os mesmos (inclusive o
::
). É comum utilizar<<
para acrescentar elementos a uma lista. No entanto atenção: em Ruby nunca se usa->
—é sempre.
. - As palavras reservadas
public
,private
eprotected
têm comportamentos semelhantes. - A sintaxe de herança é ainda apenas um caracter, mas é o
<
em vez de:
. - Pode colocar o seu código em “módulos”, semelhantes ao modo como o
namespace
é usado em C++. - As excepções têm um funcionamento semelhante, no entanto a nomenclatura das palavras reservadas foi mudada para proteger os inocentes!
Diferenças do C
Ao contrario do C, em Ruby…
- Os objectos são fortemente tipados (e as próprias variáveis não têm qualquer tipo).
- Não existem macros ou pre-processador. Não existem casts. Não existem ponteiros (nem aritmética de ponteiros). Não existem typedefs, sizeof ou enums.
- Não existem ficheiros header. Basta definir funções (normalmente chamados de “métodos”) e classes nos ficheiros de código fonte.
- Não se usa
#define
. Ao invés usam-se constantes. - A partir da versão 1.8 de Ruby, o código é interpretado em tempo de execução em vês de ser compilado para qualquer tipo de código maquina ou binário.
- As variaveis residem em memoria. Mais ainda, não precisam de se
preocupar em liberta-las—o
garbage collector
encarrega-se disso por si. - Os argumentos são passados aos métodos (por exemplo: funções) por referência, não por valor.
- Usa-se
require 'foo'
em vez de#include <foo>
ou#include "foo"
. - Não se pode baixar ao assembly.
- As linhas não acabam com ponto e virgula.
- Nas construções lógicas
if
ewhile
não se usam parênteses. - A utilização de parênteses na chamada a metodos (por exemplo: funções) é normalmente opcional.
- Normalmente não se usa chavetas – basta usar a palavra reservada end
para terminar um bloco de código expandido por múltiplas linhas(por
exemplo um ciclo
while
). - A palavra reservada
do
é utilizada nos chamados “blocos”. Não existe a construçãodo
como em C. - O termo “bloco” é usado para algo completamente diferente. Usa-se para bloco de código que se associa a uma chamada de método para que o corpo do método possa fazer chamadas ao bloco enquanto é executado.
- Não existem declarações de variáveis. Simplesmente atribuem-se valores assim que surja a necessidade.
- Num teste lógico, apenas false e nil são avaliados como falso. Tudo o
resto é verdadeiro (incluindo
0
,0.0
, e"0"
). - Não existe o
char
—é apenas uma string de apenas uma letra. - As strings não acabam com um byte nulo.
- Os arrays literais são colocados dentro de parênteses rectos em vez de chavetas.
- Os arrays crescem automaticamente quando se lhes acrescente elementos.
- Se somar dois arrays obterá um array novo e maior (alojado em memoria, é claro) em vez de fazer aritmética de ponteiros.
- Frequentemente tudo será considerado uma expressão (o que quer dizer
que coisas como ciclos
while
serão avaliados com umrvalue
).
Diferenças do C++
Ao contrario do C++, no Ruby,…
- Não existem referências explícitas. O que quer dizer que em Ruby cada variável e apenas um nome automaticamente desreferenciado para algum objecto.
- Os objectos são fortemente mas dinamicamente tipados. O runtime descobre em tempo de execução se a chamada a método realmente funciona.
- O “construtor” é chamado
initialize
em vez de um nome de uma classe. - Todos os métodos são sempre virtuais.
- Nomes de variáveis de classe (estáticas) começam sempre por
@
(por exemplo@valor_total
). - Não se pode aceder directamente a variáveis de membros todo o acesso a variáveis públicas de membros (chamadas em Ruby de atributos) é feito através de métodos.
- Usa-se
self
em vez dethis
. - Alguns nomes de métodos terminam em ’?’ ou ’!’. E a terminação faz realmente parte do nome.
- Não existe múltipla herança por si só. Embora em Ruby possa haver “mixins” (por exe.: pode-se herdar todas as instancias de métodos de um modulo).
- Nas chamadas a métodos, os parênteses são opcionais.
- Pode-se reabrir uma classe a qualquer momento e adicionar novos métodos.
- Não há a necessidade de utilização de templates de C++ (uma vez que se pode atribuir qualquer tipo de objecto a qualquer variável e os tipos são descobertos em tempo de execução de qualquer modo). Também não existe casting.
- A iteração é feita de uma maneira algo diferente. Em Ruby não
utilizará um objecto iterador separado (como por exemplo
vector<T>:const_iterator iter
) mas ao invés os objectos criados podem misturar o moduloenumerator
e fazer uma chamada a um método como por exemplomeu_obj.each
. - Existem apenas dois tipos contentores:
Array
eHash
. - Não existe conversão de tipo. No entanto provavelmente aperceber-se-á que tal não é necessário.
- As capacidades multithreading são nativas, mas a partir do Ruby 1.8, elas são “threads ecológicas” (implementadas apenas dentro do interpretador) por oposição a threads nativas.
- O Ruby vem complementado com uma biblioteca standard de testes unitários.