Pregunta

Procedente de un fondo de Python, donde siempre hay una "forma correcta de hacerlo". (una forma '' Pythonic '') cuando se trata de estilo, me pregunto si existe lo mismo para Ruby. He estado usando mis propias pautas de estilo, pero estoy pensando en publicar mi código fuente, y me gustaría que se adhiera a las reglas no escritas que puedan existir.

¿Es " The Ruby Way " escribir explícitamente return en los métodos? Lo he visto hecho con y sin, pero ¿hay una manera correcta de hacerlo? ¿Existe tal vez un momento adecuado para hacerlo? Por ejemplo:

def some_func(arg1, arg2, etc)
  # Do some stuff...
  return value # <-- Is the 'return' needed here?
end
¿Fue útil?

Solución

Antigua (y '' contestada '') pregunta, pero arrojaré mis dos centavos como respuesta.

TL; DR: no es necesario, pero puede hacer que su código sea mucho más claro en algunos casos.

Aunque no usar un retorno explícito puede ser "la forma de Ruby", es confuso para los programadores que trabajan con código desconocido o no están familiarizados con esta característica de Ruby.

Es un ejemplo un tanto artificial, pero las imágenes tienen una pequeña función como esta, que agrega uno al número pasado y lo asigna a una variable de instancia.

def plus_one_to_y(x)
    @y = x + 1
end

¿Se suponía que era una función que devolvía un valor, o no? Es realmente difícil decir qué quiso decir el desarrollador, ya que asigna la variable de instancia Y devuelve el valor asignado también.

Supongamos que mucho más tarde, aparece otro programador (tal vez no tan familiarizado con cómo Ruby regresa en función de la última línea de código ejecutada) y quiere poner algunas declaraciones de impresión para el registro, y la función se convierte en esto ...

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
end

Ahora la función está rota si algo espera un valor devuelto . Si nada espera un valor devuelto, está bien. Claramente, si en algún lugar más abajo de la cadena de código, algo que llama a esto espera un valor devuelto, fallará ya que no está recuperando lo que espera.

La verdadera pregunta ahora es esta: ¿esperaba algo realmente un valor devuelto? ¿Esto rompió algo o no? ¿Romperá algo en el futuro? ¡Quién sabe! Solo una revisión completa del código de todas las llamadas te lo hará saber.

Entonces, al menos para mí, el enfoque de mejores prácticas es ser muy explícito de que está devolviendo algo si es importante, o no devolver nada cuando no lo es.

Entonces, en el caso de nuestra pequeña función de demostración, suponiendo que deseamos que devuelva un valor, se escribiría así ...

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
    return @y
end

Y sería muy claro para cualquier programador que devuelve un valor, y mucho más difícil para ellos romperlo sin darse cuenta.

Alternativamente, uno podría escribirlo así y omitir la declaración de devolución ...

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
    @y
end

¿Pero por qué molestarse en dejar de lado la palabra retorno? ¿Por qué no simplemente ponerlo allí y dejar 100% claro lo que está sucediendo? Literalmente no tendrá ningún impacto en la capacidad de rendimiento de su código.

Otros consejos

No. El buen estilo Ruby generalmente solo usaría un retorno explícito para un retorno temprano . Ruby es grande en el minimalismo de código / magia implícita.

Dicho esto, si un retorno explícito aclararía las cosas o facilitaría la lectura, no dañará nada.

Yo personalmente uso la palabra clave return para distinguir entre lo que llamo métodos funcionales , es decir, métodos que se ejecutan principalmente por su valor de retorno, y métodos de procedimiento que se ejecutan principalmente por sus efectos secundarios. Entonces, los métodos en los que el valor de retorno es importante, obtenga una palabra clave return adicional para llamar la atención sobre el valor de retorno.

Utilizo la misma distinción cuando invoca métodos: los métodos funcionales tienen paréntesis, los métodos de procedimiento no.

Y por último pero no menos importante, también utilizo esa distinción con los bloques: los bloques funcionales obtienen llaves, los bloques de procedimiento (es decir, los bloques que "hacen" algo) obtienen do / end .

