Rust: Arguments par défaut et arguments de mot-clé

Créé le 6 juin 2013  ·  70Commentaires  ·  Source: rust-lang/rust

Je n'ai vu aucun problème pour les arguments de mots clés, des plans pour cela à l'avenir ?


REMARQUE : le bug tracker n'est pas l'endroit pour avoir une discussion sur la conception. Veuillez diriger toutes les discussions de conception vers l'etherpad ( https://pad.riseup.net/p/hvbg6dQQnEe7 ) ou créer une page bikeshedding sur le wiki.

Etherpads :

Commentaire le plus utile

Triage 05-08-2013 : aucun progrès (à ma connaissance), même si ce serait quand même chouette ; peut-être que la syntaxe de la déclaration pourrait ressembler à

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

où le RHS est n'importe quelle expression constante (c'est-à-dire les choses qui sont valides dans une déclaration static ).

Tous les 70 commentaires

Il n'y a eu aucun plan pour cela, même si personne n'a encore exprimé d'opposition. Je réfléchis à ce problème depuis longtemps, et cela se résume essentiellement à une demande d'arguments par défaut. Je suppose que cela ressemblerait à quelque chose comme:

fn foo(bar: int, qux=2: int, ham=0: uint) { ... }

Qui pourrait alors être appelé foo(1) , foo(1, 3) , foo(1, ham=4) , foo(6, 7, 8) , etc.

EDIT : veuillez consulter la syntaxe proposée par huonw ci-dessous, qui est bien meilleure et plus uniforme avec la syntaxe de déclaration actuelle.

Triage 05-08-2013 : aucun progrès (à ma connaissance), même si ce serait quand même chouette ; peut-être que la syntaxe de la déclaration pourrait ressembler à

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

où le RHS est n'importe quelle expression constante (c'est-à-dire les choses qui sont valides dans une déclaration static ).

IMO, ceux-ci sont vraiment utiles, même le système C++ d'_arguments par défaut_ où vous ne pouvez revenir aux valeurs par défaut que pour les arguments de fin non spécifiés serait formidable... réduit le nombre de variantes de fonctions nommées alternatives tout en n'étant pas aussi complexe que la surcharge .. être capable de déclarer ces variantes in structs et enum serait également formidable.
Peut-être que ce sous-ensemble plus simple du comportement requis pourrait être implémenté avant qu'il n'y ait un consensus sur comment/si appeler des paramètres de mot-clé nommés ... cela préparerait les internes ?

serait-il viable/utile d'implémenter en tant qu'expressions ... en termes d'arguments spécifiés précédemment et de paramètres de type générique (par exemple, la capacité de rechercher un zéro : :, ou écrivez des choses comme slice(&self, start:uint , end:uint=self.len ()) /* "foobarbaz".slice(6) == "baz" .. ou create_window(parent,x,y, width :uint=parent.width ()/4, height:uint= (width_161)/100) /_ par défaut les fenêtres en forme de nombre d'or et 1/4 de largeur d'écran si vous ne spécifiez aucune taille.. */ .. .. ou cela ressemble-t-il simplement à une recette pour le gonflement du code ..

Les valeurs par défaut du style c++ empêcheraient une application de fonction partielle de type haskell, mais j'ai entendu dire qu'il était peu probable que cela entre ?

Voici une autre idée d'arguments par défaut. Plutôt que de permettre aux arguments d'être complètement élidés, nous permettons aux arguments pour lesquels une valeur par défaut existe d'être invoqués avec un _ .

Donc, étant donné le bel exemple de @huonw de :

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

... nous pourrions l'invoquer sous la forme foo(1, 2, None) , foo(1, _, Some(1)) , foo(1, _, _) , etc.

Cependant, cette idée n'apporterait pas vraiment d'avantages à l'adoption d'arguments de mots clés, étant donné qu'elle est toujours strictement positionnelle.

Modification du titre en « arguments par défaut et arguments de mot-clé ».

pas implémenté, mais j'ai essayé d'ajouter au ast & parser; https://github.com/dobkeratops/rust/compare/default_args , est-ce la bonne façon de procéder ? (Option @expr .. il faudra des contraintes sur ce que l'expr peut être ? )
plonger mes orteils dans l'eau pour expérimenter cette fonctionnalité.
Je serais ravi d'augmenter le sous-ensemble d'API C++ qui pourraient être traduits, et c'est certainement quelque chose qui me manque de C++, et la fonctionnalité de mot-clé nommé serait géniale au-delà de ce que fait C++.
Il semblait simple et logique d'aller avec la deuxième syntaxe de déclaration suggérée

@dobkeratops qui a l'air bien (bien que le type Default = Option<@expr> soit probablement inutile).

