2008-11-17 9 views
110

En another Stack Overflow questionLeon Timmermans afirmó:¿Por qué son malos los prototipos de la función Perl 5?

Te aconsejaría no utilizar prototipos. Tienen sus usos, pero no para la mayoría de los casos y definitivamente no en este.

¿Por qué podría ser esto cierto (o no)? Casi siempre proporciono prototipos para mis funciones de Perl, y nunca antes había visto a nadie decir algo malo sobre su uso.

+0

Tengo curiosidad también. La única vez que no los uso es cuando estoy llamando con una cantidad variable de argumentos. –

+7

Le recomiendo que lea el artículo, ["Prototipos de Perl considerados dañinos"] (http://www.perlmonks.org/?node_id=861966)? – tchrist

Respuesta

116

Los prototipos no son malos si se usan correctamente. La dificultad es que los prototipos de Perl no funcionan de la forma en que la gente a menudo espera que lo hagan. Las personas con experiencia en otros lenguajes de programación tienden a esperar que los prototipos proporcionen un mecanismo para verificar que las llamadas a funciones sean correctas: es decir, que tengan el número y el tipo de argumentos correctos. Los prototipos de Perl no son adecuados para esta tarea. Es el mal uso eso es malo. Los prototipos de Perl tienen un propósito singular y muy diferente:

Los prototipos le permiten definir funciones que se comportan como funciones incorporadas.

  • Los paréntesis son opcionales.
  • El contexto se impone en los argumentos.

Por ejemplo, se podría definir una función como esta:

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

y llamarlo como

mypush @array, 1, 2, 3; 

sin necesidad de escribir el \ para tomar una referencia a la matriz.

En pocas palabras, los prototipos te permiten crear tu propio azúcar sintáctico. Por ejemplo, el framework Moose los usa para emular una sintaxis OO más típica.

Esto es muy útil, pero los prototipos son muy limitadas:

  • Tienen que ser visible en tiempo de compilación.
  • Se pueden omitir.
  • Propagar el contexto a los argumentos puede provocar un comportamiento inesperado.
  • Pueden hacer que sea difícil llamar a funciones que utilicen otra cosa que no sea el formulario estrictamente prescrito.

Ver Prototypes en perlsub para todos los detalles sangrientos.

+2

He aceptado esta respuesta porque creo que es la que mejor responde a la pregunta: los prototipos no son intrínsecamente malos, es solo la forma de usarlos. – Alnitak

+2

Prototipos de alces por otro lado, son/awesome/http://p3rl.org/MooseX::Declare http://p3rl.org/MooseX::Method::Signatures –

+13

[Mucho más que todo lo que siempre quiso saber sobre Prototipos de Perl] (http://www.perlmonks.org/?node_id=861966). – tchrist

66

El problema es que los prototipos de función de Perl no hacen lo que las personas piensan que hacen. Su propósito es permitirle escribir funciones que serán analizadas como las funciones integradas de Perl.

En primer lugar, las llamadas a métodos ignoran por completo los prototipos. Si estás haciendo programación OO, no importa qué prototipo tengan tus métodos. (Por lo tanto, no deberían tener ningún prototipo.)

En segundo lugar, los prototipos no se aplican estrictamente. Si llama a una subrutina con &function(...), se ignora el prototipo. Entonces, realmente no proporcionan ningún tipo de seguridad.

En tercer lugar, son espeluznantes de acción a distancia. (Especialmente el prototipo $, que hace que el parámetro correspondiente se evalúe en contexto escalar, en lugar del contexto de lista predeterminado.)

En particular, dificultan la transferencia de parámetros desde las matrices. Por ejemplo:

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]); 

impresiones:

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

junto con 3 advertencias sobre main::foo() called too early to check prototype (si están habilitadas las advertencias). El problema es que una matriz (o porción de matriz) evaluada en contexto escalar devuelve la longitud de la matriz.

Si necesita escribir una función que funciona como un built-in, use un prototipo. De lo contrario, no use prototipos.

Nota: Perl 6 tendrá prototipos completamente renovados y muy útiles. Esta respuesta solo se aplica a Perl 5.

+0

Pero aún proporcionan una verificación útil de que su interlocutor y el sub utilizan la misma cantidad de argumentos, entonces, ¿qué hay de malo en eso? –

+0

ese es el punto de mi pregunta: nunca utilizo la sintaxis old & func, por lo que el prototipo proporciona una función útil de verificación de parámetros de función. – Alnitak

+2

No; el consenso general es que los prototipos de la función Perl no proporcionan esencialmente ningún beneficio. También puede no molestarse con ellos, al menos en Perl 5. Perl 6 podría ser una historia diferente (mejor). –

29

Estoy de acuerdo con los dos carteles anteriores. En general, se debe evitar usar $. Los prototipos son sólo útiles cuando se usan parámetros de bloque (&), pegotes (*), o prototipos de referencia (\@, \$, \%, \*)

+0

En general, tal vez, pero me gustaría mencionar dos excepciones: Primero, el prototipo '($)' crea un operador unario con nombre, que puede ser útil (ciertamente Perl los encuentra útiles, yo también, en ocasiones). En segundo lugar, al anular complementos incorporados (ya sea mediante importación o utilizando CORE :: GLOBAL: :), en general debe apegarse al prototipo que tenga el built-in, incluso si incluye un '$', o puede sorprender al programador (usted mismo, incluso) con contexto de lista donde el built-in de otro modo proporcionaría un contexto escalar. –

1

Algunas personas, mirando a un prototipo subrutina Perl, piensa que significa algo que doesn 't:

sub some_sub ($$) { ... } 

Para Perl, eso significa que el analizador espera dos argumentos. Es la forma de Perl de permitirle crear subrutinas que se comporten como integradas, todas las cuales saben qué esperar del siguiente código. Puede leer sobre prototipos en perlsub

Sin leer la documentación, la gente adivina que los prototipos se refieren a la comprobación de los argumentos de tiempo de ejecución o algo similar que han visto en otros idiomas. Como con la mayoría de las cosas que las personas adivinan sobre Perl, resultan estar equivocadas.

Sin embargo, comenzando con Perl v5.20, Perl tiene una característica, experimental mientras escribo esto, que da algo más como lo que los usuarios esperan y qué. Perl de subroutine signatures se ejecuta el conteo de tiempo argumento, asignación variable y ajuste por defecto:

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"; 
    } 

Ésta es la característica es probable que desee si está considerando prototipos.

Cuestiones relacionadas