Ruby: Usando a palavra-chave unless com uma instrução de retorno

Atualmente estou trabalhando em um projeto onde tenho código que se parece com isso:

  # the first return is the one causing problems
  def collect
    return Hash["IdentANode", Array[@id, ",", @ident_a_node.collect]] unless @ident_a_node.nil? and @id.nil?
    return Hash["IdentANode", @id] unless @id.nil?
  end

Onde eu uso o operador a menos para executar condicionalmente a declaração de retorno. Por alguma razão, este código ainda é executado mesmo que @ident_a_node seja nil . Ao executar, recebo esta mensagem:

IdentANode.rb: 14: em collect ': método indefinido collect' para   nil: NilClass (NoMethodError)

O que me confunde porque pensei que a palavra-chave a menos impediria que isso acontecesse. Quando altero a declaração para este formulário:

if not @ident_a_node.nil? and not @id.nil?
  return Hash["IdentANode", Array[@id, ",", @ident_a_node.collect]]
end  

ou este formulário:

return Hash["IdentANode", Array[@id, ",", @ident_a_node.collect]] if not @ident_a_node.nil? and not @id.nil?

A declaração de retorno é não executada, o que dá? Por que há uma diferença entre essas duas declarações? Ter várias condições com a palavra-chave unless causa problemas?

Qualquer ideia seria apreciada

0
adicionado editado
Visualizações: 1

2 Respostas

Você tem uma falha lógica lá. Você está testando que eles são ambos nil para evitar a execução quando você deveria estar testando se é nil . Você provavelmente se meteu nessa situação tendo muitas camadas de negação. Qualquer coisa mais do que um é inaceitável.

Em outras palavras, você pode se safar com "se não estiver chovendo", mas não deve usar coisas como "a menos que o sinalizador is_not_raining não esteja configurado para o inverso de false".

Minha opinião pessoal é que as condições de fuga não devem ser usadas a menos que seja óbvio que elas estejam presentes. Como você pode ver no seu exemplo, você precisa rolar horizontalmente para encontrar a condição, ocultando informações importantes do desenvolvedor.

Por uma questão de estilo, não use não quando ! fará o mesmo trabalho. Em segundo lugar, você está testando especificamente contra nil quando você provavelmente quer apenas um valor definido de algum tipo.

Outros problemas incluem o uso de Hash [] e Array [] que são certamente artefatos de usar uma linguagem que os requer. Ruby, como JavaScript, permite a declaração implícita destes usando {} e [] respectivamente.

Uma versão adequada em estilo ruby do seu código é:

if (@ident_a_node and @id)
  return { "IdentANode" => [ @id, ",", @ident_a_node.collect ] }
end  
0
adicionado
@ NiklasB. Eu concordo que a verbosidade das linguagens como o Java é uma grande desvantagem, mas é uma transição difícil para mim tudo o que sei sobre programação vem desse paradigma de verbosidade
adicionado o autor Hunter McMillen, fonte
Obrigado, isso foi muito útil.
adicionado o autor Hunter McMillen, fonte
O que eu estou fazendo no método collect é retornar um hash, então se o valor for nil, ele deve retornar o Hash com um valor nulo. {"IdentANode" => nada}
adicionado o autor Hunter McMillen, fonte
A principal razão que eu escolho usar, a menos que seja porque eu tenho muitas dessas condicionais e ter uma declaração if para cada um, faria o código mais confuso na minha opinião.
adicionado o autor Hunter McMillen, fonte
Além disso, há um bom guia de estilo para se referir a coisas como o Hash [] e Array [] vs {key => valor} e [] ?
adicionado o autor Hunter McMillen, fonte
@ NiklasB. A maior parte da minha experiência de programação vem de Java e C, literais não existem para essas coisas em Java e C
adicionado o autor Hunter McMillen, fonte
@Hunter: Eu acho que isso não é muito problema. A maioria dessas linguagens é baseada em uma a três estruturas de dados muito básicas que são usadas extensivamente em todos os aplicativos. Para Ruby, esses são arrays, hashes e talvez símbolos (eu não incluí as strings aqui porque você deveria estar acostumado com a sintaxe deles do Java). Se você souber como e quando usá-los, será uma transição fácil :)
adicionado o autor Niklas B., fonte
@Hunter: Bem, eles fazem na maioria das linguagens modernas, como JavaScript, Python, LISP (Clojure, Esquema, CL, ...), Scala, Haskell, ... Na verdade, C é muito baixo nível, não tem em estruturas de dados, exceto para matrizes (para as quais a sintaxe de inicialização existe). O fato de que o Java não tem tal coisa é uma enorme chatice, IMHO (mas também tem a coisa new int [] {1, 2, 3} ).
adicionado o autor Niklas B., fonte
@Hunter: Não é óbvio que os literais são mais limpos que os construtores explícitos quando disponíveis? Quanto ao estilo geral do Ruby, gosto das Diretrizes do Github ruby
adicionado o autor Niklas B., fonte
Por que o retorna ? Eu apenas faria se ...; [expr]; outro; nada; end (para deixar claro que nil é retornado em caso de falha)
adicionado o autor Niklas B., fonte

Não use a menos que com e/ou, é simplesmente confuso. a menos que @ ident_a_node.nil? e @ id.nil? significa se! (@ ident_a_node.nil? e @ id.nil?) , o que significa que retornará sempre que uma das duas variáveis ​​de instância não for nula.

if !(@ident_a_node.nil? and @id.nil?)

é o mesmo que

if [email protected]_a_node.nil? or [email protected]?

o que deve tornar isso ainda mais claro, porque não é o mesmo que

if not @ident_a_node.nil? and not @id.nil?
0
adicionado
por alguma razão eu estava esperando uma tradução assim: if! first_condition e! second_condition Muito obrigado
adicionado o autor Hunter McMillen, fonte
Eu tentei usar a menos que do jeito @NiklasB. conselhos, a mesma questão permanece. a menos que seja complicado.
adicionado o autor iGbanam, fonte
Na verdade eu acho que gosto mais porque tem a mesma semântica que um assert . Basicamente, podemos trocar o retorno de a menos que com assert ou aumente ArgumentError, "..." a menos que a qualquer momento.
adicionado o autor Niklas B., fonte
@ Yasky: Eu vejo o que você quer dizer. OP provavelmente significa return a menos que @ident_a_node e @id . Não precisa usar nil? (eu devo ter superado isso). Eu considero este mais limpo que o retorno equivalente se @ ident_a_node.nil? ou @ id.nil?
adicionado o autor Niklas B., fonte
@dominik: a menos que permita expressar suas condições em inglês simples. Além disso, o retorna, a menos que seja um idioma que eu vejo com bastante frequência, então me parece que muitas pessoas estão acostumadas com isso. Para ser honesto, vejo esses tipos de erros booleanos muito raramente de desenvolvedores experientes, e é por isso que não considero isso confuso.
adicionado o autor Niklas B., fonte
@Hunter: Quando se trata da negação de conjunção e disjunção, as leis de De Morgan são muito útil.
adicionado o autor Niklas B., fonte
@ NiklasB. Considerando que o tipo de erro dos OPs é muito comum, eu consideraria confuso o suficiente para evitar :) Não há nenhuma razão pela qual deveríamos ter que aplicar De Morgan em nossa cabeça toda vez que vemos um exceto com e/ou. Também não há benefício em usar a menos que esteja aqui.
adicionado o autor Dominik Honnef, fonte