Les contraintes sur le expr vont dans rustc::middle::check_const ; vous devrez ajouter une fonction comme check_fn qui vérifie chaque argument. (De plus, il devrait probablement y avoir une vérification que les arguments par défaut n'apparaissent qu'à la fin ; et je suppose qu'il devra y avoir quelque chose dans le vérificateur rustc::middle::typeck type trans aussi. )

Ok, le champ est nommé donc c'est une annotation inutile.
Merci pour les pointeurs sur où chercher, je cherchais dans rustc::middle::typeck ::.. mod.rs (check_fn quelque chose ).

au nom de « l'intégration continue », cela vaut-il la peine que je soumette les bases triviales en tant que pr, si je m'arrête là-dessus, peut-être que quelqu'un qui connaît mieux la base de code pourrait faire les autres parties beaucoup plus rapidement une autre fois.
Je suis toujours paranoïaque à propos des changements divergents

C'est seulement destructeur si vous décidez définitivement _contre_ eux ?

Quelqu'un a suggéré que ce genre de chose puisse aller avec une option -Z (..Session::debug_opts...mais je n'ai pas trouvé ces swere actuellement propagés partout (par exemple dans l'analyseur).

Je peux voir que vous pourriez vous opposer à ce que le compilateur analyse quelque chose qu'il n'utilise pas encore, je pourrais peut-être le changer d'un avertissement en une erreur ...

@dobkeratops Notez qu'aucun développeur officiel n'a encore commenté cela, il est donc très peu probable qu'un PR soit accepté. Il y a beaucoup de discussions à avoir ici concernant 1) si nous voulons des arguments par défaut, 2) si oui, quelle devrait être la syntaxe et 3) si nous voulons des arguments de mot-clé (car la sémantique que nous choisissons pour les arguments par défaut pourrait empêcher cela ).

D'accord, je suppose qu'ils seraient une priorité très basse pendant encore longtemps, car ils ne bloquent rien (ils ne sont certainement pas en haut de ma propre liste de souhaits).
J'ai juste pensé que cela pourrait être un fruit à portée de main, et une autre familiarité pour les personnes C++ ..
Je suppose que les macros peuvent parfois faire un travail similaire (et plus).

Je peux voir que les arguments nommés ne sont pas critiques, mais les arguments facultatifs de l'OMI le sont en quelque sorte. Parce qu'à certains endroits, je pense avoir vu quelques méthodes avec des signatures similaires et des noms similaires juste pour offrir des interfaces plus faciles lorsqu'un argument donné n'est pas nécessaire. Ce serait nul si nous nous retrouvions avec des fonctions héritées comme celle-ci simplement parce qu'une fonctionnalité manquait.

Il y a beaucoup de parties subtiles ici. Tout argument par défaut est une forme implicite de surcharge, donc (je suppose) sera probablement intégré à l'algorithme de résolution de trait et/ou à l'inférence de type. Ce n'est peut-être pas très difficile, mais cela vaut la peine d'être conçu avec soin, et à ce stade, je ne suis pas sûr que nous ayons le budget temps pour cela. En tant que fonctionnalité _language_, j'imagine qu'elle est rétrocompatible ; en tant que fonctionnalité d'api, cela informerait probablement certains de la conception d'api, ce qui représente donc un risque bc.

@Seldaek Je suis d'accord que si nous voulons des arguments par défaut, il est alors important de les implémenter avant de nous engager pour la compatibilité ascendante stdlib. Cependant, je connais au moins un langage (Go) qui rejette philosophiquement les arguments par défaut en faveur de l'approche des fonctions avec des noms et des signatures légèrement différents.

Cependant, contrairement à Rust, Go a quelques fonctionnalités qui rendent l'absence d'arguments par défaut moins douloureuse. D'une part, ils ont des fonctions variadiques.[1] Deuxièmement, vous êtes autorisé à omettre des champs lors de la création de structures, ce qui signifie qu'il est facile de passer une structure de configuration à une fonction (les champs omis semblent être définis sur des valeurs par défaut spécifiées par le compilateur (?), plutôt que d'être quelque chose qu'un utilisateur peut personnaliser).[2]

Pour le premier, nous pourrions peut-être nous en sortir avec du macro-piratage pour obtenir le même résultat (bien qu'à un coût de mise en œuvre laborieux). En effet, le prochain remplacement de fmt!() fait ceci :

ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3)

C'est un code qui fonctionne aujourd'hui.

Quant à ce dernier, le meilleur analogue que nous ayons serait d'utiliser la mise à jour de la structure fonctionnelle comme suit :

struct Foo { x: int, y: int, z: int }

impl Foo {
    fn default() -> Foo {
        Foo{x: 0, y: 0, z: 0}
    }
}

fn bar(f: Foo) {
    printf!(f);
}

fn main() {
    bar(Foo{y: 5, ..Foo::default()});
}

J'ai vu cette méthode suggérée avec désinvolture dans le passé comme une solution de contournement pour le manque d'arguments par défaut, mais c'est assez disgracieux dans la pratique (comparez bar(Foo{y: 5, ..Foo::default()}) à bar(y=5) , ou ma proposition plus conservatrice de bar(_, 5, _) ), et bien sûr, cela oblige tous les appelants à créer une structure même s'ils veulent passer tous les arguments.

Pour réitérer, en tant que personne qui vient de Python et de Javascript, j'apprécierais évidemment les arguments par défaut. Cependant, je sympathise quelque peu avec la philosophie de Go consistant à rendre les API explicites (en échange de (potentiellement considérablement) gonfler le nombre de fonctions dans l'API elle-même).

[1] https://groups.google.com/d/msg/golang-nuts/NWMReL1HueQ/X9mdYduCOB8J

[2] http://stackoverflow.com/questions/2032149/facultatif-paramètres

Je dois également souligner qu'il interagit avec les fermetures et prend des références de première classe à des fonctions.

@bstrie merci pour la

Et je suis en quelque sorte d'accord pour dire que les fonctions wrapper pour remplir les arguments par défaut ne sont pas si mauvaises dans certains cas. Mais le problème est que même si cela vous évite certains cas déroutants, cela introduit beaucoup de passe-partout dans d'autres. Un exemple est *::to_str_radix(num, radix) . Si nous avions des arguments facultatifs, cela pourrait bien être plié dans *::to_str(num, radix = 10) . J'ai l'impression que dans certains cas, l'explosion des variantes de fonctions rend les choses moins intuitives et plus difficiles à retenir. Juste mes deux cents bien évidemment.

Je peux voir que c'est un bon compromis pour les reporter ;
mais va-t-il _vraiment_ omettre les défauts philosophiquement, ou est-ce juste eux qui justifient les compromis de budgétisation du temps de mise en œuvre qu'ils ont faits ? Je serais surpris si quelqu'un pensait que parcourir long_function_names_with_lots_of_trailing_qualifiers est un pas en avant :) , mais s'ils disaient "cela nous permet de tirer parti d'outils simples, nous n'avons pas encore développé d'IDE puissant .." c'est une autre affaire.

