OO Perl help for a dot Net convert?

Discussion in 'Perl Misc' started by ben.wilder@gmail.com, Jun 20, 2006.

  1. Guest

    Hello all,

    I am making the transition from .Net to Perl for a new project and i
    have a few questions about OO Perl, that i would be most grateful if
    someone could comment on / answer!

    Many thanks for any of your help,


    This problem is conceptual, in that i am waiting to learn about certain
    features before trying to actually implement this - so i'll put
    together a dummy OO module and a calling script.

    ------------------------------------------------------------------------------------------
    ****************
    * Perl Module *
    ****************
    package MyPackage;


    #Use definitions
    use strict;


    #Contructor for MyPackage Class
    sub new {
    my ($class, %arg) = @_;
    bless {
    _myFirstName => $arg{myFirstName},
    _myLastName => $arg{myLastName},
    _myAge => $arg{myAge},
    _myFavouriteArtists => $arg{myFavouriteArtists},
    }, $class;
    }


    sub ShowAgeAndArtists{

    my $self = $_[0];

    #Dereference array
    my @myFavouriteArtists = @{$self->{_myFavouriteArtists}};

    my $artist = '';

    foreach $artist ( @myFavouriteArtists )
    {
    print "$self->{_myFirstName} aged $self->{_myAge}, likes $artist\n";
    }


    }

    1;
    ------------------------------------------------------------------------------------------


    ------------------------------------------------------------------------------------------
    ********************
    * Calling script *
    ********************
    #!/usr/bin/perl -w

    use strict;
    use MyPackage;

    my $myFirstName = 'Ben';
    my $myLastName = 'Wilder';
    my $myAge = 28;
    my @myFavouriteArtists = qw[Wolfmother LedZep ChesneyHawkes];

    #Instantiate MyPackage class
    my $myPackage =
    MyPackage->new(myFirstName=>$myFirstName,myLastName=>$myLastName,myAge=>$myAge,myFavouriteArtists=>\@myFavouriteArtists);

    $myPackage->ShowAgeAndArtists();

    ------------------------------------------------------------------------------------------

    Now that i have my example, i'd like to ask a few questions:

    1. I am passing a reference to the @myFavouriteArtists array, however
    with objects being in my mind, an encapsulation of data, it this the
    most effective way to pass array data to an object? Can i pass the data
    by value so that the object deals with its own copy of the data - or am
    i being silly?


    2. In MS .Net there is the principle of object fields, object instance
    scoped, not class scoped, that are not accessible through any public
    methods, but are used possibly by methods private to the class. For
    example - in the above scenario i may want to implement a boolean flag
    "IsTooOld" that can be set by a private internal method for the
    purposes of a logical decision elsewhere in the module. How can i
    define such a variable in perl? It seems that since i am blessing the
    hash into object-hood, that is where i will have to put the definition,
    but i dont want the constructor to be able to alter this definition!
    Any ideas (please let me know if i havent put explained this well
    enough!)


    Thanks again for any help!

    Now go easy on the perl noob guys *backs into corner*


    Ben
     
    , Jun 20, 2006
    #1
    1. Advertising

  2. Anno Siegel Guest

    wrote:

    > Hello all,
    >
    > I am making the transition from .Net to Perl for a new project and i
    > have a few questions about OO Perl, that i would be most grateful if
    > someone could comment on / answer!
    >
    > Many thanks for any of your help,
    >
    >
    > This problem is conceptual, in that i am waiting to learn about certain
    > features before trying to actually implement this - so i'll put
    > together a dummy OO module and a calling script.
    >
    >

    ------------------------------------------------------------------------------------------
    > ****************
    > * Perl Module *
    > ****************
    > package MyPackage;
    >
    >
    > #Use definitions
    > use strict;
    >
    >
    > #Contructor for MyPackage Class
    > sub new {
    > my ($class, %arg) = @_;
    > bless {
    > _myFirstName => $arg{myFirstName},
    > _myLastName => $arg{myLastName},
    > _myAge => $arg{myAge},
    > _myFavouriteArtists => $arg{myFavouriteArtists},


    Better:

    _myFavouriteArtists => [ @{ $arg{myFavouriteArtists} } ],

    to decouple the original array (see below).

    > }, $class;
    > }
    >
    >
    > sub ShowAgeAndArtists{
    >
    > my $self = $_[0];
    >
    > #Dereference array
    > my @myFavouriteArtists = @{$self->{_myFavouriteArtists}};


    Copying the array is not necessary here, you're not changing it.

    > my $artist = '';
    >
    > foreach $artist ( @myFavouriteArtists )


    Just say

    foreach $artist ( @{ $self->{ _myFavouriteArtists} } ) {

    > {
    > print "$self->{_myFirstName} aged $self->{_myAge}, likes $artist\n";
    > }
    >
    >
    > }
    >
    > 1;
    >

    ------------------------------------------------------------------------------------------
    >
    >
    >

    ------------------------------------------------------------------------------------------
    > ********************
    > * Calling script *
    > ********************
    > #!/usr/bin/perl -w
    >
    > use strict;
    > use MyPackage;
    >
    > my $myFirstName = 'Ben';
    > my $myLastName = 'Wilder';
    > my $myAge = 28;
    > my @myFavouriteArtists = qw[Wolfmother LedZep ChesneyHawkes];
    >
    > #Instantiate MyPackage class
    > my $myPackage =
    >

    MyPackage->new(myFirstName=>$myFirstName,myLastName=>$myLastName,myAge=>$myAge,myFavouriteArtists=>\@myFavouriteArtists);
    >
    > $myPackage->ShowAgeAndArtists();
    >
    >

    ------------------------------------------------------------------------------------------
    >
    > Now that i have my example, i'd like to ask a few questions:
    >
    > 1. I am passing a reference to the @myFavouriteArtists array, however
    > with objects being in my mind, an encapsulation of data, it this the
    > most effective way to pass array data to an object? Can i pass the data
    > by value so that the object deals with its own copy of the data - or am
    > i being silly?


    No, not at all. Storing a reference to the @myFavouriteArtists array
    means that later changes to that array will be reflected in the
    object -- usually not what you want. To avoid this, make a copy
    of the array when you initialize the object (see code above). On
    the other hand you're copying the array on access, which is not
    necessary.

    >
    > 2. In MS .Net there is the principle of object fields, object instance
    > scoped, not class scoped, that are not accessible through any public
    > methods, but are used possibly by methods private to the class. For
    > example - in the above scenario i may want to implement a boolean flag
    > "IsTooOld" that can be set by a private internal method for the
    > purposes of a logical decision elsewhere in the module. How can i
    > define such a variable in perl? It seems that since i am blessing the
    > hash into object-hood, that is where i will have to put the definition,
    > but i dont want the constructor to be able to alter this definition!
    > Any ideas (please let me know if i havent put explained this well
    > enough!)


    There is no concept of private methods in Perl OO. Instead we use the
    simple convention that methods whose names start with an underscore
    are meant to be private and the class user is not supposed to call
    them directly. This is not enforcable, however.

    Two more remarks:

    It is usually better to have a separate initializer method (->init, say)
    in each class that takes a given object and sets it up for use with
    that class. The conventional ->new method can then be written:

    sub new {
    my $class = shift;
    bless( {}, $class)->init( @_);

    This separation is not usually taught with Perl OO, but it is
    nevertheless important. It is hard to set up objects for multiple
    inheritance without it.

    You have chosen the common implementation of Perl objects as hashrefs.
    It may be worth while to acquaint yourself with the concept of inside-out
    classes. These are a relatively newly developed alternative to more
    conventional ways of implementing objects in Perl. Inside-out classes
    are a little more involved than other types of classes, but give you
    a class that can be inherited by *any* other Perl class, whether it
    is itself inside-out or not. Normal classes are usually confined in
    inheritance to classes of the same type (hash in your case), or else...
    Google for "inside-out Perl" with an eye to articles on perlmonks.

    Anno
     
    Anno Siegel, Jun 20, 2006
    #2
    1. Advertising

  3. wrote:
    [ example snipped]
    > Now that i have my example, i'd like to ask a few questions:
    >
    > 1. I am passing a reference to the @myFavouriteArtists array, however
    > with objects being in my mind, an encapsulation of data, it this the
    > most effective way to pass array data to an object? Can i pass the data
    > by value so that the object deals with its own copy of the data - or am
    > i being silly?


    Your constructor needs to distinguish between its arguments. Since there
    is exactly one array, you could change your constructor to:

    sub new {
    my ($class, $myFirstName, $myLastName, $myAge, @myFavouriteArtists) = @_;
    ...
    }

    and call it like

    MyPackage->new($myFirstName,$myLastName,$myAge,@myFavouriteArtists);

    or

    MyPackage->new("Ben","Wilder",28, "Wolfmother", "LedZep", "ChesneyHawkes");

    But what happens if you add a second array?

    Alternatively, you could scan the @_ in the constructor for keywords
    like "myFirstName", "myLastName", etc. But what happens if someone
    founds a band called "myAge"?

    So I think, passing references to arrays is generally the best way.

    You can of course make a copy of the array in the constructor:

    _myFavouriteArtists => [ @{ $arg{myFavouriteArtists} } ],

    if you want to. I found this rarely to be necessary, and usually made
    the copy when calling the constructor (because when I'm calling the
    constructor, I know whether I will continue to use the array. I don't
    know this in the constructor).

    > 2. In MS .Net there is the principle of object fields, object instance
    > scoped, not class scoped, that are not accessible through any public
    > methods, but are used possibly by methods private to the class.


    This seems to be a rather strange concept to me. I understand making
    fields private so they are only accessible through methods from the
    outside. But why make them inaccessible from the inside?

    > For example - in the above scenario i may want to implement a boolean
    > flag "IsTooOld" that can be set by a private internal method for the
    > purposes of a logical decision elsewhere in the module. How can i
    > define such a variable in perl?


    Perl doesn't even have private methods, much less a way to declare that
    some variable should be accessible to only some methods.

    It's probably possible to achieve this with tie. Maybe there is even
    already a package on CPAN which does this. (There are a lot of packages
    on CPAN implementing different styles of object oriented programming -
    I've played with a few but always went back to the basic blessed hashref
    style).

    > It seems that since i am blessing the hash into object-hood, that is
    > where i will have to put the definition, but i dont want the
    > constructor to be able to alter this definition!


    In the blessed hashref style, there is no information hiding at all. Not
    only can the constructor change the object (well it has to, since it
    *creates* the object in the first place), but anybody who gets the
    object can examine and change its contents - it is just a hashref, after
    all.

    hp

    --
    _ | Peter J. Holzer | Man könnte sich [die Diskussion] auch
    |_|_) | Sysadmin WSR/LUGA | sparen, wenn man sie sich einfach sparen
    | | | | würde.
    __/ | http://www.hjp.at/ | -- Ralph Angenendt in dang 2006-04-15
     
    Peter J. Holzer, Jun 20, 2006
    #3
  4. Dave Guest

    <> wrote in message
    news:...
    > Hello all,
    >
    > I am making the transition from .Net to Perl for a new project and i
    > have a few questions about OO Perl, that i would be most grateful if
    > someone could comment on / answer!
    >
    > Many thanks for any of your help,
    >
    >
    > This problem is conceptual, in that i am waiting to learn about certain
    > features before trying to actually implement this - so i'll put
    > together a dummy OO module and a calling script.
    >
    > ------------------------------------------------------------------------------------------
    > ****************
    > * Perl Module *
    > ****************
    > package MyPackage;
    >
    >
    > #Use definitions
    > use strict;
    >
    >
    > #Contructor for MyPackage Class
    > sub new {
    > my ($class, %arg) = @_;
    > bless {
    > _myFirstName => $arg{myFirstName},
    > _myLastName => $arg{myLastName},
    > _myAge => $arg{myAge},
    > _myFavouriteArtists => $arg{myFavouriteArtists},
    > }, $class;
    > }
    >
    >
    > sub ShowAgeAndArtists{
    >
    > my $self = $_[0];
    >
    > #Dereference array
    > my @myFavouriteArtists = @{$self->{_myFavouriteArtists}};
    >
    > my $artist = '';
    >
    > foreach $artist ( @myFavouriteArtists )
    > {
    > print "$self->{_myFirstName} aged $self->{_myAge}, likes $artist\n";
    > }
    >
    >
    > }
    >
    > 1;
    > ------------------------------------------------------------------------------------------
    >
    >
    > ------------------------------------------------------------------------------------------
    > ********************
    > * Calling script *
    > ********************
    > #!/usr/bin/perl -w
    >
    > use strict;
    > use MyPackage;
    >
    > my $myFirstName = 'Ben';
    > my $myLastName = 'Wilder';
    > my $myAge = 28;
    > my @myFavouriteArtists = qw[Wolfmother LedZep ChesneyHawkes];
    >
    > #Instantiate MyPackage class
    > my $myPackage =
    > MyPackage->new(myFirstName=>$myFirstName,myLastName=>$myLastName,myAge=>$myAge,myFavouriteArtists=>\@myFavouriteArtists);
    >
    > $myPackage->ShowAgeAndArtists();
    >
    > ------------------------------------------------------------------------------------------
    >
    > Now that i have my example, i'd like to ask a few questions:
    >
    > 1. I am passing a reference to the @myFavouriteArtists array, however
    > with objects being in my mind, an encapsulation of data, it this the
    > most effective way to pass array data to an object? Can i pass the data
    > by value so that the object deals with its own copy of the data - or am
    > i being silly?
    >
    >
    > 2. In MS .Net there is the principle of object fields, object instance
    > scoped, not class scoped, that are not accessible through any public
    > methods, but are used possibly by methods private to the class. For
    > example - in the above scenario i may want to implement a boolean flag
    > "IsTooOld" that can be set by a private internal method for the
    > purposes of a logical decision elsewhere in the module. How can i
    > define such a variable in perl? It seems that since i am blessing the
    > hash into object-hood, that is where i will have to put the definition,
    > but i dont want the constructor to be able to alter this definition!
    > Any ideas (please let me know if i havent put explained this well
    > enough!)
    >
    >
    > Thanks again for any help!
    >
    > Now go easy on the perl noob guys *backs into corner*
    >
    >
    > Ben
    >


    You should have a look at Conway's 'Perl Best Practices' that has some
    strong advise about how to implement OO Perl. It goes without saying that
    this advice is not universally accepted in the Perl community but it is
    worth considering nontheless. [I believe Schwarz's 'Intermediate Perl' has
    different OO Perl recommendations but I have not read that one].

    Dave
     
    Dave, Jun 20, 2006
    #4
  5. Anno Siegel Guest

    Peter J. Holzer wrote:
    > wrote:


    [snippage]

    > So I think, passing references to arrays is generally the best way.
    >
    > You can of course make a copy of the array in the constructor:
    >
    > _myFavouriteArtists => [ @{ $arg{myFavouriteArtists} } ],
    >
    > if you want to. I found this rarely to be necessary,


    It is practically always necessary to copy any references before
    using them in an object. Just consider a loop like this:

    while ( <> ) {
    my ( $first, $last, $age, @artists) = split;
    push @somewhere, MyPackage->new( $first, $last, $age, \ @artists);
    }

    All the objects created in this loop will *share* their internal
    myFavouriteArtists array and will show the same favourite artists
    unless you copy the array on object creation.

    Anno
     
    Anno Siegel, Jun 20, 2006
    #5
  6. Anno Siegel wrote:
    > Peter J. Holzer wrote:
    >> wrote:

    >
    > [snippage]
    >
    >> So I think, passing references to arrays is generally the best way.
    >>
    >> You can of course make a copy of the array in the constructor:
    >>
    >> _myFavouriteArtists => [ @{ $arg{myFavouriteArtists} } ],
    >>
    >> if you want to. I found this rarely to be necessary,

    >
    > It is practically always necessary to copy any references before
    > using them in an object. Just consider a loop like this:
    >
    > while ( <> ) {
    > my ( $first, $last, $age, @artists) = split;
    > push @somewhere, MyPackage->new( $first, $last, $age, \ @artists);
    > }
    >
    > All the objects created in this loop will *share* their internal
    > myFavouriteArtists array and will show the same favourite artists
    > unless you copy the array on object creation.


    Actually, no. In this case each run through the loop will create a new
    instance of @artists.

    Run this program, and you will see that the addresses will change and
    that the contents are correctly preserved:

    ----8<--------8<--------8<--------8<--------8<--------8<--------8<--------8<----
    #!/usr/bin/perl
    use warnings;
    use strict;

    package Foo;

    sub new {
    my ($class, $arr) = @_;
    my $self = { arr => $arr };
    bless $self => $class;
    return $self;
    }

    sub getarr {
    my ($self) = @_;
    return $self->{arr};
    }

    package main;

    my @foo;
    while (<>) {
    chomp;
    my (@arr) = split;
    push @foo, Foo->new(\@arr);
    }

    for (@foo) {
    my $arr = $_->getarr;
    print "$arr @$arr\n";
    }
    ----8<--------8<--------8<--------8<--------8<--------8<--------8<--------8<----

    There are cases where copying is necessary, but since this can only be
    determined from reading the code of the caller I find it more logical to
    do the copying in the caller:

    push @foo, Foo->new([@arr]);

    $arr[5] = "foo";
    push @arr, "baz";

    push @foo, Foo->new([@arr]);

    Or something like that.


    hp

    --
    _ | Peter J. Holzer | Man könnte sich [die Diskussion] auch
    |_|_) | Sysadmin WSR/LUGA | sparen, wenn man sie sich einfach sparen
    | | | | würde.
    __/ | http://www.hjp.at/ | -- Ralph Angenendt in dang 2006-04-15
     
    Peter J. Holzer, Jun 20, 2006
    #6
  7. Anno Siegel Guest

    Peter J. Holzer wrote:

    > Anno Siegel wrote:
    >> Peter J. Holzer wrote:
    >>> wrote:

    >>
    >> [snippage]
    >>
    >>> So I think, passing references to arrays is generally the best way.
    >>>
    >>> You can of course make a copy of the array in the constructor:
    >>>
    >>> _myFavouriteArtists => [ @{ $arg{myFavouriteArtists} } ],
    >>>
    >>> if you want to. I found this rarely to be necessary,

    >>
    >> It is practically always necessary to copy any references before
    >> using them in an object. Just consider a loop like this:
    >>
    >> while ( <> ) {
    >> my ( $first, $last, $age, @artists) = split;
    >> push @somewhere, MyPackage->new( $first, $last, $age, \
    >> @artists);
    >> }
    >>
    >> All the objects created in this loop will *share* their internal
    >> myFavouriteArtists array and will show the same favourite artists
    >> unless you copy the array on object creation.

    >
    > Actually, no. In this case each run through the loop will create a new
    > instance of @artists.


    You are right, my example doesn't show what I wanted to show. If
    @artists was declared outside of the loop for some reason, the effect
    I described will happen (untested again):

    my ($first, $last, @artists);
    push @somewhere, MyPackage->new( $first, $last, $age, \ @artists)
    while <>;

    In general, it is not a good idea to use references given from outside
    directly in an object. If you do, the users of the class must be
    told.

    Anno
     
    Anno Siegel, Jun 21, 2006
    #7
  8. Guest

    Gentlemen,


    Thank you all very much for your help. Your explanations very much
    appreciated. I have now the Conway OO perl book and will investigate!
    The copying array in the constructor sample is invaluable and your
    explanation of class / object behaviour has improved my understanding
    of how Perl implements OO a great deal!

    Thanks again for your time!

    Ben
     
    , Jun 22, 2006
    #8
  9. Dave wrote:
    > <> wrote in message
    > news:...
    >> Hello all,
    >>...
    >>

    >
    > You should have a look at Conway's 'Perl Best Practices' that has some
    > strong advise about how to implement OO Perl. It goes without saying that
    > this advice is not universally accepted in the Perl community but it is
    > worth considering nontheless. [I believe Schwarz's 'Intermediate Perl' has
    > different OO Perl recommendations but I have not read that one].
    >


    s/Schwarz/Schwartz/. I haven't read `Intermediate Perl` yet but I assumed
    its OO approach and recommendations wouldn't differ greatly with PBP's.
    Can anyone who's read both contrast them...

    --
    Charles DeRykus
     
    Charles DeRykus, Jun 27, 2006
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Samuël van Laere

    To dot or not to dot?

    Samuël van Laere, Oct 16, 2003, in forum: HTML
    Replies:
    8
    Views:
    461
    Samuël van Laere
    Oct 16, 2003
  2. Christopher M. Lusardi

    volatile struct in dot h vs dot c

    Christopher M. Lusardi, May 11, 2004, in forum: C Programming
    Replies:
    3
    Views:
    501
    Peter Shaggy Haywood
    May 15, 2004
  3. Nathan Sokalski
    Replies:
    11
    Views:
    736
    AAaron123
    Aug 14, 2009
  4. krishnan

    Dot Net Project Execution without Dot Net and Framework....

    krishnan, Jan 7, 2006, in forum: ASP .Net Building Controls
    Replies:
    0
    Views:
    214
    krishnan
    Jan 7, 2006
  5. Replies:
    6
    Views:
    291
    Thomas 'PointedEars' Lahn
    Dec 12, 2005
Loading...

Share This Page