Ruby: Usar la palabra clave unless con una declaración de devolución

Actualmente estoy trabajando en un proyecto donde tengo un código que se ve así:

  # 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

Donde uso el operador a menos para ejecutar condicionalmente la declaración de devolución. Por algún motivo, este código todavía se ejecuta incluso si @ident_a_node es nil . Cuando ejecuto recibo este mensaje:

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

Lo cual me confunde porque pensé que la palabra clave a menos evitaría que esto sucediera. Cuando cambio la declaración a este formulario:

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

o esta forma:

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

La declaración de devolución no está ejecutada , ¿qué ocurre? ¿Por qué hay una diferencia entre estas dos afirmaciones? ¿Tiene múltiples condiciones con la palabra clave a menos que cause problemas?

Cualquier idea sería apreciada

0

2 Respuestas

Tienes una falla lógica allí. Está probando que son ambos nil para evitar ejecutarlo cuando debería probar si cualquiera de ellos es nil . Probablemente te hayas metido en esta situación al tener demasiadas capas de negación. Cualquier cosa más que uno es inaceptable.

En otras palabras, puede salirse con la suya "si no está lloviendo", pero no debe usar cosas como "a menos que el indicador is_not_raining no esté establecido en el inverso de false".

Mi opinión personal es que las condiciones finales no deben usarse a menos que sea obvio que están presentes. Como puede ver en su ejemplo, tiene que desplazarse horizontalmente para encontrar la condición, ocultando información importante del desarrollador.

Como una cuestión de estilo, no use not cuando ! hará el mismo trabajo. En segundo lugar, está probando específicamente contra nil cuando probablemente solo quiera un valor definido de algún tipo.

Otros problemas incluyen el uso de Hash [] y Array [] que seguramente son artefactos de usar un lenguaje que los requiera. Ruby, como JavaScript, permite la declaración implícita de estos usando {} y [] respectivamente.

Una versión propia de ruby de tu código es:

if (@ident_a_node and @id)
  return { "IdentANode" => [ @id, ",", @ident_a_node.collect ] }
end  
0
agregado
@NiklasB. Estoy de acuerdo en que la verbosidad de los lenguajes como Java es un gran inconveniente, pero para mí es una transición difícil. Todo lo que sé sobre programación proviene de ese paradigma de verbosidad.
agregado el autor Hunter McMillen, fuente
Gracias, esto fue de gran ayuda.
agregado el autor Hunter McMillen, fuente
Lo que estoy haciendo en el método de recopilación es devolver un Hash, por lo que si el valor es nulo, debería devolver Hash con un valor nulo. {"IdentANode" => nil}
agregado el autor Hunter McMillen, fuente
La razón principal por la que elijo usar, a menos que sea porque tengo muchos de estos condicionales y tener una declaración if para cada uno, haría que el código fuera más desordenado en mi opinión.
agregado el autor Hunter McMillen, fuente
Además, ¿hay una buena guía de estilo para consultar cosas como Hash [] y Array [] versus {key => value} y [] ??
agregado el autor Hunter McMillen, fuente
@NiklasB. La mayor parte de mi experiencia de programación proviene de Java y C, los literales no existen para estas cosas en Java y C
agregado el autor Hunter McMillen, fuente
@Hunter: Creo que no es un gran problema. La mayoría de estos lenguajes se basan en una a tres estructuras de datos muy básicas que luego se usan de manera muy extensa en cada aplicación. Para Ruby, esos son arreglos, hashes y quizás símbolos (no incluí cadenas aquí porque debería estar acostumbrado a su sintaxis de Java). Si sabes cómo y cuándo usarlos, será una transición fácil :)
agregado el autor Niklas B., fuente
@Hunter: Bueno, lo hacen en la mayoría de los lenguajes modernos, como JavaScript, Python, LISP (Clojure, Scheme, CL, ...), Scala, Haskell, ... En realidad C es de muy bajo nivel, no tiene en estructuras de datos a excepción de las matrices (para las cuales existe la sintaxis de inicialización). El hecho de que Java no tiene tal cosa es un gran fastidio, en mi humilde opinión (pero también tiene el elemento new int [] {1, 2, 3} ).
agregado el autor Niklas B., fuente
@Hunter: ¿No es obvio que los literales son más limpios que los constructores explícitos cuando están disponibles? En cuanto al estilo general de Ruby, me gustan las Pautas de Github ruby
agregado el autor Niklas B., fuente
¿Por qué el return ? Solo haría si ...; [expr]; más; nulo; end (para dejar en claro que se devuelve nil en caso de error)
agregado el autor Niklas B., fuente

No lo use a menos que sea con y/o simplemente confuso. a menos @ ident_a_node.nil? y @ id.nil? significa if! (@ ident_a_node.nil? y @ id.nil?) , lo que significa que volverá siempre que una de las dos variables de instancia no sea nula.

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

es lo mismo que

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

lo que debería hacerlo aún más claro, por qué no es lo mismo que

if not @ident_a_node.nil? and not @id.nil?
0
agregado
por alguna razón, esperaba una traducción como esta: if! first_condition y! second_condition Muchas gracias
agregado el autor Hunter McMillen, fuente
Intenté usar a menos que la forma @NiklasB. consejos, el mismo problema permanece. a menos que sea complicado.
agregado el autor iGbanam, fuente
En realidad, creo que me gusta más porque tiene la misma semántica que un assert . Básicamente podemos intercambiar el return a menos que con assert o levante ArgumentError, "..." a menos que en cualquier momento.
agregado el autor Niklas B., fuente
@Yasky: entiendo a qué te refieres. OP probablemente significa return a menos que @ident_a_node y @id . No es necesario usar nil? (Debo haber sobreescrito). Considero esto más limpio que el retorno de equivalente si @ ident_a_node.nil? o @ id.nil?
agregado el autor Niklas B., fuente
@dominik: a menos que te permita expresar tus condiciones en inglés simple. Además, el return a menos que sea un modismo que veo bastante a menudo, por lo que me parece que mucha gente está acostumbrada. Para ser honesto, veo esos tipos de errores booleanos muy raramente de desarrolladores experimentados, por lo que no los considero confusos.
agregado el autor Niklas B., fuente
@Hunter: cuando se trata de la negación de la conjunción y la disyunción, las leyes de De Morgan son muy útil.
agregado el autor Niklas B., fuente
@NiklasB. Teniendo en cuenta que el tipo de error de PO es muy común, lo consideraría bastante confuso como para evitarlo :) No hay ninguna razón por la que deberíamos aplicar De Morgan en nuestra cabeza cada vez que vemos un mensaje de error con y/o. Tampoco hay beneficio de usar a menos que sea aquí.
agregado el autor Dominik Honnef, fuente