Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Perl semi-object without a constructor

by Wiggins (Hermit)
on Feb 20, 2013 at 18:23 UTC ( [id://1019819]=perlquestion: print w/replies, xml ) Need Help??

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

Please be tolerant, and read through to the end. I am trying to wrap my head arround some OO Perl that doesn't match the style of any of the examples I can find. The code ths that Msg.pm from
"Advanced Perl Programming By Sriram Srinivasan 1st Edition 1997".
Only some parts are in the book, but it is all tied together in
" ftp://ftp.oreilly.com/published/orielly/nutshell/advanved_perl/examples.tar.gz".

Puzzlement #1)
This code comes from Msg.pm. It is the first sub in the file, following some glocal hashes and such.

# Send side routines sub connect { my ($pkg, $to_host, $to_port, $rcvd_notification_proc) = @_; # Create a new internet socket my $sock = IO::Socket::INET->new ( PeerAddr => $to_host, PeerPort => $to_port, Proto => 'tcp', Reuse => 1);
Connect lists 4 paramaters, 3 are used here.
The calling code in "msgdemo.pl":
use Msg; ... foreach $prog (@ARGV) { my $conn = Msg->connect($host, $port, \&rcvd_msg_from_server); die "Client could not connect to $host:$port\n" unless $conn; print "Connection successful.\n";

'new_server()' is called with only 3 arguments, not 4! But it works. The '$pkg' is used a bit later in this code:
# Create a connection end-point object my $conn = bless { sock => $sock, rcvd_notification_proc => $rcvd_notification_proc, }, $pkg;
From the comment, an object was created. The reference is the anonymous hash with 2 members, and the class name is what? $pkg appears to be an undefined scalar?

Puzzlement #2
Further down in the code is a small subroutine that sets the flush value to true for the 'conn':

sub send_now { my ($conn, $msg) = @_; _enqueue ($conn, $msg); $conn->_send (1); # 1 ==> flush ?????? }
From the prior 'bless', a $conn has no methods, but the
$conn->_send (1);
looks like _send is a method of the $conn object. Is that a shorthand or alternate form of
_send ($conn,1);
of a Perl convention to have a non object method work with this object.

This --server code listens on only one port, and I am trying to generalize it to manage multiple listen sockets and support UDP as well as TCP.

It is always better to have seen your target for yourself, rather than depend upon someone else's description.

Replies are listed 'Best First'.
Re: Perl semi-object without a constructor
by tobyink (Canon) on Feb 20, 2013 at 21:29 UTC

    Given this

    package Msg; sub connect { my ($pkg, $to_host, $to_port, $rcvd_notification_proc) = @_; } # ... Msg->connect($host, $port, \&rcvd_msg_from_server);

    The connect method is not being called with three arguments, it's being called with four arguments. The first argument is the string "Msg" - that is, the part before the ->. This is how method calls work in Perl (we borrowed it from Python); the thing before the arrow gets passed in as the first argument.

    "From the comment, an object was created. The reference is the anonymous hash with 2 members, and the class name is what? $pkg appears to be an undefined scalar?"

    $pkg is "Msg".

    "From the prior 'bless', a $conn has no methods"

    Why do you think $conn has no methods? Something to do with the hash only having a couple of uninteresting key-value pairs? An object's methods have nothing to do with the blessed reference itself, but are taken from the package it is blessed into.

    So because $conn is blessed into the Msg package, all the subs defined within Msg are available as methods for $conn.

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
      "Why do you think $conn has no methods? "
      Because of my ignorance of the nuances of Perl classes and objects. All of the texts I looked at started with a package and a sub called 'new' to create the object. I had been looking at Msg.pm as a way to carve out and localize a set of functions and have a cleaner organization. That is the only usage I knew about for packages.

      This exploration has been enlightening, and gives me a new light to look at Perl packages. The simple explanation of:

      The first argument is the string "Msg" - that is, the part before the ->. This is how method calls work in Perl (we borrowed it from Python); the thing before the arrow gets passed in as the first argument.
      Is the key that I never found in my frantic scanning of my library; I didn't find an explanation of the mechanics, just the conceptualization of OO.

      Thanks a bunch! odd, ending my text with an exclamation point messes up formatting.

      !-- Node text goes above. Div tags should contain sig only -->

      It is always better to have seen your target for yourself, rather than depend upon someone else's description.

        "All of the texts I looked at started with a package and a sub called 'new' to create the object."

        It is convention to name constructors new but there's no requirement to do so. You could just as well call it old or frangipane and it would make not one whit of difference to the Perl interpreter. But the reason that you should call a constructor new (and not old or frangipane) is for humans reading your code. When they see new they'll know precisely what that method call is doing!

        That said, it's quite common for a class to define additional constructors such as new_from_json or new_from_yaml in addition to their standard new constructor. These are often wrappers around new that do additional pre-processing or post-processing.

        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Perl semi-object without a constructor
by arnaud99 (Beadle) on Feb 20, 2013 at 19:19 UTC
    Hi, it seems to me that in your first example, the connect method is part of a package that also defines a class. If this is the case then all methods within that package are being passed silently the object reference as the first parameter. This is why you only need 3 parameters to call the method. What is called $pkg here is usually called $self. I hope this helps.
Re: Perl semi-object without a constructor
by Anonymous Monk on Feb 20, 2013 at 19:35 UTC
    As far as I can see 'connect' *is* the constructor.

    Whenever you see a construct that looks like Module->subroutine you should think "Class Method". The subroutine will be called with the Class name as the 1st parameter, and as expected it's used in a bless command.

    Now that $conn is an object, all subroutines in it's class' (Msg) namespace and in the namespaces listed in Msg::ISA, can now be used as methods. Any such method will receive the blessed reference $conn implicitly as it's 1st parameter.

      I went back and looked at all the subroutines.
      2 have $pkg as arg0 (event_loop() & new_server())
      7 have $conn as arg0
      3 don't take args
      1 starts with the line:
      shift unless ref($_[0]); # shift if first arg is package name

      So maybe the entire package is actually a class.

      With 1 dodgy routine:

      sub _new_client { my $sock = $main_socket->accept(); my $conn = bless { 'sock' => $sock, 'state' => 'connected' }, $g_pkg; #< different CLASSNAME my $rcvd_notification_proc = &$g_login_proc ($conn, $sock->peerhost(), $sock->peerport()); if ($rcvd_notification_proc) { $conn->{rcvd_notification_proc} = $rcvd_notification_proc; my $callback = sub {_rcv($conn,0)}; set_event_handler ($sock, "read" => $callback); } else { # Login failed $conn->disconnect(); } }

      It is always better to have seen your target for yourself, rather than depend upon someone else's description.

        Common Perl convention is that sub/method names beginning with an underscore are to be treated as private. The reason that sub _new_client is structured differently than the other subs in the package is because it's meant for internal use only and is not a part of the public interface.
Re: Perl semi-object without a constructor
by sundialsvc4 (Abbot) on Feb 21, 2013 at 14:50 UTC

    Let me try to toss-in an explanation of the big picture here:

    (1)   In Perl, an “object” is (usually...) a hashref that has been passed to the built-in function, bless, which takes as its (usually...) two parameters the hashref to be blessed and a package name.   Internally, Perl now flips a switch that says that it is “blessed,” and associates the specified package-name with it.   (Yes, it can be, and occasionally is, re-blessed, which changes the associated package-name.)

    Any piece of code which serves this function, no matter where it is located nor what it is named, serves this purpose.   Specifically, there is nothing “magical” about a function named new.


    (2)   When something has been blessed, it becomes possible to use the $obj->methodname(args...) syntax.   This simply translates to a subroutine call, to a sub (maybe...) found in the previously-associated package, but passing $obj as an additional, first, parameter.

    You will therefore find that these subroutines begin with a statement such as my $self = shift;, which grabs that first-parameter that has been added.   Once again, the name $self is simply a convention.


    HTH...   If you are used to looking at very formal, computer-science-y language implementations, you might be a bit startled by Perl.

Re: Perl semi-object without a constructor
by TomDLux (Vicar) on Feb 21, 2013 at 15:26 UTC

    Use the POD, Wiggins!

    If you're on a Mac or Linux/Unix system, type into a terminal window:

    perldoc perlobj

    to read about using objects in Perl. If you can't use a terminal window, or you're on Windows, go to http://perldoc.perl.org/perlobj.html

    There are tons (ie several dozen) of tutorial/reference files installed on your system; perldoc perl contains the entire list. perlootut is a great OO guide for beginners.

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1019819]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (2)
As of 2024-04-18 23:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found