Flame has asked for the wisdom of the Perl Monks concerning the following question:

I have a prototype that seems to be failing... or perhaps it's beeing ignored. Posted below is an excerpt from an object oriented module I'm writing (Reference: Data Validation Tests, further reference listed in there)

sub selftest(@){ my $self = _self(@_); print Dumper(@_); } sub _self(\@){ print Dumper(@_); if(ref($_[0]->[0]) && $_[0]->[0]->_me() eq 'DVALID'){ return shift(@{ $_[0] }); }else{ return; } }
This is the test proggy:
my $chk = new Data::Validate::OO( -failure => sub{ my $rule = shift; print "Error in rule '$rule': ". +join(', ',@_)."\n"; }, ); $chk->selftest(qw(This Is a Test of the emergency broadcast system!));
This is the output:
$VAR1 = bless( { '_error' => '', '_fail' => sub { "DUMMY" }, '_rules' => {} }, 'Data::Validate::OO' ); $VAR2 = 'This'; $VAR3 = 'Is'; $VAR4 = 'a'; $VAR5 = 'Test'; $VAR6 = 'of'; $VAR7 = 'the'; $VAR8 = 'emergency'; $VAR9 = 'broadcast'; $VAR10 = 'system!'; Not an ARRAY reference at OO.pm line 264.


Line 264 is the if(ref($_[0]->[0]) && $_[0]->[0]->_me() eq 'DVALID'){ line.

Now, according to perlman:perlsub "Any backslashed prototype character represents an actual argument that absolutely must start with that character. The value passed as part of @_ will be a reference to the actual argument given in the subroutine call, obtained by applying \ to that argument." Reading this, it seems to me that I should be getting a reference to the @_ of the caller sub. Unfortunately that apparently isn't happening... unless I messed up somewhere else (which is quite possible).

If there is any more information you feel might help to solve the problem, please request it and I will do my best to take care of it.

Thank you.



My code doesn't have bugs, it just develops random features.

Flame ~ Lead Programmer: GMS | GMS

Replies are listed 'Best First'.
Re: Prototype Failing?
by BrowserUk (Patriarch) on Jan 27, 2003 at 04:46 UTC

    Prototypes are not honoured on method calls. You passed an array and received and array. For the low-down on why, read on in the same document to the secion that starts

    Method calls are not influenced by prototypes either, ...

    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

      Ok, so the first call was as a method, but the second was internal... a method calling a function, shouldn't it have honored the prototype then?

      _self is the only one with a prototype that needs to be payed attention to and it's being called as a function.



      My code doesn't have bugs, it just develops random features.

      Flame ~ Lead Programmer: GMS (DOWN) | GMS (DOWN)

        The first argument in @_ in a method call is self.

        When you call _self(@_) you are passing a reference to an array, the first element of which is a bless'd reference. (in this case a hashref).

        When you give the array ref to Dumper, it duly dumps contents of the hash followed by the individual elements of the rest of @_. Ie. the list you passed to selftest().

        When you try to dereference the first element of @_ as an array ref in ref($_[0]->[0]), it complains because $_[0] is a hashref (self) as magically supplied to selftest() when you invoked it as a method.

        Hope that makes sense of it.


        Examine what is said, not who speaks.

        The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Re: Prototype Failing?
by blokhead (Monsignor) on Jan 27, 2003 at 04:52 UTC
    I got your code to work by changing the order of sub selftest and sub _self declarations in your source:
    # With selftest declared after _self % perl -MO=Deparse test.pl ... sub Data::Validate::OO::selftest (@) { package Data::Validate::OO; my $self = &_self(\@_); # <---- look here print Dumper(@_); } ... # Now with selftest declared after _self % perl -MO=Deparse test.pl ... sub Data::Validate::OO::selftest (@) { package Data::Validate::OO; my $self = &_self(@_); # <---- and here print Dumper(@_); } ...
    The compiler doesn't yet know about the prototype as it is parsing the line that contains my $self = _self(@_), so it doesn't know it must pass the array by reference. Either put an empty prototype at the top of the package, or switch the order of the subs in your source code.

    Incidentally, a prototype of (@) like you have in the selftest sub is equivalent to declaring no prototype at all. And as already mentioned, not honored for a method call anyway.

    blokhead

      ... Wow... behold the power of order... I'll have to keep that in mind. Yeah I know @ might as well not be there, it's there because I got in the habit while designing the tests (it determines the number of arguments to pass to a test via the prototype function. Tricky, but avoids extra fields of 'this many args')

      Thanks!



      My code doesn't have bugs, it just develops random features.

      Flame ~ Lead Programmer: GMS (DOWN) | GMS (DOWN)

Re: Prototype Failing?
by Aragorn (Curate) on Jan 27, 2003 at 07:22 UTC
    See this article for a (IMHO) good explanation of Perl's "prototypes".