Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Can you help me understand this OO notation/issue?

by mr.nick (Chaplain)
on Sep 06, 2013 at 14:30 UTC ( [id://1052721] : perlquestion . print w/replies, xml ) Need Help??

mr.nick has asked for the wisdom of the Perl Monks concerning the following question:

While I've been programming in Perl forever it seems, I do very, very little OOP in Perl so I'm a bit confused by this code I was shown recently. I'm hoping you folks might be able to divine why it would be done this way and finally, why the issue I'm seeing is occurring.

Firstly, there are two modules named AuditLogReview_Event.pm and AuditLogReview_Event08.pm. This is the first:
use strict; use warnings; package Event; sub new { my ($class) = @_; my $self = {}; $self = { 'Event Type' => 'Windows 2003', }; bless $self, ref($class) || $class; return $self; } package Security; our @ISA = qw (Event); @PARENT::ISA = @ISA; sub new { my $class = shift; my($self) = $class->PARENT::new(@_); $self->{'EventLog'} = 'Security'; return (bless($self, $class)); + # return object } 1;
My first question is: what's the purpose of
@ISA = qw(Event); @PARENT::ISA = @ISA
? To me, that seems that it would make each class a subclass of the other. Why do that?

For my second issue I need to show you the rest of the code, AuditLogReview_Event08.pm:

use strict; use warnings; package Event08; sub new { my ($class) = @_; my $self = {}; $self = { 'Event Type' => 'Windows 2008', }; bless $self, ref($class) || $class; return $self; } package Security08; our @ISA = qw (Event08); @PARENT::ISA = @ISA; sub new { my $class = shift; my($self) = $class->PARENT::new(@_); $self->{'EventLog'} = 'Security'; return (bless($self, $class)); + # return object } 1;

And finally, the test script, AuditTest.pl:

#!/usr/bin/perl -w use strict; use warnings; use AuditLogReview_Event; # handles 2003 events use AuditLogReview_Event08; # handles 2008 events EventWindowsHandler('.evt'); EventWindowsHandler('.evtx'); sub EventWindowsHandler { my $oEvent; my $ext = shift; if ($ext eq '.evt') { $oEvent = Security->new(); } elsif ( $ext eq '.evtx') { $oEvent = Security08->new(); # can I call Security from the + AuditLogReview_Event08 file? } print "Processing $oEvent->{'Event Type'} $oEvent->{'EventLog'} ev +ent.\n"; }

Now, the thing is, as written when it runs it produces the following:

C:\Users\A209624\Desktop>perl AuditTest.pl
Processing Windows 2008 Security event.
Processing Windows 2008 Security event.

Putting some debugging in there, I see that the Security->new() call goes to the right place, but when it does it's

$class->PARENT::new(@_)
it's hitting Event08 instead of Event. Why?

I was able to get the behavior I wanted by changing the my $self = $class->PARENT::new(@_) in each package to

my $self = Event->new(@_); my $self = Event08->new(@_);

But I'm still unsure why the first way didn't work correctly.

Thanks!

mr.nick ...

Replies are listed 'Best First'.
Re: Can you help me understand this OO notation/issue?
by choroba (Cardinal) on Sep 06, 2013 at 15:00 UTC
    I might be mistaken, but PARENT is not special in Perl. Maybe it should have been SUPER?
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      Now that you mention it, that does seem to be true. I guess the @PARENT::ISA = @ISA is actually creating a namespace called "PARENT" with @ISA in it, then the PARENT::new() call searches that @ISA and finds the Event package, then calls the new. Interesting. That would explain why the Event08 is always being called; it's the last to populate @ISA in PARENT.

      Thanks! (I should have noticed this, though ... too much PHP coding).

      mr.nick ...

Re: Can you help me understand this OO notation/issue?
by kcott (Archbishop) on Sep 07, 2013 at 07:16 UTC

    G'day mr.nick,

    It looks like you've resolved your posted question with ++choroba's help.

    As you "do very, very little OOP in Perl", I thought I'd draw your attention to the parent pragma which is used to "Establish an ISA relationship with base classes at compile time".

    Using this pragma, your code might look at little more straightforward written along these lines:

    $ perl -Mstrict -Mwarnings -E ' package Event; sub new { my $class = shift; my $self = { EventType => "Windows 2003", @_ }; bless $self => ref $class || $class; } package Event08; use parent qw{-norequire Event}; sub new { shift->SUPER::new(EventType => "Windows 2008", @_); } package Security; use parent qw{-norequire Event}; sub new { shift->SUPER::new(EventLog => "Security", @_); } package Security08; use parent qw{-norequire Event08}; sub new { shift->SUPER::new(EventLog => "Security", @_); } package main; my $sec = Security::->new(some_attribute => "abc"); say "Class: ", ref $sec; say "EventType: ", $sec->{EventType}; say "EventLog: ", $sec->{EventLog}; say "Some attribute: ", $sec->{some_attribute}; my $sec08 = Security08::->new(some_attribute => "xyz"); say "Class: ", ref $sec08; say "EventType: ", $sec08->{EventType}; say "EventLog: ", $sec08->{EventLog}; say "Some attribute: ", $sec08->{some_attribute}; ' Class: Security EventType: Windows 2003 EventLog: Security Some attribute: abc Class: Security08 EventType: Windows 2008 EventLog: Security Some attribute: xyz

    Notes:

    • It's considered good practice to put classes in their own <ClassName>.pm files. If you do this, you won't need the -norequire: see the parent documentation for details.
    • What I've shown under package main; would typically be in one or more <script_name>.pl files. If you do this, you won't need package main;. However, you would need use Security; and use Security08; (with the test code I've shown).

    -- Ken