web-dev-qa-db-fra.com

Pourquoi les prototypes de fonction de Perl 5 sont-ils mauvais?

Dans ne autre question Stack OverflowLeon Timmermans a affirmé:

Je vous conseillerais de ne pas utiliser de prototypes. Ils ont leurs utilisations, mais pas dans la plupart des cas et certainement pas dans celui-ci.

Pourquoi cela pourrait-il être vrai (ou autre)? Je fournis presque toujours des prototypes pour mes fonctions Perl, et je n'ai jamais vu quelqu'un d'autre dire quoi que ce soit de mauvais à propos de leur utilisation.

116
Alnitak

Les prototypes ne sont pas mauvais s'ils sont utilisés correctement. La difficulté est que les prototypes de Perl ne fonctionnent pas comme les gens attendent souvent d'eux. Les personnes ayant une expérience dans d'autres langages de programmation ont tendance à s'attendre à ce que les prototypes fournissent un mécanisme pour vérifier que les appels de fonction sont corrects, c'est-à-dire qu'ils ont le bon nombre et le bon type d'arguments. Les prototypes de Perl ne sont pas bien adaptés à cette tâche. C'est le abus c'est mauvais. Les prototypes de Perl ont un objectif singulier et très différent:

Les prototypes vous permettent de définir des fonctions qui se comportent comme des fonctions intégrées.

  • Les parenthèses sont facultatives.
  • Le contexte est imposé aux arguments.

Par exemple, vous pouvez définir une fonction comme celle-ci:

sub mypush(\@@) { ... }

et l'appelle comme

mypush @array, 1, 2, 3;

sans avoir besoin d'écrire le \ pour prendre une référence au tableau.

En résumé, les prototypes vous permettent de créer votre propre sucre syntaxique. Par exemple, le framework Moose les utilise pour émuler une syntaxe OO plus typique.

C'est très utile mais les prototypes sont très limités:

  • Ils doivent être visibles au moment de la compilation.
  • Ils peuvent être contournés.
  • La propagation du contexte aux arguments peut provoquer un comportement inattendu.
  • Ils peuvent rendre difficile l'appel de fonctions en utilisant autre chose que la forme strictement prescrite.

Voir Prototypes dans perlsub pour tous les détails sanglants.

121
Michael Carman

Le problème est que les prototypes de fonction de Perl ne font pas ce que les gens pensent qu'ils font. Leur but est de vous permettre d'écrire des fonctions qui seront analysées comme les fonctions intégrées de Perl.

Tout d'abord, les appels de méthode ignorent complètement les prototypes. Si vous faites de la programmation OO, peu importe le prototype de vos méthodes (elles ne devraient donc pas avoir de prototype).)

Deuxièmement, les prototypes ne sont pas strictement appliqués. Si vous appelez un sous-programme avec &function(...), le prototype est ignoré. Ils n'offrent donc pas vraiment de sécurité de type.

Troisièmement, ils sont effrayants à distance. (Surtout le prototype $, Qui fait évaluer le paramètre correspondant dans un contexte scalaire, au lieu du contexte de liste par défaut.)

En particulier, ils rendent difficile la transmission de paramètres à partir de tableaux. Par exemple:

my @array = qw(a b c);

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

sub foo ($;$$) { print "@_\n" }

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

impressions:

a b c
a b
a b c
3
b
a b c

ainsi que 3 avertissements concernant main::foo() called too early to check prototype (si les avertissements sont activés). Le problème est qu'un tableau (ou tranche de tableau) évalué dans un contexte scalaire renvoie la longueur du tableau.

Si vous devez écrire une fonction qui agit comme une fonction intégrée, utilisez un prototype. Sinon, n'utilisez pas de prototypes.

Remarque: Perl 6 aura des prototypes entièrement repensés et très utiles. Cette réponse s'applique uniquement à Perl 5.

69
cjm

Je suis d'accord avec les deux affiches ci-dessus. En général, en utilisant $ devrait être évité. Les prototypes ne sont utiles que lorsque vous utilisez des arguments de bloc (&), globes (*) ou des prototypes de référence (\@, \$, \%, \*)

30
Leon Timmermans

Certaines personnes, en regardant un prototype de sous-programme Perl, pensent que cela signifie quelque chose qu'il ne fait pas:

sub some_sub ($$) { ... }

Pour Perl, cela signifie que l'analyseur attend deux arguments. C'est la manière de Perl de vous laisser créer des sous-programmes qui se comportent comme des éléments intégrés, qui savent tous à quoi s'attendre du code suivant. Vous pouvez lire sur les prototypes dans perlsub

Sans lire la documentation, les gens pensent que les prototypes font référence à la vérification des arguments au moment de l'exécution ou à quelque chose de similaire qu'ils ont vu dans d'autres langues. Comme pour la plupart des choses que les gens pensent de Perl, ils se trompent.

Cependant, à partir de Perl v5.20, Perl a une fonctionnalité, expérimentale au moment où j'écris ceci, qui donne quelque chose de plus comme ce que les utilisateurs attendent et quoi. Perl's sous-routine signatures exécute le comptage des arguments de temps, l'affectation des variables et le réglage par défaut:

use v5.20;
use feature qw(signatures);
no warnings qw(experimental::signatures);

animals( 'Buster', 'Nikki', 'Godzilla' );

sub animals ($cat, $dog, $lizard = 'Default reptile') { 
    say "The cat is $cat";
    say "The dog is $dog";
    say "The lizard is $lizard";
    }

C'est la fonctionnalité que vous souhaitez probablement si vous envisagez des prototypes.

4
brian d foy