La surcharge et les valeurs par défaut de C++ me manquent définitivement.

Pour une expérience, j'ai pensé à essayer de les faire en tant que « piratage d'analyseur » ... travaillant au niveau des macros ? incorporer les expr par défaut sur les sites d'appel où les arguments sont manquants ?
Je me rends compte qu'il est peu probable que ce soit une conception acceptable - mais cela me fait croire qu'il n'est pas _impossible_ d'avoir des arguments par défaut qui fonctionnent avec les fonctionnalités de rusts.

Une chose à laquelle je m'habitue encore vraiment, c'est que les méthodes sont en théorie beaucoup plus utilisables dans la rouille.
De retour en C++, j'ai peur d'eux à cause des problèmes d'en-tête/dépendance (c'est la raison principale pour laquelle je suis ici), donc je vais souvent instinctivement d'abord pour les fonctions.
Peut-être que les valeurs par défaut me manqueront moins lorsque j'utiliserai mieux la rouille.

Pour que l'idée ne disparaisse pas : l'aspect bavard de bar(Foo{y: 5, ..Foo::default()}) me semble être la partie ..Foo::default() .

Si nous facilitions l'omission des champs dans une construction de structure, en les laissant tomber à une valeur par défaut, alors peut-être que cette approche serait plus acceptable.

Par exemple, une nouvelle forme, probablement définie uniquement pour les structures qui implémentent un trait approprié ( Zero ou Default ou autre), qui ressemblait à ceci :

Foo{y: 5, *) où le * remplace le précédent ..Foo::default() .

Alors l'exemple est "juste" bar(Foo{y: 5, *}) . Peut-être que d'autres préféreraient que le Foo ne soit pas là non plus, mais cela me semble assez propre.

Je suppose que les énumérations vous donnent également d'autres moyens de transmettre de manière pratique des groupes de paramètres facultatifs différemment de ce à quoi un programmeur C++ est habitué ... et un moyen d'intercaler des annotations et des valeurs avec un appel.
Cela semblerait convenir aux cas comme créer quelque chose avec beaucoup de paramètres de configuration bien

@pnkfelix Rappelez-vous que la Foo dans cet exemple aurait probablement un nom beaucoup plus auto-descriptif, et même avec votre sucre proposé ressemblerait à quelque chose comme ceci dans la pratique :

html::start_server(html::ServerOpts{port: 10088, *});

C'est un peu plus joli. Je ne sais toujours pas si cela aide suffisamment pour justifier une nouvelle syntaxe ou si cela suffit pour satisfaire tous les cas d'utilisation d'arguments par défaut.

En fait, pour utiliser mon propre exemple, lors de l'initialisation de quelque chose avec beaucoup d'options telles qu'un serveur HTML, je serais probablement tout aussi heureux de configurer au préalable une structure server_opts , puis d'appeler simplement start_server(server_opts) . Et cela ne me dérange vraiment pas d'ajouter une ligne avec ..html::ServerOpts::default si mon initialisation de structure s'étend déjà sur plusieurs lignes.

Je pense que nous devons peut-être repenser où les arguments par défaut seraient les plus utiles. Pour moi, ce n'est pas là qu'il y a beaucoup d'arguments potentiels ; ceux-ci devraient être assez rares, et quelques lignes pour initialiser une structure de configuration suffisent. Au contraire, les arguments par défaut me manquent le plus lorsque 1) l'opération est assez courante et 2) l'opération a, au plus, un ou deux arguments qui sont presque toujours superflus mais nécessaires pour être complet. Par example:

let foo = Some('a');
foo.unwrap();  // same as today
foo.unwrap('z');  // imagine that this replaced unwrap_or_default

int::from_str("4");  // same as today
int::from_str("4", 16);  // imagine that this replaced from_str_radix

Cependant, maintenant que je les ai tapés, je préfère en fait le caractère explicite des méthodes séparées. :) Peut-être que je ne sais pas vraiment ce que je veux après tout !

@dobkeratops , d'après votre expérience avec C++, pouvez-vous nous donner quelques exemples d'API C++ sympas qui sont activées par les arguments par défaut ?

Les commentaires dans https://github.com/mozilla/rust/wiki/Meeting-weekly-2013-08-13 semblent indiquer que les développeurs voient cela comme une fonctionnalité d'un avenir lointain. Nomination.

