В каких случаях переменные экземпляра объявляются как _var в закрытых полях использования?

Я пытаюсь понять поведение прагмы fields, которая, по моему мнению, плохо документирована, относительно поля с префиксом подчеркивания. Вот что об этом говорится в документации:

Имена полей, начинающиеся с символа подчеркивания, делаются частными для класса и не видны для подклассов. Унаследованные поля можно переопределить, но при использовании вместе с ключом -w будет выдано предупреждение.

Это не согласуется с его реальным поведением, согласно моему тесту ниже. Поля с префиксом _ видны не только внутри подкласса, но и внутри внешних классов (если только я не понимаю, что означает «видимый»). Кроме того, прямой доступ к ограниченному хешу работает нормально.

Где я могу узнать больше о поведении прагмы fields, если не считать исходный код?

{
    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');
}

person Pedro Silva    schedule 08.06.2010    source источник


Ответы (1)


По стечению обстоятельств, у меня есть тестовый сценарий в ~/codescraps/fields/test.pl, датированный два года назад, когда я экспериментировал с ответом точно на этот же вопрос. :)

#!/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;

И когда я запускаю ваш код, я получаю сообщение об ошибке:

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

(строка 16 — это определение подпункта b.) На какой архитектуре вы это используете? Объекты, использующие прагму fields, не являются простыми благословенными хэш-ссылками — они являются благословенными ссылками-массивами, например. когда я изменяю ваш конструктор, чтобы он выглядел так:

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

Я понимаю:

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

В качестве постскриптума я чувствую себя обязанным указать, что прагма fields и base, которая идет вместе с ней, устарела, и настоятельно рекомендуется избегать их использования. В настоящее время, если вы хотите создать хороший объектно-ориентированный модуль с аксессорами, можно использовать либо Class ::Доступ или перейдите непосредственно к Moose.

person Ether    schedule 08.06.2010
comment
Спасибо за ответ. Я использую x86_64, debian и perl 5.10. Я также должен указать, что, насколько я знаю, fields вообще не устарел. Однако, начиная с версии 5.9, его реализация перестала использовать псевдохэши в пользу ограниченных хэшей. У меня тоже есть экземпляр OO Perl Конвея; Я, конечно, знаю об альтернативах «полям» и «базе». Как я уже сказал, я просто хочу понять прагмы, а документации не хватает. - person Pedro Silva; 09.06.2010
comment
@Pedro: да, они будут доступны в течение некоторого времени, но больше не поддерживаются; Некоторое время назад я действительно задал здесь вопрос о себе fields: -perl" title="почему прагма fields несовместима с множественным наследованием в perl">stackoverflow.com/questions/1168644/ -- и вместо этого получил то же самое использование Moose. :) - person Ether; 09.06.2010