Ruby é uma linguagem maravilhosa, mas tem alguns poréns. O que eu vou citar é algo bem pequeno mas a linguagem está repleta de coisas do tipo.
> class Foo > def bar; @bar; end > def bar=(other) > puts "bar= has been called" > @bar = other > end > end
Basicamente escrevemos um setter para um variável.
> foo = Foo.new > foo.bar = 1 bar= has been called => 1
Ok, exatamente como esperávamos.
> foo.bar = foo.bar || 2 bar= has been called => 1
Ok, sem surpresas ainda.
> foo.bar ||= 2 => 1
Ops, notem que bar= não foi chamado.
Portanto, ao contrário do que muitos pensam foo.bar ||= 2 é diferente de foo.bar = foo.bar || 2.
foo.bar ||= 2 só realiza a atribuição se bar não avaliar para uma expressão verdadeira.
É algo muito bobo e muito sútil, mas se o programador realizar alguma computação na atribuição, essa computação pode não ser executada em alguns casos.
Isso não é um grande problema, porém existem diversas coisas do tipo na linguagem. O Matz diz que a linguagem deve ter o comportamento que o programador espera, isso é bom porque a linguagem torna-se natural, mas e casos como esse, o que o programador espera?
Outra coisa decorrente é que isto dificulta outras implementações Ruby 100% compatíveis.
Acho que essa confusão é gerada por comparação aos operadores matemáticos += -= ...
ResponderExcluirvalue = 1
value += 1 # same value= value + 1
O operador binário || diz que, se o operando a esquerda for um valor verdadeiro, retorna este valor, mas caso contrário se executa o operador a direita, que neste caso tem um sugar sintaxe para chamar o atribuidor (=) do valor a esquerda, que neste caso o operando a esquerda deve implementar o método (=)
value ||= 2 # same value || value = 2
Sei não, nesse específico caso a linguagem se comporta como eu espero, então, pra mim causa o efeito oposto. São surpresas desse tipo que me maravilham todo dia.
ResponderExcluirMas fiquei interessado em saber sobre as outras coisas que te incomodam no Ruby.
Discordo. A linguagem se comporta exatamente como eu esperaria.
ResponderExcluirComo disse, o Celestino, talvez tenha havido uma confusão pelo fato de ||= parecer com +=. Na verdade:
`foo.bar ||= 2` é apenas um atalho para `foo.bar = 2 unless foo.bar`
Correção:
ResponderExcluir`foo.bar ||= 2` é na verdade um atalho para `foo.bar || foo.bar = 2`