Skip Menu |

This queue is for tickets about the Class-Std CPAN distribution.

Report information
The Basics
Id: 20966
Status: open
Priority: 0/
Queue: Class-Std

People
Owner: Nobody in particular
Requestors: ROBN [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: No way to set a superclass constructor argument from a derived class
Class-Std 0.0.8 Perl 5.8.8 Linux 2.6.16 In days gone by, I might have done this: package myclass; use Carp qw(croak); sub new { my ($class, $value) = @_; croak "required value missing" if @_ == 1 or !$value; return bless \$value, $class; } package mysubclass; use base qw(myclass); sub new { my ($class) = @_; return bless $class->SUPER::new(23), $class; } I see no way to do this with Class::Std. My instinct was to do this: package myclass; use Class::Std; my %value :ATTR( :init_arg<value> ); package mysubclass; use base qw(myclass); sub BUILD { my ($self, $ident, $args) = @_; $args->{value} = 23; } Reading Class/Std.pm, I see why this doesn't work, but I think it should. At least there should be some mechanism to make this possible. My "workaround" is to remove the :init_arg from myclass, and setup a START that croaks if the value isn't there, or sets it if it is. In other words, I'm doing what I would have done pre-Class::Std, and not taking advantage of its whole argument checking setup. Was there a design rationale for not allowing this? Can I get something like this in the next release? Otherwise, if you think the idea is fine, I can try to cobble together a patch myself. Cheers, Rob.
Subject: Re: [rt.cpan.org #20966] No way to set a superclass constructor argument from a derived class
Date: Thu, 17 Aug 2006 17:59:27 +1000
To: bug-Class-Std [...] rt.cpan.org
From: Damian Conway <damian [...] conway.org>
Rob writes: Show quoted text
> I see no way to [wrap a constructor] with Class::Std.
It's easy: package myclass; use Class::Std; my %value :ATTR( :init_arg<value> :get<value> ); package mysubclass; use base qw(myclass); sub new { my ($class, $args) = @_; return $class->SUPER::new({ %{$args}, value=>23 }); } package main; my $obj = mysubclass->new({value=>42}); print $obj->get_value(); Damian
From: ROBN [...] cpan.org
Show quoted text
> package mysubclass; > use base qw(myclass); > > sub new { > my ($class, $args) = @_; > return $class->SUPER::new({ %{$args}, value=>23 }); > }
Sorry, I wasn't clear. In my app, mysubclass is another Class::Std class. Relevant snips: package Unit; use Class::Std; my %race :ATTR( :name<race> ); my %location :ATTR( :get<location> :set<location>); my %energy :ATTR( :get<energy> ); package Army; use base qw(Unit); use Class::Std; my %size :ATTR( :name<size> ); my %morale :ATTR( :name<morale> ); Now the enemy armies have a bunch of extra stuff related to the AI, so they get their own class. I want the constructor to initialise Unit::race to mark them as an enemy. The most obvious way to do this (to me) was: package EnemyArmy; use base qw(Army); use Class::Std; my %orders :ATTR( :init_arg<orders> :get<orders> ); my %target :ATTR( :init_arg<target> :get<target> ); sub BUILD { my ($self, $ident, $args) = @_; $args->{race} = Race::FOUL; } ie let the derived class initialise args for the base class constructors. That doesn't work, of course. My workaround is removing init_arg from Unit::race, then having Unit::START, Army::START check for $args->{race} and call $self->set_race if its there, or croak if its not. Obviously that sucks. Thanks, Rob.