OCaml fait un argument facultatif/par défaut sans surcharger, je crois. Les arguments facultatifs de type T sans valeur par défaut sont implicitement convertis en option T et la fonction doit vérifier si une valeur a été fournie. Il existe également des restrictions sur la déclaration et l'utilisation d'arguments facultatifs pour informer le compilateur lorsqu'un argument a été omis. Tous les arguments facultatifs doivent avoir des étiquettes (ils doivent être des arguments de mot-clé pour être facultatifs). Cela complique le système de types d'OCaml (les étiquettes deviennent une partie du type de la fonction) mais je pense que c'est un artefact d'avoir à interagir avec le reste du système de types Hindley-Milner.

Venant de C++, les valeurs d'argument par défaut me manqueraient vraiment. J'utilise souvent des fonctions avec un grand nombre de paramètres, où la plupart d'entre elles ont presque toujours des valeurs par défaut, à l'exception de quelques rares cas d'utilisation ou de test. L'ajout de dérivés de nom de fonction purement combinatoires au lieu de valeurs par défaut créerait un grand désordre de noms très longs.

Je suis d'accord que les arguments par défaut et/ou les arguments de mot-clé seraient extrêmement utiles. Je pense que nous devrions travailler vers une proposition pré-1.0 qui décrit ce qui doit être fait en termes de surcharge et peut-être avoir une discussion sur la syntaxe.

C'est bien de voir plus de gens commenter en faveur :) Une autre raison pour laquelle je le voulais était d'augmenter le nombre d'API C++ pouvant être traduites de manière transparente. L'utilisation des bibliothèques C++ est l'une des principales raisons pour lesquelles nous sommes bloqués avec C++.

Je soupçonne que la seule façon pour nous d'obtenir cela si la communauté pouvait _le mettre en œuvre_ sans aucun coût pour les développeurs principaux.
Je suis d'accord qu'ils ont des choses bien plus importantes à faire, et les énumérations récupèrent le polymorphisme perdu avec des possibilités qui ne sont pas immédiatement apparentes pour les cerveaux conditionnés C++.

C'est pourquoi je voulais soumettre les bases de son analyse dans la structure de données AST. Il serait prêt pour que quelqu'un d'autre le ramasse et essaie d'obtenir une solution. les premiers commentaires m'ont découragé de faire un PR.

de c++ Je regarde ce que scala et python ont là-dessus avec envie. Un langage natif non-GC avec cette élégance serait formidable.
..sa plus de fonctionnalités en un seul endroit, moins de navigation pour comprendre ce qui se passe, moins de profondeur d'imbrication, moins de bruit dans le code source. Pas seulement trivialement moins de frappe.
peut-être pourriez-vous même prétendre qu'elle est plus auto-documentée, la signature de la fonction vous en dit plus sur la façon dont elle est utilisée.

le peu difficile est le vérificateur de type, empêchant les possibilités de bogues subtiles et les erreurs déroutantes s'il s'agissait simplement d'un hack d'analyseur, pense-t-il.

imaginez si vous pouviez simplement écrire des choses comme ça..

fn substr(a:&str, start:int, end:int=a.len())->~str

il suffit de pirater ce genre de chose dans l'AST sans vérification d'erreur, je suis sûr que beaucoup de choses peuvent mal tourner .. mais imaginez si nous pouvions résoudre ce problème pour faire ce qui était attendu :)

Juste un bug. Nous pouvons débattre du fond, mais nous ne bloquerons pas une sortie là-dessus.

J'aime le comportement que @tautologico décrit dans son commentaire.

Appliqué à Rust, je pense que cela se traduirait par ce qui suit :

fn ga(bu: int, zo: Option<int>, meu: Option<int>) {
  let zo = zo.get_or_default(42);
  let meu = meu.get_or_default(99);
  ...
}

Et ceux-ci seraient tous des appels valides :

ga(10, 20, 30); // 20 and 30 are automagically
                // converted to Some(20) and Some(30)
ga(10, 20);         // ga(10, 20, 99) 
ga(10);             // ga(10, 42, 99)
ga(10, None, None); // ga(10, 42, 99)
ga(10, 20, None);   // ga(10, 20, 99)
ga(10, None, 30);   // ga(10, 42, 30)

La règle est que les paramètres Option<T> peuvent être omis. Ici, le type Option est réutilisé, mais si cela cause des problèmes, un autre type OptParam plus spécifique pourrait être créé.

Cette proposition permet à l'appelant de choisir précisément les paramètres qu'il souhaite fournir et ceux qu'il souhaite conserver par défaut, indépendamment de sa position. Aussi, je pense que c'est une bonne chose que la valeur par défaut n'apparaisse pas dans la liste des paramètres. De cette façon, la valeur par défaut n'est pas limitée à une expression constante, elle peut dépendre de l'état de l'objet, ou elle peut dépendre d'autres paramètres.

Exemple réel d'une fonction qui affiche une boîte de dialogue GUI :

fn showDialog(message: ~str,
              parent: Option<Widget>,
              title: Option<~str>,
              type: Option<DialogType>,
              icon: Option<Icon>) { ... }

// Display an info box in the middle of the screen.
// Set the title to "information", translated in the current locale
// Set the icon to an "info" icon
showDialog(~"hello, world!");

