On 2020-04-01 14:05:31, PEVANS wrote:
Show quoted text> Further discussion suggests it might be safe to allow slot accesses
> even though they're not set up yet by just presenting all values as
> (immutable) undef. Forbid writing to them but at least let them read
> as undef; possibly with a warning about slot access to not-fully-
> constructed instance. Thoughts continue on that.
Unfortunately that limits options for workarounds: the entire BUILD chain breaks on a trivial `sub new { bless; $self->BUILD }` pattern, because all the attempted setup within the child methods will have no write access to slots. I don't think partial slot support is going to help much in practical cases.
Hooking `bless` would be the ideal time for the ->INIT_SLOTS upgrade to happen, although not sure whether that's even possible at CPAN level (even if it is, bless is a hot path - this could have significant performance implications?)
How would a child class work around this issue at the moment? Is there anything that could be done to make that easier?
For now, it looks like the best option is to reïmplement the logic from the parent class constructor(s) in `method BUILD` - we can't bless an empty hash and pass that over:
$ perl -e'use strict; use warnings; package Parent { sub new { my ($class, %args) = @_; my $self = bless { }, $class; $self->BUILD(%args); } sub BUILD { my ($self, %args) = @_; $self } } use Object::Pad; class Child extends Parent { has $thing; sub new { my ($class, %args) = @_; my $self = bless {}, $class; $self->INITSLOTS; return $self->next::method(%args) } method BUILD (%args) { $thing = delete $args{thing}; $self } } Child->new'
Subroutine new redefined at -e line 1.
Attempt to bless into a reference at -e line 1.
and it's too late to call ->INITSLOTS at the start of the method:
$ perl -e'use strict; use warnings; package Parent { sub new { my ($class, %args) = @_; my $self = bless { }, $class; $self->BUILD(%args); } sub BUILD { my ($self, %args) = @_; $self } } use Object::Pad; class Child extends Parent { has $thing; method BUILD (%args) { $self->INITSLOTS; $thing = delete $args{thing}; $self } } Child->new'
Expected $self->{"Object::Pad/slots"} to be an ARRAY reference at -e line 1.
Providing ways for parent classes to make this easier would be a good starting point, assuming that there isn't a neat solution to let existing parent classes work without needing any changes - IO::Async::Notifier in particular would really benefit from a cleaner option than the current workarounds, would be nice to avoid proliferation of code like this:
use Object::Pad;
{
package Workaround::Notifier::Empty;
use parent qw(IO::Async::Notifier);
sub new {
my ($class, %args) = @_;
bless \%args, $class
}
}
class Workaround::Notifier extends Workaround::Notifier::Empty;
method BUILD (%args) {
$self->_init(\%args);
$self->configure(%args);
$self
}