in reply to Passing object attributes around

I don't think the former has less "action at a distance", on the contrary — though theorists may disagree with my terminology. In the former, you calculate the attributes, but you don't set them in init; you actually set the attributes in new. There, you depend on the specific order the attribute values are returned. That is bad: you split a logical action (setting attributes) between two tightly bound subs. Add or remove one attribute, and you have to modify both subs, and very strictly in sync. That is what makes it bad for maintenance. Surely it's better to do it all just in one place, in one single sub?

Besides, re "action at a distance", that applies to setting global variables, but that's not the case here, as you alter an object you pass as a read/write parameter.

If you insist on turning init into a function, at least, make it return a hash.

sub my_init { my ($self, $args) = @_; # do stuff with $args; return { attr_1 => $attr_1, attr_2 => $attr_2 }; } sub new { my ($class, $args) = @_; my $self = {}; bless ($self, $class); my $attrs = $self->my_init($args); foreach (keys %$attrs) { $self->{$_} = $attrs->{$_}; } return $self; }
At least it breaks the internal dependency on which attributes, and in what order, are returned.

I still prefer directly setting the attributes for the object you passed as a parameter. It smells cleaner to me: there's far less distracting "janitor code" in it. (That is code that is necessary for an implementation but actually doesn't do much useful for its perceived complexity; where nothing specifically applies to this particular piece of code. Up to 4 lines of code for a simple "copy attributes" action: ugh.)