// Display a warning box in the middle of the screen.
// Set the title to "warning", translated in the current locale
// Set the icon to a "warning" icon
showDialog(~"sick, sad world!", None, None, WarningDialog);

// Display a warning box in the middle of the screen.
// Set the title to "warning", translated in the current locale
// Set the icon to a custom icon
showDialog(~"sick, sad world!", None, None, WarningDialog, bugIcon);

Dans cet exemple :

  • la valeur par défaut de parent est None (pas de parent)
  • la valeur par défaut de type est InfoDialog
  • la valeur par défaut de icon dépend de la valeur de type
  • la valeur par défaut de title dépend de la valeur de type et de la locale actuelle

Vous proposez maintenant également d'ajouter Option comme nouveau type primitif. C'est entièrement une fonctionnalité de bibliothèque en ce moment, car c'est un vieux enum .

J'aimerais ajouter que les arguments par défaut de l'OMI sont un milliard de fois meilleurs avec les arguments de mot-clé. Je n'aime pas l'idée d'arguments par défaut mais pas d'arguments de mot-clé.

l'un est un tremplin vers l'autre et les valeurs par défaut sont toujours utiles en elles-mêmes, vous avez des indicateurs supplémentaires .. et pouvez les laisser de côté si vous voulez juste les valeurs par défaut.
convenu qu'ils se combinent bien si vous avez les deux.
Le point de friction est en fait de les mettre en œuvre :)
comment le réinstaller dans le vérificateur de type/l'inféreur de type .. ou comment l'insérer autrement.

Les valeurs par défaut des arguments positionnels génèrent un code cryptique. Pourquoi ne pas avoir uniquement des valeurs par défaut pour les arguments de mots clés ? (Si ceux-ci sont mis en œuvre).

OMI ... ce n'est pas "l'un ou l'autre".
Ils sont tous les deux utiles. L'un est plus simple à implémenter, avec moins de choix à faire dans la syntaxe ;
il est donc logique pour nous de le faire, ou d'essayer de le mettre en œuvre en premier, comme un tremplin...

En quoi l'omission des valeurs par défaut est-elle plus cryptique que les appels de fonction normaux ? Les programmeurs C++ sont déjà habitués à trier les paramètres pour cela. Habituellement, une sorte de mot de contrôle avec une valeur par défaut sensée à la fin.. omettez simplement la valeur au lieu d'écrire (..,BLAH_DEFAULT) quoi que ce soit.. clarifie en répertoriant uniquement les informations importantes. Les personnes qui ont besoin de Rust ont probablement déjà utilisé le C++ et y sont donc habituées.

J'ai réalisé plus tôt dans la journée que ma proposition ci-dessus (qui tentait d'exploiter la syntaxe d'extension de structure existante pour fournir quelque chose de proche des arguments par défaut, car je considère que les structures fournissent déjà les ingrédients pour les arguments de mot-clé), ignorait un problème important : la syntaxe que je proposais supposait que l'on serait en mesure de fournir une valeur par défaut pour _every_ argument (et ensuite ils seraient tous élevés dans le paramètre de structure unique).

Ce n'est bien sûr pas vrai en général : on a assez souvent des arguments qui sont obligatoires et d'autres qui sont facultatifs.

J'aimerais quand même trouver un moyen d'exploiter les fonctionnalités que nous avons déjà, plutôt que de mâcher davantage avec la syntaxe de déclaration de fonction, principalement parce que les déclarations de fonction sont _déjà poilues_ grâce aux différentes manières dont on peut écrire des fonctions/fermetures/méthodes.


Mon brainstorming actuel s'est concentré sur la possibilité de tirer parti de la syntaxe de structure existante, peut-être en ajoutant des expressions par défaut pour les champs dans la définition d'un élément de structure. Cela permettrait alors d'avoir certains champs qui pourraient être supprimés et d'autres qui seraient nécessaires. Quelque chose comme:

struct Foo { x: int = 0, y:int = 0, z:int = 0 }

fn bar(f: Foo) {
    printf!(f);
}

struct Baz { x: int, y: int, z:int = 0 }

fn quux(g: Baz} {
    printf!(g);
}

fn main() {
    bar(Foo{y: 5});
    quux(Baz{y: 5}); // ~ERROR: required field, `x`
}

@pnkfelix J'aime cette suggestion, peut-être qu'il ne serait pas trop difficile d'exploiter les mêmes éléments internes mais de générer une structure anonyme. Donc, en prenant votre exemple, ce serait effectivement le même code avec un peu de magie du compilateur pour déduire la structure :

fn bar({ x: int = 0, y:int = 0, z:int = 0 }) {
    printf!(f);
}

fn quux({ x: int, y: int, z:int = 0 }) {
    printf!(g);
}

fn main() {
    bar({ y: 5 });
    quux({ y: 5 }); // ~ERROR: required field, `x`
}

@visionmedia @bstrie Avons-nous vraiment besoin de nous préoccuper de la suppression du nom de la structure ? Une déclaration d'utilisation de reliure ne résout-elle pas le problème des noms longs, en ramenant le nombre minimum de caractères supplémentaires sur le site d'appel à 3 (pour le nom + crochets gauche et droit) ?

C'est-à-dire, avec l'exemple ServerOpts que bstrie m'a posé :

fn main() {
  use O = html::StartServerOptions;
  ...
  html::start_server(O{port: 10088});
}

