Gostaria de fazer uma pergunta sobre vários valores de retorno, por que esse construto não é preferível em linguagens de programação (dificuldades conceituais e / ou técnicas). Eu ouvi algo sobre quadros de pilha e como eles reservam memória para valor de retorno e valores de retorno variáveis podem tornar isso problemático, mas se alguém pudesse explicar isso melhor, isso seria muito apreciado.
Em linguagens conctanetative (como FORTH), ter vários valores de retorno de uma função é uma coisa comum e muito útil, e imagino que algo parecido com isto em linguagens do tipo java / c também seria útil (um exemplo muito básico):
x, y = multRet(5);
multret(int x) {
return x+1;
return x+2;
exit;
}
Para esclarecer: não estou perguntando como retornar vários valores (essa é uma pergunta conhecida com respostas conhecidas), mas quero obter um esclarecimento sobre por que essa prática não é comum em linguagens de programação.
fonte
i=0; while (true) { return i; i+=1 }
?). Observe que algumas linguagens funcionais oferecem tuplas, uma alternativa melhor.return
instrução. Ao retornar funções / lambdas, você pode ter razão.Respostas:
As funções são tradicionalmente consideradas como retornando um único valor - em matemática. É claro que vários valores formam uma tupla, mas muitas vezes em matemática estamos lidando com funções com valor real. Suspeito que essa origem de funções seja a razão pela qual vários valores de retorno não são tão comuns. Dito isso, é fácil imitá-los de várias maneiras (retornando uma tupla ou tendo vários parâmetros de saída, ou seja, passados por referência), e algumas linguagens modernas comuns (como Python) suportam nativamente essa construção.
fonte
Ter vários valores de retorno é preferível . Na falta deles, o design é ruim, puro e simples. No entanto, devemos esclarecer o equívoco de que tal coisa existe no sentido em que você está pensando.
Em linguagens baseadas no cálculo lambda digitado (as linguagens de programação progenitoras), por exemplo, família ML, Haskell, uma função (abstração lambda) aceita apenas um único argumento e "retorna" (mais formalmente, avalia para) um único resultado. Então, como podemos criar uma função que parece receber ou retornar vários valores?
A resposta é que podemos "colar" valores usando tipos de produtos . Se A e B são os dois tipos, o tipo de produtoA × B contém todas as tuplas do formulário ( a , b ) , Onde a : A e b : B .
Assim, para criar uma função
multiply
que multiplica dois números inteiros, atribuímos o tipo a elamultiply: int * int -> int
. Ele aceita um único argumento que passa a ser uma tupla. Da mesma forma, uma funçãosplit
que divide uma lista em duas teria tiposplit: a list -> a list * a list
.Talvez 30 anos atrás, a implementação era uma preocupação válida ao incluir esse recurso. De acordo com a convenção de chamada C cedl (e é exatamente isso, uma convenção - que ninguém a ordenou), o valor de retorno é armazenado em um registro especial, geralmente
EAX
. Certamente, isso é extremamente rápido de ler e escrever, então a ideia tem algum mérito.Mas é muito limitante, como você aponta, e não há motivo para seguirmos essa regra hoje em dia. Por exemplo, poderíamos usar a seguinte política: para um pequeno número de valores retornados, use um conjunto de registros especificados (temos mais registros para uso agora do que nos anos 80). Para dados maiores, poderíamos retornar um ponteiro para um local na memória. Não sei o que é melhor; Eu não sou um escritor de compilador. Mas a convenção arcaica de chamada C não deve ter influência na semântica das linguagens modernas.
fonte
A sintaxe não é necessária quando padrões simples fazem o trabalho melhor e a sintaxe proposta seria historicamente confusa para muitas pessoas. Isso significa que sua sintaxe é difícil de aprender e causará problemas quando as pessoas alternarem entre seu idioma e os outros.
O padrão simples que resolve esse problema é definir uma variável denominada "returnValue" no início do seu método e depois atribuir valores a ele. Se você precisar de vários valores, basta usar uma coleção de algum tipo e adicionar os valores. Em seguida, retorne esta variável. Problema resolvido.
Sua sintaxe significaria que, por padrão, você teria que lidar com coleções. Isso é frustrante para funções que retornam apenas 1 valor.
E se alguém fizer algo errado? Por exemplo.
ou
O compilador deve pegar isso? E se você tiver um loop?
Na melhor das hipóteses, isso seria açúcar sintático. Algo que não adiciona novos recursos, mas apenas torna os padrões atuais mais confortáveis e mais curtos no código.
Na pior das hipóteses, isso levaria a um erro horrível e horrível no código. Exceção de ponteiro nulo em massas.
fonte
É principalmente por razões sintáticas; no seu próprio exemplo, a primeira declaração de retorno retornaria um valor e retornaria e nunca alcançaria a segunda declaração de retorno.
Atualmente, existem alguns idiomas que permitem o retorno de uma tupla, que é zero, um ou mais valores de tipos arbitrários, agrupados em um único valor. Ainda assim, eles estão retornando um valor, apenas um valor um pouco mais complicado. Geralmente, esses idiomas também podem atribuir uma tupla a zero, uma ou mais variáveis correspondentes, geralmente com uma maneira fácil de ignorar alguns elementos da tupla. Isso pode ser assim:
Atribua tupla a outra tupla:
Essa sintaxe não seria compatível com C, onde (x, y) é uma expressão de vírgula entre parênteses. Por outro lado, é muito mais fácil receber dois valores do que em C, onde você passa os dois valores usando ponteiros ou declara uma estrutura para esse fim, preenche e devolve. Usando ponteiros, o terceiro exemplo em que o chamador está interessado apenas em um valor é uma dor, portanto esse método de retornar tuplas é muito útil.
fonte
return x, y
e para aceitar os valores de retorno que você fariax,y = multiRet()