2010-02-05 5 views
27

Pourquoi Scala ne parvient pas à déduire le type de retour de la méthode lorsqu'une instruction explicite return est utilisée dans la méthode?Inférence de type sur le type de retour de méthode

Par exemple, pourquoi compiler le code suivant?

object Main { 
    def who = 5 
    def main(args: Array[String]) = println(who) 
} 

Mais ce qui suit ne le fait pas.

object Main { 
    def who = return 5 
    def main(args: Array[String]) = println(who) 
} 

Répondre

30

Le type de retour d'une méthode est soit le type de la dernière instruction du bloc qui la définit, soit le type de l'expression qui la définit, en l'absence de bloc.

Lorsque vous utilisez return à l'intérieur d'une méthode, vous introduisez une autre instruction à partir de laquelle la méthode peut renvoyer. Cela signifie que Scala ne peut pas déterminer le type de ce return au point où il est trouvé. Au lieu de cela, il doit continuer jusqu'à la fin de la méthode, puis combiner tous les points de sortie pour déduire leurs types, puis revenir à chacun de ces points de sortie et affecter leurs types. Cela augmenterait la complexité du compilateur et le ralentirait, pour le seul gain de ne pas avoir à spécifier le type de retour lors de l'utilisation return. D'un autre côté, dans le système actuel, l'inférence du type de retour vient gratuitement de l'inférence de type limité que Scala utilise déjà. Donc, à la fin, dans l'équilibre entre la complexité du compilateur et les gains à obtenir, on a jugé que ce dernier ne valait pas le premier.

+5

Bonjour Daniel. Je n'ai pas votre explication. Scala doit déjà combiner plusieurs expressions et des points de sortie dans les fonctions à cause des instructions if/else. Et le langage Scala contient des tonnes de choses complexes et complexes que les programmeurs de la plupart des Scala d'IMO ne comprennent pas très bien ou n'utilisent pas (par exemple covariance/contravariance, types structurels, etc.). Cela ajoute beaucoup de complexité au compilateur; donc "rend le compilateur plus complexe" semble une réponse faible. –

+4

@UrbanVagabond Vous avez manqué la partie "gains à être en tête". Juste parce que quelque chose est complexe ne veut pas dire qu'il vaut la peine d'y ajouter plus de complexité. Maintenant, Scala n'a pas besoin de combiner plusieurs expressions et de quitter des points sur les instructions if/else car if/else est une expression, pas des instructions. Cela peut sembler friser les poils, mais la différence est très réelle. –

-2

Je ne sais pas pourquoi. Peut-être juste pour décourager l'utilisation de l'instruction return. :)

1

Compte tenu de cette (2.8.Beta1):

object Main { 
    def who = return 5 
    def main(args: Array[String]) = println(who) 
} 
<console>:5: error: method who has return statement; needs result type 
     def who = return 5 

... il ne semble pas accidentelle.

11

Cela augmenterait la complexité du compilateur (et du langage). C'est vraiment génial de faire une inférence de type sur quelque chose comme ça. Comme pour tout ce qui concerne l'inférence de type, tout fonctionne mieux quand vous avez une seule expression. Les déclarations renvoyées dispersées créent effectivement beaucoup de ramification implicite qui devient très difficile à unifier. Ce n'est pas que c'est particulièrement dur, juste collant. Par exemple:

def foo(xs: List[Int]) = xs map { i => return i; i } 

Qu'est-ce que, je vous demande, le compilateur en déduit ici? Si le compilateur faisait une inférence avec des instructions de retour explicites, il devrait être Any. En fait, beaucoup de méthodes avec des instructions de retour explicites finissent par renvoyer Any, même si vous ne vous sentez pas sournois avec des retours non-locaux. Comme je l'ai dit, collant.

Et en plus de cela, ce n'est pas une fonctionnalité de langue qui devrait être encouragée. Les retours explicites ne pas améliorer la clarté du code, sauf s'il n'y a qu'un seul retour explicite et que c'est à la fin de la fonction. La raison est assez facile à voir si vous visualisez les chemins de code comme un graphe orienté. Comme je l'ai dit plus tôt, les retours dispersés produisent beaucoup de ramification implicite qui produit des feuilles bizarres sur votre graphe, ainsi que beaucoup de chemins supplémentaires dans le corps principal. C'est juste génial. Le flux de contrôle est beaucoup plus facile à voir si vos branches sont toutes explicites (correspondance de modèle ou expressions if) et votre code sera beaucoup plus fonctionnel si vous ne comptez pas sur les instructions return pour produire des valeurs.

Ainsi, comme plusieurs autres « découragées » caractéristiques à Scala (par exemple asInstanceOf plutôt que as), les concepteurs de la langue a fait un choix délibéré pour rendre les choses moins agréable. Ceci combiné avec la complexité qu'il introduit dans l'inférence de type et l'inutilité pratique des résultats dans tous les scénarios sauf les plus artificiels. Cela n'a aucun sens pour scalac de tenter ce genre d'inférence.

Morale de l'histoire: apprenez à ne pas disperser vos retours! C'est un bon conseil dans n'importe quelle langue, pas seulement Scala.

+0

@ Daniel ... "découragé" caractéristiques dans Scala (par exemple commeInstanceOf plutôt que comme) ".... Ai-je manqué quelque chose? Je ne me souviens pas de" comme "une fonction dans Scala (mais je suis assez nouveau à Scala , donc c'est peut-être mon erreur.) – Jus12

+0

@ Daniel, je pense qu'une recommandation encore meilleure serait d'éviter d'utiliser 'return's (related: http://stackoverflow.com/questions/3770989/purpose-of-return-statement -dans-scala) – Jus12

+1

Il n'y a pas de fonction "as" dans Scala, mais un opérateur "as" dans C# qui fonctionne comme la méthode "asInstanceOf" dans Scala. est * si * verbeux, et la réponse est simplement de décourager son utilisation –

Questions connexes