@pnkfelix j'aime le

struct Foo {
   x: int = 10,
   y: float = 1.0
}

syntaxe, mais je ne pense pas que nous en ayons besoin pour obtenir des arguments obligatoires sensibles (non nommés, malheureusement), il suffit de passer les obligatoires séparément :

struct FooOptions { ... }
static default: FooOptions = FooOptions { ... };
fn foo(compulsory: int, required: uint, necessary: float, optionals: FooOptions) { ... }

FWIW, j'aime aussi l'idée de structure avec des valeurs par défaut. Je suppose que ce serait un raccourci pour :

struct Test {
    m: int,
    y: int
}

static DEFAULT: Test = Test{m: 10, y: 15};

Test{y: 5, ..DEFAULT}

J'aime aussi les valeurs par défaut de la structure dans la définition

J'ai également ces analyses avec cette syntaxe, mais je ne les utilise toujours pas. Je ne connais toujours pas la source du vérificateur de type, etc.

Peut-être que le fait qu'il existe déjà un mécanisme par défaut pourrait le rendre un peu plus facile à mettre en œuvre.

ré. structs anonymes, je pense qu'ils les avaient à l'origine mais ont dû les supprimer «à cause d'interactions étranges»?
Je préférerais avoir les deux mécanismes disponibles. peut-être que les structs de paramètres atténueraient le besoin d'arguments _keyword_, mais les valeurs par défaut comme en c++ seraient toujours pratiques

pour référence -
http://www.parashift.com/c++-faq-lite/named-parameter-idiom.html
lol - des arguments de mots clés intéressants mais vrais éviteraient le besoin de hacks lourds comme celui-ci

ré. structs anonymes, je pense qu'ils les avaient à l'origine mais ont dû les supprimer «à cause d'interactions étranges»?

À l'origine, tous les types de structure étaient structurels. Ils ont été supprimés (remplacés par des types de structure nominaux) en raison d'interactions maladroites avec les traits, je crois.

J'aime les valeurs par défaut dans l'idée des définitions de structure. Cela semble facile à comprendre et évite au moins d'avoir à énumérer chaque champ lors de la construction d'une structure - c'est un problème pour les structures de type "options" car cela signifie que lorsqu'un nouveau champ "facultatif" est ajouté, chaque site d'appel doit être modifié pour initialisez-le à 0/Aucun/etc.

Venant de Perl (où les valeurs par défaut sont un modèle ad-hoc), Python 2 (où vous pouvez obtenir foo() takes at least 2 arguments (2 given) ) et Python 3 (où vous pouvez avoir des arguments nommés uniquement _sans_ valeurs par défaut), je propose humblement : add un _teeny_ peu de sucre pour permettre de déclarer une structure comme argument final d'une fonction, mais laissez l'appelant _inline_ les champs de structure.

par exemple

impl int {
    struct FromStrOptions {
        radix: uint = 10
    }
    fn from_str(s: str, opts: FromStrOptions) -> int {
        // ...
    }
}

int::from_str("4", radix: 10);

Avantages :

  • Pas de nouvelle syntaxe pour la définition de la fonction, qui n'a en fait pas à se soucier de la façon dont l'appelant l'appelle. C'est un peu comme le fait de passer des blocs avec do : c'est purement la préoccupation de l'appelant. (Est-ce qu'il doit y avoir un moyen d'activer/de désactiver, dans le cas d'avoir un dernier argument qui est une structure mais qui n'a pas l'intention de l'utiliser pour les kwargs ? Est-ce que quelqu'un s'en soucie ? Je pense que personne ne se soucie de do .)
  • La disposition binaire et la sémantique des appels C, etc. sont encore assez bien définies.
  • La surcharge par type ou par arité n'est plus difficile à implémenter un jour, sauf que le type de l'argument final ne peut pas contribuer à la surcharge de type. Ne devrait pas non plus interférer avec les arguments variadiques, si jamais ceux-ci se produisent.
  • Le même ensemble de valeurs par défaut peut être réutilisé dans plusieurs fonctions.
  • Quelque chose comme **kwargs gratuitement : créez simplement la structure et transmettez-la plutôt en tant qu'argument positionnel.
  • Les arguments de mot-clé requis en découlent naturellement : ne donnez simplement pas de valeur par défaut dans la structure et vous êtes obligé de passer _quelque chose_ par nom.
  • Pas de confusion farfelue lors du passage d'arguments positionnels par nom ; tu ne peux pas faire ça.

Désavantages:

  • Un peu magique. Mais pas plus que de passer 5 et d'avoir le type déduit de l'argspec de la fonction, je pense.
  • On ne sait pas comment il interagirait avec l'idiome do existant. Il peut être assez facile de dire que ce doit être le dernier argument _écrit_, c'est-à-dire qu'il fonctionne comme l'avant-dernier argument uniquement lorsqu'il est utilisé avec do .

FWIW int::from_str("4", radix: 10) serait en conflit avec l'utilisation, précédemment proposée, de : comme opérateur d'attribution de type.

Malédictions, déjouées par ASCII.

int::from_str("4", radix☃ 10)

je voterais pour l'utilisation de = pour les arguments de mot-clé, rejette simplement l'idée de C des affectations dans les sous-expressions. exemple possible de la façon dont il s'intègre dans une syntaxe de type c ?

