Archive for the ‘programacao.funcional’ Category

Ruby é JavaScript ao Avesso

Thursday, June 12th, 2008

O titulo é uma brincadeira mas é uma boa forma de lembrar algumas coisinhas sobre programação nestas linguagens. Cada vez mais lidamos no dia-a-dia com conceitos que estão presentes há décadas em linguagens mais esotéricas mas nunca deram as caras no mainstream, um deles é o uso de funções como abstração. Existe um conflito de termos aqui então só para deixar claro eu não estou falando de funções como em programação procedural mas sim de funções como vemos em closures.

Muita gente tem escrito sobre como devemos aprender programação funcional. Eu concordo mas não posso deixar de notar que quando alguém diz programação funcional geralmente ela quer dizer Higher-Order Functions.

E o que é isso? Bom, uma linguagem possui higher-order quando uma função pode receber como parâmetro outra função. O nome deriva do fato de que uma função que recebe outra é considerada de ordem 1, uma função que recebe outra que recebe outra é considerado 3 e assim em diante.

JavaScript possui higher-order programming. Funções são a abstração principal em javaScript e elas podem ser passadas à vontade pelo programa. Por exemplo, vamos supor que queremos comparar dois objetos de acordo com um critério arbitrário. Em JavaScript podemos fazer algo assim:

function melhorEntre(um, outro, criterio){
  if(criterio(um, outro)){
    return um;
  }
  else {
    return outro;
  }
}

sorvete1 = {sabor: 'morango'};
sorvete2 = {sabor: 'chocolate'};

prefiroChocolate = (function (s1, s2){
                                   return (s1.sabor === 'chocolate');
                            });

prefiroMorango = (function (s1, s2){
                                  return (s1.sabor === 'morango');
                            });

alert(melhorEntre(sorvete1, sorvete2, prefiroMorango).sabor);
alert(melhorEntre(sorvete1, sorvete2, prefiroChocolate).sabor);

Em Ruby o código ficaria um pouco diferente:

def melhor_entre(um, outro, criterio)
    if criterio.call(um, outro)
        um
    else
        outro
    end
end

sorvete_1 = { :sabor => 'chocolate' }
sorvete_2 = { :sabor => 'morango' }

prefiro_chocolate = lambda {|s1,s2| s1[:sabor] == 'chocolate'}
prefiro_morango = lambda {|s1,s2| s1[:sabor] == 'morango'}

puts melhor_entre(sorvete_1, sorvete_2, prefiro_morango)[:sabor]
puts melhor_entre(sorvete_1, sorvete_2, prefiro_chocolate)[:sabor]

Agora vamos pensar: as duas linguagens possuem higher-order programming? Não, só JavaScript possui. Em Ruby o que é passado não é uma função e sim um objeto, veja só:

prefiro_chocolate = lambda {|s1,s2| s1[:sabor] == 'chocolate'}
puts prefiro_chocolate
#=> #<Proc:0x00028a64@tmp/compara.rb:19>
puts prefiro_chocolate.class
#=> Proc

O principal divergente da solução em Ruby é que você deve passar a mensagem call para o objeto (ou usar a palavra-chave yield). Na pratica do dia-a-dia não tem tanta diferença e é comum falar em higher-order Ruby.

Em Ruby não precisamos de funções de verdade para termos higher-order programming, podemos usar objetos para modelar as funções. Em JavaScript não temos construções especiais para objetos, mas utilizamos funções:

function Sorveteiro(){
  this.numeroDeVendidos = 0;
  this.vender = function(){this.numeroDeVendidos++;};
};

s = new Sorveteiro();
alert(s.numeroDeVendidos);
s.vender();
alert(s.numeroDeVendidos);
s.vender();
s.vender();
alert(s.numeroDeVendidos);

Alguém me disse essa semana que uma das grandes vantaens em aprender higher-order programming (a pessoa falou em programação funcional mas não é bem isso que ela quis dizer) é que com ela você simula objetos mas o contrario não é verdade. Bom, não é assim. Nada impede de você ter higher-order programming em uma linguagem Orientada a Objetos (JavaScript é Orientada a Objetos!) e com objetos você pode facilmente modelar higher-order programming.

E qual a diferença disso tudo para programação funcional? Bom, programação funcional usa higher-order programming, mas não é isso que define uma linguagem funcional (JavaScript não é funcional).

Em 1984, John Hughes publicou um paper chamado “Why Functional Programming Matters”. Este paper é, até hoje, uma das obras mais importantes para o paradigma. Nele o autor descreve:

The special characteristics and advantages of functional programming are often summed up more or less as follows. Functional programs contain no assignment statements, so variables, once given a value, never change. More generally, functional programs contain no side-effects at all. A function call can have no effect other than to compute its result. This eliminates a ma jor source of bugs, and also makes the order of execution irrelevant - since no side-efect can change the value of an expression, it can be evaluated at any time. This relieves the programmer of the burden of prescribing the flow of control. Since expressions can be evaluated at any time, one can freely replace variables by their values and vice versa - that is, programs are “referentially transparent”. This freedom helps make functional programs more tractable mathematically than their conventional counterparts.

Erik Meijer apresentou uma palestra no JAOO chamada “Why Functional Programming (still) Matters” onde ele afirma que nenhuma linguagem é realmente funcional, provando que se pode simular efeitos colaterais em Erlang, Haskell, F# e várias outras.

A conclusão do Erik -é claro que defendendo suas decisões ao criar o LINQ- é que os conceitos por trás das linguagens ditas funcionais são mais importantes do que ser uma linguagem puramente funcional ou não.

Isso significa que você deve aprender sobre programação funcional e aplicar suas técnicas sempre que necessário mas cuidado com o termo “funcional”. Na maioria das vezes você quis dizer Higher-Order Programming.

Update: Alguns dos comentários msotram uma confusão com funções javaScript e objetos. Não só o texto falou que em JavaScript funções são objetos bem como ele mostrou o exemplo do sorveteiro, mas tentando deixar ainda mais claro:

ds