2010-06-08 7 views
4

J'essaie de comprendre le comportement du pragma fields, que je trouve poorly documented, en ce qui concerne les champs préfixés par des traits de soulignement. C'est ce que la documentation doit dire à son sujet:Dans quelles circonstances les variables d'instance sont-elles déclarées comme '_var' dans 'use fields' private?

Field names that start with an underscore character are made private to the class and are not visible to subclasses. Inherited fields can be overridden but will generate a warning if used together with the -w switch.

Ce ne correspond pas à son comportement réel, d'après mon test, ci-dessous. Non seulement les champs préfixés _ sont visibles dans une sous-classe, mais ils sont également visibles dans les classes étrangères (à moins que je n'obtienne ce que 'visible' signifie). En outre, accéder directement au hachage restreint fonctionne correctement.

Où puis-je trouver plus d'informations sur le comportement du pragma fields, sans aller au code source?

{ 
    package Foo; 
    use strict; 
    use warnings; 
    use fields qw/a _b __c/; 

    sub new { 
     my ($class) = @_; 
     my Foo $self = fields::new($class); 
     $self->a = 1; $self->b = 2; $self->c = 3; 
     return $self; 
    } 

    sub a : lvalue { shift->{a} } 
    sub b : lvalue { shift->{_b} } 
    sub c : lvalue { shift->{__c} } 
} 
{ 
    package Bar; 
    use base 'Foo'; 
    use strict; 
    use warnings; 
    use Data::Dumper; 

    my $o = Bar->new; 
    print Dumper $o; ##$VAR1 = bless({'_b' => 2, '__c' => 3, 'a' => 1}, 'Foo'); 

    $o->a = 4; $o->b = 5; $o->c = 6; 
    print Dumper $o; ##$VAR1 = bless({'_b' => 5, '__c' => 6, 'a' => 4}, 'Foo'); 

    $o->{a} = 7; $o->{_b} = 8; $o->{__c} = 9; 
    print Dumper $o; ##$VAR1 = bless({'_b' => 8, '__c' => 9, 'a' => 7}, 'Foo'); 
} 

Répondre

7

assez pure coïncidence, j'arrive d'avoir un script de test dans ~/codescraps/fields/test.pl daté il y a deux ans quand j'expérimenté avec répondant exactement cette même question. :)

#!/usr/bin/perl 

use strict; 
use warnings; 

use Data::Dumper; 

{ 
    package Foo; 
    use fields qw(foo bar _Foo_private); 
    use private qw(_really_private); 
    sub new { 
     my Foo $self = shift; 
     unless (ref $self) { 
      $self = fields::new($self); 
      $self->{_Foo_private} = "this is Foo's secret"; 
     } 
     $self->{foo} = 10; 
     $self->{bar} = 20; 
     return $self; 
    } 
} 

my $foo = Foo->new; 
$foo->{foo} = 42; 

# this will generate an error: field does not exist 
#$foo->{zap} = 42; 

print "_Foo_private: " . $foo->{_Foo_private} . "\n"; 
$foo->{_Foo_private} = 1; 
print "_Foo_private: " . $foo->{_Foo_private} . "\n"; 

print "_really_private: " . $foo->{_really_private} . "\n"; 
$foo->{_really_private} = 1; 
print "_really_private: " . $foo->{_really_private} . "\n"; 

print Dumper($foo); 

# subclassing 
{ 
    package Bar; 
    use base 'Foo'; 
    use fields qw(baz _Bar_private);  # these fields not shared with Foo 
    sub new { 
     my $class = shift; 
     my $self = fields::new($class); 
     $self->SUPER::new();    # init base fields 
     $self->{baz} = 10;     # init own fields 
     $self->{_Bar_private} = "this is Bar's secret"; 
     return $self; 
    } 
} 

my $bar = Bar->new; 
# these work fine 
$bar->{foo} = 1; 
$bar->{bar} = 1; 
$bar->{_Bar_private} = 1; 

# this will not work - underscored fields are not visible to children 
$bar->{_Foo_private} = 1; 

Et quand je lance votre code, je reçois l'erreur:

No such pseudo-hash field "_b" at test2.pl line 16. 

(ligne 16 est la définition de la sous b.) Quelle architecture vous exécutez ce sur? Les objets utilisant les champs pragma ne sont pas de simples hashrefs bénis - ils sont bénis arrayrefs, par ex. quand je modifie votre constructeur pour ressembler à ceci:

sub new { 
    my ($class) = @_; 
    my Foo $self = fields::new($class); 
    $self->{a} = 1; $self->{_b} = 2; $self->{__c} = 3; 
    print "I look like: ", Data::Dumper::Dumper($self); 
    return $self; 
} 

Je vois:

I look like: $VAR1 = bless([ 
       bless({ 
          'a' => 1 
         }, 'pseudohash'), 
       1, 
       2, 
       3 
       ], 'Bar'); 

En post-scriptum, je me sens obligé de souligner que le fields pragma, et le base Pragma va avec, sont à la fois obsolètes et on est fortement encouragé à éviter de les utiliser. De nos jours, si vous cherchez à construire un joli module OO avec des accesseurs, on utiliserait soit Class::Accessor soit directement Moose.

+0

Merci pour votre réponse. Je cours x86_64, debian et perl 5.10. Je dois également souligner que, pour autant que je sache, les «champs» ne sont pas du tout déconseillés. Cependant, depuis la version 5.9, son implémentation a cessé d'utiliser des pseudo-hachages en faveur des hachages restreints. Et moi aussi, j'ai une copie de OO Perl de Conways; Je connais certainement les alternatives aux «champs» et aux «bases». Comme je l'ai dit, je veux juste comprendre les pragmas, et la documentation manque. –

+2

@Pedro: oui, ils seront disponibles pendant un certain temps, mais pas vraiment supportés; En fait, j'ai posé une question ici à propos de 'fields' moi-même, il y a un moment: http://stackoverflow.com/questions/1168644/why-is-the-fields-pragma-incompatible-with-multiple-inheritance-in-perl - - et a reçu les mêmes réponses "utiliser Moose à la place". :) – Ether

Questions connexes