Sin embargo, trato de no ser religioso al respecto: con bloques, llaves y do / end tienen una prioridad diferente, y en lugar de agregar paréntesis explícitos para desambiguar un expresión, simplemente cambio al otro estilo. Lo mismo ocurre con la llamada al método: si agregar paréntesis alrededor de la lista de parámetros hace que el código sea más legible, lo hago, incluso si el método en cuestión es de naturaleza procesal.

En realidad, lo importante es distinguir entre:

  1. Funciones: métodos ejecutados para su valor de retorno
  2. Procedimientos: métodos ejecutados por sus efectos secundarios

Ruby no tiene una forma nativa de distinguirlos, lo que lo deja vulnerable a escribir un procedimiento side_effect () y a otro desarrollador que decide abusar del valor de retorno implícito de su procedimiento (básicamente tratándolo como una función impura).

Para resolver esto, saque una hoja del libro de Scala y Haskell y haga que sus procedimientos devuelvan explícitamente nil (también conocido como Unit o () en otros idiomas).

Si sigue esto, entonces usar la sintaxis explícita return o no solo se convierte en una cuestión de estilo personal.

Para distinguir aún más entre funciones y procedimientos:

  1. Copie la buena idea de Jörg W Mittag de escribir bloques funcionales con llaves y bloques de procedimiento con do/end
  2. Cuando invoque procedimientos, use () , mientras que cuando invoque funciones, no

Tenga en cuenta que Jörg W Mittag en realidad abogó al revés, evitando () s para los procedimientos, pero eso no es aconsejable porque desea que las invocaciones de métodos de efectos secundarios sean claramente distinguibles de las variables, especialmente cuando el arity es 0. Consulte la Guía de estilo Scala sobre invocación de métodos para obtener más detalles.

La guía de estilo establece que no deberías ' No use return en su última declaración. Todavía puede usarlo si no es el último . Esta es una de las convenciones que la comunidad sigue estrictamente, y usted también debería hacerlo si planea colaborar con alguien que use Ruby.


Dicho esto, el argumento principal para usar return s explícito es que es confuso para las personas que vienen de otros idiomas.

  • En primer lugar, esto no es completamente exclusivo de Ruby. Por ejemplo, Perl también tiene retornos implícitos.
  • En segundo lugar, la mayoría de las personas a las que se aplica esto provienen de los idiomas Algol. La mayoría de ellos son " nivel inferior " que Ruby, por lo tanto, debe escribir más código para hacer algo.

Una heurística común para la longitud del método (excluyendo getters / setters) en java es una pantalla . En ese caso, es posible que no esté viendo la definición del método y / o que ya se haya olvidado de dónde regresaba.

Por otro lado, en Ruby lo mejor es seguir los métodos menos de 10 líneas de largo . Dado eso, uno se preguntaría por qué tiene que escribir ~ 10% más de declaraciones, cuando están claramente implícitas.


Dado que Ruby no tiene métodos void y todo es mucho más conciso, solo está agregando gastos generales para ninguno de los beneficios si opta por return s explícito .

Estoy de acuerdo con Ben Hughes y no estoy de acuerdo con Tim Holt, porque la pregunta menciona la forma definitiva en que Python lo hace y pregunta si Ruby tiene un estándar similar.

Sí.

Esta es una característica tan conocida del lenguaje que cualquier persona que esperara depurar un problema en ruby ??debería saberlo razonablemente.

Es una cuestión de qué estilo prefieres en su mayor parte. Debe usar la palabra clave return si desea regresar desde algún lugar en medio de un método.

Como dijo Ben. El hecho de que "el valor de retorno de un método ruby ??es el valor de retorno de la última instrucción en el cuerpo de la función" hace que la palabra clave return rara vez se use en la mayoría de los métodos ruby.

def some_func_which_returns_a_list( x, y, z)
  return nil if failed_some_early_check


  # function code 

  @list     # returns the list
end
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top