Y a-t-il un endroit pour réfléchir à la façon d'implémenter tout cela. Je me suis demandé si le style de variable argumentmnt pouvait être implémenté en interne comme une surcharge de fonction basée sur le nombre d'arguments (presque comme si le nombre d'arguments était postfixé sur le nom de la fonction .. )

Nous en avons parlé hier soir lors de la

Je pense que tout le monde a convenu qu'une complication supplémentaire aux formulaires de déclaration/invocation de fonction n'est pas bonne, et que l'extension des déclarations de structure pour permettre les valeurs par défaut des champs (associées aux expressions const), comme suggéré dans mon commentaire précédent , serait un moyen raisonnable d'obtenir une majorité de ce qui est souhaité ici.

L'équipe a également décidé que résoudre ce problème de quelque manière que ce soit n'est pas une priorité pour la version 1.0. Le chef de projet @brson a suggéré que nous

C'est donc un indice fort pour tous les contributeurs : piratez tout ce que vous voulez, mais s'il vous plaît, ne soumettez pas de demandes d'extraction ou ne faites rien pour ce bogue avant la publication post 1.0.

De loin, Rust est un langage incroyable. Il fait tellement de choses correctement que ce n'est même pas drôle. Mais je pense que reporter cette fonctionnalité pour la publication 1.0 est une erreur.

Permettez-moi d'élaborer.

Les arguments de fonction par défaut sont _critiques_ pour une bonne conception d'API ; leur absence complique ce qui serait autrement des API plus simples. Exemples de la bibliothèque std :

Et d'autres.

Le fait d'avoir tous ces noms de fonctions supplémentaires qui pourraient être supprimés avec des arguments par défaut augmente inutilement la charge cognitive. L'utilisateur doit maintenant connaître deux (ou plus) noms au lieu d'un.

Si les arguments par défaut sont reportés après la version 1.0, ces fonctions de la bibliothèque std ne peuvent pas être supprimées en raison de la rétrocompatibilité. Cela signifie que même si des arguments par défaut sont ajoutés à l'avenir et que la version "vanille" des fonctions peut désormais faire le travail des autres variantes, les anciennes variantes resteront et les développeurs devront les connaître car quelqu'un les utilisera certainement eux, ne serait-ce que par erreur.

Ainsi, cette charge cognitive supplémentaire restera _pour toujours_.

[NB Le même argument peut être avancé pour la surcharge de fonction basée sur le type de paramètre (la solution de contournement actuelle basée sur les traits est trop lourde et les fonctions de la bibliothèque std ne l'utilisent pas), mais ce problème n'est pas le lieu pour cette discussion.]

Les développeurs de Rust, merci d'avoir travaillé sur Rust et de l'avoir rendu génial !

J'ajoute le jalon « futur lointain » pour souligner le découragement extrême que nous, l'équipe de base, souhaitons communiquer à quiconque passe une seconde de temps sur cette question. Si vous souhaitez contribuer à Rust dès maintenant, veuillez vous attaquer à l'un des 41 bogues ouverts au jalon 1 (bien défini) :

https://github.com/mozilla/rust/issues?milestone=12&state=open

ou l'un des 104 bugs ouverts au jalon 2 (compatibilité descendante) :

https://github.com/mozilla/rust/issues?milestone=13&state=open

ou l'un des 68 bogues ouverts au jalon 3 (les fonctionnalités que nous avons convenues à un moment donné sont cruciales pour la publication de Rust 1.0) :

https://github.com/mozilla/rust/issues?milestone=14&state=open

ou même simplement commenter l'un de ces bogues pour demander des éclaircissements ou suggérer des moyens de progresser. C'est 213 bogues à choisir ; faire des progrès sur l'un d'entre eux à ce stade serait beaucoup plus précieux pour Rust que ce problème. Et quiconque pourra fermer l'un de ces bogues aura notre plus grande gratitude.

Je peux voir que l'équipe de base a des choses bien plus importantes à faire, mais il semble dommage de « communiquer un découragement extrême » :(
+1 aux commentaires vallorics. nommer est difficile, creuser dans la documentation et apprendre plus de noms est rebutant .. ; les arguments par défaut/la surcharge facilitent les choses ; avec des arguments de mot-clé, vous auriez la possibilité d'aller au-delà du C++ sur ce point. (J'aurais aimé que github vote, je pourrais juste appuyer sur +1 au lieu de fulminer un peu plus ici lol)

@Valloric Je suis entièrement d'accord (comme je l'ai déjà dit) et j'espère vraiment que l'équipe de base de

Il n'y a pas de consensus sur le fait que ce serait une bonne fonctionnalité de langage. Il n'y a pas non plus de proposition concrète avec tous les détails élaborés pour les paramètres nommés/par défaut. Cela n'arrivera pas pour la version 1.0, car il existe un ensemble existant de fonctionnalités de base des langages à corriger ou à supprimer avant d'imaginer du sucre syntaxique très inutile.

« rêver » donne l'impression que c'est quelque chose de fantaisiste, mais ces fonctionnalités ont été prouvées dans d'autres langues. Ce n'est pas seulement du sucre de syntaxe - cela réduit la quantité de code que vous devez parcourir, réduisant le nombre de symboles que vous devez apprendre

Cela n'arrivera pas pour la version 1.0, car il existe un ensemble existant de fonctionnalités de base des langages à corriger ou à supprimer avant d'imaginer du sucre syntaxique très inutile.

