http://qs321.pair.com?node_id=11106234


in reply to Language design: direct attribute access and postponed mutators (Perl Vs Python)

Update: is Variable::Magic an option?

Probably yes, since the following also relies on perl magic.

are there better options in Perl to upgrade the easier interface?

Can't think of any. This approach is nice since it allows you define interactions between attributes of objects in a succinct way. To rule out the usage of $object->{attribute} = $value I'd go with Hash::Util::FieldHash which makes the implementation of attributes opaque. Example:

test file...
use Test::More; use Scalar::Util qw(reftype); my $n_tests; use_ok('Person'); BEGIN{ $n_tests++ } # OBJECT # instantiate object my $p = Person->new; is(ref $p, 'Person', 'object is Person'); is(reftype $p, 'SCALAR', 'object type is SCALAR'); BEGIN { $n_tests += 2 } # set fullname by setting given and surname $p->given = 'Xaver'; is($p->fullname, 'Xaver', 'fullname is givenName only'); $p->surname = 'Unsinn'; is($p->fullname, 'Xaver Unsinn','fullname is "givenName surname"'); BEGIN { $n_tests += 2 } # set given and surname by setting fullname $p->fullname = 'John Doe'; is($p->given, 'John', 'givenName is set after setting ful +lname'); is($p->surname, 'Doe', 'surname is set after setting fulln +ame'); BEGIN { $n_tests += 2 } # dereferencing as hash - for confusion only ;-) # is($p->{given}, 'John', 'hash dereferencing of SCALAR is +correct'); # $p->{given} = 'Xaver'; # is($p->given, 'John', '...which is correct, no setting +via hashref'); # is($p->{surname}, 'Doe', 'hash dereferencing of SCALAR is +correct'); # is($p->{fullname}, 'John Doe', 'hash dereferencing of SCALAR is +correct'); # BEGIN { $n_tests += 4 } # CLASS Person->fullname = 'Christian Surname'; is(Person->given, 'Christian', 'class attribute for given is set') +; is(Person->surname, 'Surname', 'class attribute for surname is set +'); BEGIN { $n_tests += 2 } BEGIN { plan tests => $n_tests }
...and package
package Person; use strict; use warnings; use Hash::Util::FieldHash qw(fieldhashes id); use overload '%{}' => \&_refsub, fallback => 1; fieldhashes \my(%given,%surname,%fullname); # package attribute 'fullname' tie $Person::fullname{Person}, 'Person::fullname', 'Person'; sub new { my $class = shift; my %args = @_; my $obj = bless do{ \my $x }, $class; for(qw{given surname}) { $obj->$_ = $args{$_} if $args{$_}; } tie $fullname{$obj}, 'Person::fullname', $obj; $obj; } # make getters/setters for (qw{given surname fullname}) { eval "sub $_ : lvalue { \$${_}{shift()} }"; } # provide $obj->{attribute} syntactic sugar - for more confusion # sub _refsub { # my $obj = shift; # warn "WARNING: dereferencing $obj as hashref is deprecated\n"; # warn "WARNING: setting an attribute via hashref does NOT work\n" +; # { # given => $obj->given, # surname => $obj->surname, # fullname => $obj->fullname, # }; # } # tied interface for compound attribute 'fullname' package Person::fullname; sub TIESCALAR { my $class = shift; my $obj = shift; my $tied = bless \$obj, $class; } sub FETCH { my $obj = shift; join" ", grep {length} $$obj->given,$$obj->surname; } sub STORE { my $obj = shift; my ($first, $last) = split /\s+/,shift; $$obj->given = $first; $$obj->surname = $last; } 1;

This is just to give an idea and far from complete. No middle names :-)
Also, $obj->fullname = [ qw(Xaver Unsinn) ] works, but sets just the 'given' field to the string "ARRAY(0x1234567)", which doesn't DWIM. And so on... update: also, the Person::fullname tied objects aren't teared down when its Person objects go out of scope. Ah well.

Of course, the $obj->{attribute} syntactic sugar via overload may lead to confusion, since it works for getting, but fails (silently, if there weren't the warnings) for setting the value. The message Not a HASH reference might be better. What good is it to write curlies anyways, if you can omit them?

This approach lets you define package defaults (or class variables) and could be converted to a singleton class with minor tweaks; the tied() classes could be set up on the fly, and the possiblity of tying hash value slots gives full control about how attributes behave, their behavior could even be different between objects.

Could it be possible that the python solution is much faster?

No idea, and frankly, I don't care.

perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

Replies are listed 'Best First'.
Re^2: Language design: direct attribute access and postponed mutators (Perl Vs Python)
by LanX (Saint) on Sep 16, 2019 at 14:20 UTC
    > No idea, and frankly, I don't care.

    I'm always keen to learn from my enemies.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      I'm always keen to learn from my enemies.

      Um, enemies. But okay, yes, that's one good approach, but also: I'm comfortable with what they don't want to learn from me.

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'