¿Es un buen estilo devolver explícitamente en Ruby?


Viniendo de una Pitón de fondo, donde siempre hay una "manera correcta de hacerlo" (un "Python" cuando se trata de estilo, me pregunto si el mismo existe 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 adhiriera a cualquier regla no escrita que pueda existir.

¿Es "La forma Ruby" escribir explícitamente return en los métodos? Lo he visto hecho con y sin, pero ¿hay una manera correcta de hacerlo? Hay tal vez un derecho tiempo para hacerlo? Por ejemplo:

def some_func(arg1, arg2, etc)
  # Do some stuff...
  return value # <-- Is the 'return' needed here?
end
Author: Sasha Chedygov, 2009-06-21

8 answers

Vieja pregunta (y "contestada"), pero voy a tirar mis dos centavos como respuesta.

TL;DR - No tiene que hacerlo, 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 manera de Ruby", es confuso para los programadores que trabajan con código desconocido, o que no están familiarizados con esta característica de Ruby.

Es un ejemplo algo artificial, pero la imagen tiene 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

¿Estaba esto destinado a ser una función que devolvía un valor, o no? Es muy difícil decir lo que el desarrollador quiso decir, ya que tanto asigna la variable de instancia, Y devuelve el valor asignado, así.

Supongamos que mucho más tarde, otro programador (quizás no tan familiarizado con cómo Ruby devuelve basado en la última línea de código ejecutado) viene y quiere poner algunas instrucciones de impresión para el registro, y la función se convierte en este...

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 está esperando un valor devuelto, va a fallar ya que no está recuperando lo que espera.

La verdadera pregunta ahora es esta: ¿algo realmente esperaba 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 le permitirá saber.

Así que para mí, al menos, el enfoque de la mejor práctica es ser muy explícito de que está devolviendo algo si importa, o devolver nada en absoluto cuando no lo hace.

Así que en el caso de nuestra pequeña función demo, suponiendo que queríamos que devolviera 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 es muy claro para cualquier programador que devuelve un valor, y mucho más difícil de romper sin dándolo cuenta.

Alternativamente, uno podría escribirlo así y omitir la instrucción return...

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 ponerlo ahí y dejar 100% claro lo que está pasando? Literalmente, no tendrá ningún impacto en la capacidad de su código para realizar.

 200
Author: Tim Holt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-28 21:20:27

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

Dicho esto, si un retorno explícito haría las cosas más claras o más fáciles de leer, no dañará nada.

 66
Author: Ben Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-15 23:35:48

Personalmente uso la palabra clave returnpara 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. Por lo tanto, los métodos en los que el valor devuelto es importante, obtienen una palabra clave return extra para llamar la atención sobre el valor devuelto.

Uso la misma distinción cuando llama a métodos: los métodos funcionales obtienen paréntesis, procedimentales los métodos no.

Y por último, pero no menos importante, también uso 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,do/end tienen diferente precedencia, y en lugar de agregar paréntesis explícitos para desambiguar una expresión, simplemente cambio al otro estilo. Lo mismo ocurre con la llamada al método: si agrega paréntesis alrededor del la lista de parámetros hace que el código sea más legible, yo lo hago, incluso si el método en cuestión es de naturaleza procedimental.

 30
Author: Jörg W Mittag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-21 08:29:17

En Realidad lo importante es distinguir entre:

  1. Funciones-métodos ejecutados por su valor devuelto
  2. Procedimientos-métodos ejecutados por sus efectos secundarios

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

Para resolver esto, tome un hojee el libro de Scala y Haskell y haga que sus procedimientos devuelvan explícitamente nil (también conocido como Unit o () en otros idiomas).

Si sigues esto, entonces usar sintaxis explícita return o no simplemente 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, utilice (), mientras que cuando invoca 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 recomendable porque desea que las invocaciones de métodos de efecto lateral sean claramente distinguibles de las variables, particularmente cuando arity es 0. Vea la guía de estilo de Scala sobre invocación de métodos para más detalles.

 13
Author: Alex Dean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-30 13:06:48

La guía de estilo indica que no debe usar return en su última declaración. Todavía puedes usarlo si no es el último. Esta es una de las convenciones que la comunidad sigue estrictamente, y también deberías hacerlo tú si planeas colaborar con alguien que use Ruby.


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

  • En primer lugar, esto no es totalmente exclusivo de Rubí. Por ejemplo, Perl también tiene retornos implícitos.
  • En segundo lugar, la mayoría de las personas a las que esto se aplica provienen de lenguas Algol. La mayoría de ellos son way "lower level" que Ruby, por lo tanto tienes que 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 one screen. 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 estaba regresando de.

Por otro lado, en Ruby es mejor atenerse a los métodos de menos de 10 líneas. Teniendo en cuenta que, uno se preguntaría por qué tiene que escribir ~10% más 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 sobrecarga para ninguno de los beneficios si usa returns explícitos.

 7
Author: ndn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-24 13:01:49

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

Lo hace.

Esta es una característica tan conocida del lenguaje que cualquiera que espere depurar un problema en ruby debería esperarse razonablemente que lo sepa.

 3
Author: Devon Parsons,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-30 20:49:13

Es cuestión de qué estilo prefieras en su mayor parte. Tienes que usar la palabra clave return si quieres volver desde algún lugar en el medio de un método.

 1
Author: Praveen Angyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-21 03:54:25

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
 0
Author: Gishu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-11 02:17:10