Je ne dis pas que les autres fonctionnalités du langage qui doivent être corrigées/implémentées ne sont pas plus importantes ; ils le sont probablement. Mais ce n'est pas l'un ou l'autre. Tout ce que je dis, c'est que cette fonctionnalité devrait être fortement considérée pour la 1.0 (en plus des autres fonctionnalités) car ne pas l'avoir a un impact sur la qualité des API dans la bibliothèque std _forever_.

C'est probablement une opinion controversée, mais les langages de programmation IMO vivent et meurent plus par les API qu'ils fournissent que par leurs fonctionnalités de base. La bibliothèque std "piles incluses" de Python a vendu l'intégralité du langage. CPAN maintient Perl en vie. .Net rend l'écriture de code C# géniale, et LINQ est la meilleure chose depuis le pain tranché. L'un des plus gros défauts du C++ est le manque de bonnes API standardisées. Etc.

Les API sont essentielles au succès d'un langage, de sorte que les fonctionnalités qui permettent la création de _bonnes_ API ne doivent pas être rejetées comme « sucre syntaxique non essentiel ».

@dobkeratops : en disant _rêver_, j'essaie de souligner qu'aucune proposition complète n'a été faite donc ce n'est pas à une étape décisionnelle

Cette discussion est improductive. Pour éviter que cela ne fasse perdre plus de temps à qui que ce soit, je vais clore le sujet. Si quelqu'un veut le rouvrir (ou commencer un nouveau numéro) dans un an, ou plus tard, ce serait bien.

Si quelqu'un fait une proposition avec presque tous les détails élaborés (grammaire, sémantique), je suggère de la poster sur la liste de diffusion. Si un consensus est atteint sur une certaine manière de faire cela étant la _bonne manière_, alors il est logique d'ouvrir un problème et de l'implémenter en tant que fonctionnalité expérimentale derrière un indicateur comme les fonctions once .

Je seconde @thestinger -- si quelqu'un (ou un petit groupe de personnes) a une proposition complète, ou une proposition avec quelques blancs clairement épelés qui sont à discuter, il serait approprié que cette personne l'exécute par la liste de diffusion. Ce n'est pas une promesse que nous mettrons en œuvre cette proposition, mais faire le travail de formalisation de l'idée et d'expliquer comment elle interagit avec d'autres fonctionnalités du langage augmenterait considérablement la valeur de la suggestion.

@thestinger @catamorphism Merci à vous deux de garder l'esprit ouvert ! Quand je trouverai un peu de temps, je préparerai une proposition et l'enverrai à rust-dev.

J'ai créé un pad afin de débattre de cette fonctionnalité et d'écrire une spécification claire à ce sujet : https://pad.riseup.net/p/hvbg6dQQnEe7

Je rouvre ça. Ce n'est pas une priorité - il y a déjà beaucoup trop à faire - mais c'est une fonctionnalité que les gens veulent, et ce n'est pas complètement exclu. Je ne souhaite mettre fin à aucune conversation sur le sujet.

@brson Merci !

J'ai édité le problème d'origine avec un lien vers l'etherpad.

Salut.
Depuis la création du pad, il a été complété par de nombreuses propositions de design, questions, problèmes, etc...
J'ai donc créé un deuxième bloc pour "résumer" le bloc de discussion, ce bloc sera utilisé pour décrire exactement la demande de fonctionnalité.
URL du pad ici : https://pad.riseup.net/p/Ca5PBeDjUGxW

@KokaKiwi, tous les tampons sont vides maintenant. Où est passé le contenu ?

@cmr , je suppose:

AVERTISSEMENT : ce bloc-notes sera SUPPRIMÉ si 30 jours se sont écoulés sans aucune modification. Il n'y a AUCUN MOYEN de récupérer le tampon après que cela se produise, alors soyez prudent !

:renfrogné:

Je cherche en fait le pad que j'ai créé sur l'instance Mozilla Etherpad (afin d'éviter ce cas), mais je ne le trouve pas dans mon historique, et j'ai oublié de publier le lien ici :(

@cmr @huonw @KokaKiwi , voici deux liens dans l'historique de mon navigateur :

https://etherpad.mozilla.org/CQEDa85jLX
https://etherpad.mozilla.org/78FA1bozLd

@dram C'est ce que je cherchais ! Merci :souriant:
Peut-être que le problème devrait être modifié avec les nouveaux liens, je pense.

(Édité.)

Je n'ai rien de significatif à ajouter à part que c'est l'une des choses que je surveille de près avant d'investir plus de temps avec la langue. Issu des langages (Objective-C et Python) dotés de cette fonctionnalité, je pense que les paramètres nommés sont un coup de pouce indirect majeur à la productivité en raison de la façon dont ils forcent le code des autres à être plus lisible.

Une proposition concrète doit être faite via le nouveau processus RFC : https://github.com/rust-lang/rfcs

Il y a trop d'idées contradictoires et de fils de conversation divergents ici pour que ce soit un espace de discussion utile.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

withoutboats picture withoutboats  ·  211Commentaires

cramertj picture cramertj  ·  512Commentaires

nikomatsakis picture nikomatsakis  ·  340Commentaires

withoutboats picture withoutboats  ·  213Commentaires

thestinger picture thestinger  ·  234Commentaires