Неблагородные объекты Perl - ужасный дизайн?

Неужели небессмысленные объекты Perl означают ужасный дизайн?
Если да, может кто-нибудь объяснить это мне?
Кстати, вот обсуждение, которое вызвало этот вопрос, проверьте комментарии на вопрос

4 ответа

Нуждаясь unbless конечно поднимает брови. Поскольку вы все еще можете использовать объект в качестве исходной структуры данных, это почти никогда не требуется.

Модули, которые разборчивы в получении необъявленных ссылок на хеш-объекты по сравнению с объектами, как правило, имеют опции, чтобы не быть такими разборчивыми, например, allow_blessed и convert_blessed в JSON.

Одно приложение - это объект, реализованный в виде хеш-ссылки, и вы также хотите перегрузить %{} оператор разыменования [EDIT: и вы также хотите поддерживать Perls старше v5.10.1 - в противном случае вы должны просто использовать no overloading.]

package Foo;
use overload '+' => sub { $_[0]->get + $_[1] },
             ...,
             '%{}' => sub { return { foo => "bar", this => $_[0] } },
             ...;

Теперь для любого$fooэто имеет типFoo, пытаясь получить доступ к элементу, как $foo->{$key} вызовет ваш перегруженный %{}метод, и ваш доступ не удастся.

Обходной путь - временно изменить тип вашего объекта при доступе к члену вашего объекта и вернуть его обратно, когда вы закончите. Вы можете сделать это, отбрасывая свой объект, но это чаще делается (и легче сделать), благословляя его до мусорной стоимости.

sub Foo::bar {   # access 'bar' member of Foo object
  my $self = shift;
  # $self->{bar} will invoke Foo::{'%{}'}, and we don't wan't that

  my $ref = ref $self;
  unbless($self);    #   or  bless $self, 'Not::An::Object::Name'
  # now $self->{bar} is accessible

  my $value = $self->{bar};
  bless $self, $ref;        # restore object type
  return $value;
}

Другой пример приведен в разделе "Ссылки на два лица" вoverload


Я использую этот шаблон здесь, для другого примера.

Это пустой и глупый вопрос. У вас нет цели для unbless но случайно выбрали его из неясного модуля CPAN, чтобы спросить, почему он отражает плохой дизайн. Вы можете также спросить, как объявить переменную, которая была объявлена ​​с my, Это также вполне возможно в коде XS, но я надеюсь, что это довольно глупо?

У меня проблема с unbless является то, что вы создали структуру данных - от скалярной переменной или дескриптора файла до вложенного хеша или массива - и назвали bless чтобы Perl знал, как разрешать вызовы методов для этого объекта

Так что теперь вы хотите unbless Это. Это оставит данные нетронутыми, и основное отличие будет в том, что любые вызовы методов теперь будут приводить к фатальной ошибке.

Can't call method ... on unblessed reference

Так какой был твой unbless за? Если вы полагаетесь на Perl, чтобы дать вам эту фатальную ошибку, то это так же легко назначить undef к объекту, который вызывает эту фатальную ошибку вместо

Can't call method ... on an undefined value

но имеет то преимущество, что ваша структура данных может быть разрушена, чтобы освободить память

Если вы хотите что-то более твердое, то, потому что ссылки могут быть переданы на несколько разделов кода, unbless был бы примером действия на расстоянии, которое дискредитируется гораздо большим количеством людей, чем я

Я думаюunblessполезно, когда я хочу сохранить данные объекта, а не данные объекта с именем класса; именно тогда, когда природа данных вашего объекта предназначена для производственных данных, а не для ссылки на сам объект для работы.

      package My::Pkg;
use Storable qw/dclone/;
use Data::Structure::Util qw/unbless/;

sub _distribute_private_attr { 
 $_[0]->{_private_attrs} = {...}
}

sub new {
 my $obj = bless { Foo => [qw/bar/] };
 $obj->_distribute_private_attr();
 return $obj;
}

sub load {
 my $cls = shift;
 my $data = retrieve $_[0];
 my $obj = bless $data, $cls;
  $obj->_distribute_private_attr();
 return $obj
}

sub save {
 my $obj = shift;
 my $data = unbless ( dclone $obj );
 delete $data->{_private_attrs};
 store $data, $_[0];
}
1;

package main;
use Some::Other::Mod;

my $obj = My::Pkg -> new;
$obj->{Bar} = "Baz";
$obj->save ("someFile");

my $obj2 = My::Pkg->load("someFile"); # Now we can do this
my $obj3 = Some::Other::Mod->load("someFile"); # or this
my $data = retrieve "someFile"; # or this

И теперь сохраненная структура данных может использоваться другими, не вмешиваясь в другие вещи класса, но при этом ничто не испортило экземпляр среды выполнения.

Другие вопросы по тегам