É bom estilo explicitamente retornar em Ruby?

Vindo de um background em Python, onde há sempre um “jeito certo de fazê-lo” (uma maneira “Pythonica”) quando se trata de estilo, eu estou querendo saber se o mesmo existe para Ruby. Eu tenho usado minhas próprias diretrizes de estilo, mas estou pensando em liberar meu código-fonte e gostaria que ele seguisse as regras não escritas que possam existir.

É “The Ruby Way” para explicitamente digitar o return nos methods? Eu vi isso feito com e sem, mas existe uma maneira correta de fazer isso? Há talvez um momento certo para fazer isso? Por exemplo:

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

Pergunta antiga (e “respondida”), mas vou lançar meus dois centavos como resposta.

TL; DR – Você não precisa, mas pode tornar seu código muito mais claro em alguns casos.

Apesar de não usar um retorno explícito pode ser “o caminho Ruby”, é confuso para os programadores que trabalham com código desconhecido, ou não estão familiarizados com esse recurso do Ruby.

É um exemplo um pouco inventado, mas a imagem tem uma pequena function como essa, que adiciona um ao número passado e o atribui a uma variável de instância.

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

Isso era para ser uma function que retornou um valor ou não? É realmente difícil dizer o que o desenvolvedor quis dizer, pois ele atribui a variável de instância AND retorna o valor atribuído também.

Suponha que muito mais tarde, outro programador (talvez não tão familiarizado com o retorno do Ruby baseado na última linha de código executada) apareça e queira colocar algumas instruções de impressão para o registro, e a function se torne …

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

Agora a function está quebrada se algo espera um valor retornado . Se nada espera um valor retornado, tudo bem. Claramente, se em algum lugar mais abaixo na cadeia de código, algo chamando isso está esperando um valor retornado, ele falhará, pois não está recebendo de volta o que espera.

A verdadeira questão agora é esta: alguma coisa realmente esperava um valor retornado? Isso quebrou alguma coisa ou não? Será que vai quebrar alguma coisa no futuro? Quem sabe! Somente uma revisão completa de todas as chamadas permitirá que você saiba.

Então, pelo menos para mim, a abordagem de melhor prática é ser muito explícito se você está retornando algo, se é importante, ou não retornar nada quando isso não acontece.

Então, no caso da nossa pequena function de demonstração, assumindo que queríamos que ela retornasse um valor, ela seria escrita assim …

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

E seria muito claro para qualquer programador que ele retorna um valor, e muito mais difícil para ele quebrá-lo sem perceber.

Como alternativa, pode-se escrever assim e deixar de fora a declaração de retorno …

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

Mas por que incomodar deixando de fora a palavra retorno? Por que não apenas colocá-lo lá e torná-lo 100% claro o que está acontecendo? Ele literalmente não terá impacto na capacidade do seu código de executar.

Não. O estilo Good Ruby geralmente usaria apenas retornos explícitos para um retorno antecipado . Ruby é grande em código minimalista / mágica implícita.

Dito isto, se um retorno explícito tornasse as coisas mais claras, ou mais fáceis de ler, não prejudicaria nada.

Eu pessoalmente uso a palavra-chave return para distinguir entre o que eu chamo de methods funcionais , isto é, methods que são executados primariamente por seu valor de retorno, e methods processuais que são executados primariamente por seus efeitos colaterais. Portanto, methods nos quais o valor de retorno é importante, obtenha uma palavra-chave de return extra para chamar atenção para o valor de retorno.

Eu uso a mesma distinção ao chamar methods: methods funcionais obtêm parênteses, methods processuais não.

E por último, mas não menos importante, eu também uso essa distinção com blocos: blocos funcionais recebem chaves, blocos procedurais (isto é, blocos que “fazem” alguma coisa) fazem do / end .

No entanto, eu tento não ser religioso sobre isso: com blocos, chaves e do / end tem precedência diferente, e ao invés de adicionar parênteses explícitos para desambiguar uma expressão, eu simplesmente mudo para o outro estilo. O mesmo vale para a chamada de método: se adicionar parênteses ao redor da lista de parâmetros torna o código mais legível, eu o faço, mesmo se o método em questão for processual por natureza.

Na verdade, o importante é distinguir entre:

  1. Funções – methods executados para seu valor de retorno
  2. Procedimentos – methods executados por seus efeitos colaterais

Ruby não tem uma maneira nativa de distinguir estes – o que deixa você vulnerável a escrever um procedimento side_effect() e outro desenvolvedor a decidir abusar do valor implícito de retorno do seu procedimento (basicamente tratando-o como uma function impura).

Para resolver isso, tire uma folha do livro de Scala e Haskell e faça com que seus procedimentos retornem explicitamente nil (também conhecido como Unit ou () em outros idiomas).

Se você seguir isso, usar a syntax de return explícita ou não se tornará apenas uma questão de estilo pessoal.

Para distinguir ainda mais entre funções e procedimentos:

  1. Copie a boa idéia de Jörg W Mittag de escrever blocos funcionais com chaves e blocos procedurais com do/end
  2. Quando você invoca procedimentos, use () , enquanto quando invoca funções, não

Observe que Jörg W Mittag realmente defendeu o contrário – evitando () s para procedimentos – mas isso não é aconselhável porque você deseja que as invocações de método de efeito colateral sejam claramente distinguíveis das variables, particularmente quando arity é 0. Consulte o guia de estilo Scala no método invocação para detalhes.

O guia de estilo declara que você não deveria estar usando o return em sua última declaração. Você ainda pode usá-lo se não for o último . Esta é uma das convenções que a comunidade segue estritamente, e você também deve se você planeja colaborar com qualquer um usando Ruby.


Dito isto, o principal argumento para usar return explícitos é que é confuso para pessoas que vêm de outras línguas.

  • Em primeiro lugar, isso não é totalmente exclusivo do Ruby. Por exemplo, o Perl também tem retornos implícitos.
  • Em segundo lugar, a maioria das pessoas a quem isso se aplica vem das línguas Algol. A maioria delas é muito “inferior” do que Ruby, por isso você precisa escrever mais código para fazer alguma coisa.

Uma heurística comum para o comprimento do método (excluindo getters / setters) em java é uma canvas . Nesse caso, você pode não estar vendo a definição do método e / ou já ter esquecido de onde você estava retornando.

Por outro lado, em Ruby é melhor seguir methods com menos de 10 linhas . Dado isso, seria de se perguntar por que ele tem que escrever mais 10% de declarações, quando elas estão claramente implícitas.


Como o Ruby não tem methods nulos e tudo é muito mais conciso, você está apenas adicionando sobrecarga para nenhum dos benefícios se você optar por return explícitos.

Eu concordo com Ben Hughes e discordo de Tim Holt, porque a questão menciona a maneira definitiva como o Python faz e pergunta se Ruby tem um padrão similar.

Isso acontece.

Esta é uma característica tão conhecida da linguagem que qualquer um esperava depurar um problema em ruby ​​deveria razoavelmente ser esperado para saber sobre isso.

É uma questão de qual estilo você prefere na maioria das vezes. Você precisa usar a palavra-chave return se quiser retornar de algum lugar no meio de um método.

Como Ben disse. O fato de que ‘o valor de retorno de um método ruby ​​é o valor de retorno da última instrução no corpo da function’ faz com que a palavra chave return seja raramente usada na maioria dos methods 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