Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Getting Confused with the '->' operator

by the_Don (Scribe)
on Sep 30, 2002 at 21:45 UTC ( [id://201861]=perlquestion: print w/replies, xml ) Need Help??

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

OK, the easiet way for me to explain this is to show you a line of code that I have at work...

$interface->handler($client)->parse($local_file_name);

My question, I hope, is trivial... 'Which methods are invoked on which objects?'

I have seen examples that piggy-back the '->' operator:

$Person->name('Homer') ->job('safety inspector') ->wife('Marge') ->fav_food('Duff');
Obviosly all the method calls are targeted at the Person object (I mean a job does not have a wife, and we all know that Marge's favorite food is potatoes!) but other times I'll see things like the first line from work where it looks like each call is invoked on the last referenced object.

Does it depend on what each of those calls are returning? i.e. a return of undef forces Perl to make the call on the next previously defined object? Or is there some other rule that I am not aware of?

I have gone through the Object chapter of Programming Perl, 3rd Edition. Feel free to direct me within that text or on-line for an existing explanation. I may have just missed it as a result of my frustration.

the_Don
...making offers others can't rufuse.

Replies are listed 'Best First'.
Re: Getting Confused with the '->' operator
by elusion (Curate) on Sep 30, 2002 at 22:34 UTC
    The arrow operator always operates on the value to its left. That means that your second example would be equivalent to this:
    my $result1 = $Person->name('Homer'); my $result2 = $result1->job('safety inspector'); my $result3 = $result2->wife('Marge'); $result3->fav_food('Duff');
    where the result variables are temporary. In order for the code to work as expected, the methods (name, job, wife, fav_food) must return the original object. A sample method that works this way would look like this (assuming the object is a hash ref):
    sub name { my ($self, $value) = @_; if (defined $value) { # if a value is given $self->{name} = $value; # set the value return $self; # return the original object } return $self->{name}; # else return the name }
    This code fragment will set the value and return the object if a value is given, else it will return what the name is set as.

    So why do you sometimes see the original object ($Person in this case) have multiple method calls originating from the original obect on multiple lines? Because if the method returns a value other than itself (which is quite common), it will try to call the method on that value, and most likely fail.

    elusion : http://matt.diephouse.com

Re: Getting Confused with the '->' operator
by BrowserUk (Patriarch) on Sep 30, 2002 at 22:51 UTC

    In your first example, the assumption I would make based on what I see is that

    1. $interface is a handle to an object that has a method, handler() that takes a parameter ($client) and returns an object.

      This object is probably the handler object for the specified client for this interface.

    2. This handler object has a method parse that takes a string, in this case probably a filename, and either parses that string, or possibly the contents of a file who's name is held in that string.

      That the results of the parsing are not returned immediately suggests that the latter is more likely, and subsequent calls to the handler would be needed to verify and/or retrive thos results.

      That no attempt is made to check any return code from the parse call would worry me slightly.

    In the second example, the code looks remenicient of much of the Java Library API's, where accessor methods for 'set' operations return their own handle allowing calls to the 'set' methods to be chained.

    So that $Person is the handle to an object that has (at least 4) private attributes (name,job,wife,favorite_food), and accessor methods that return (at least when a parameter os passed) their object handle, thus leading to the notational 'short-hand' of

    $Person->name('Homer')->job('safety inspector')->wife('Marge')->fav_fo +od('Duff');

    instead of

    $Person->name('Homer'); $Person->job('safety inspector'); $Person->wife('Marge'); $Person->fav_food('Duff');

    Of course the real answer is that you shouldn't need to make these assumptions, as you should be able to consult the documentation, even if, in the worse-case scenario, the only documentation is the source code.

    One of the joys of an interpreted language (interpreter/compiler debate aside) is that you always have the source to fall back on. None of the agony of trying to maintain and/or modify code that uses binary libararies for which the source and or documentation has long since disappeared or never existed in the first place.


    Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
Re: Getting Confused with the '->' operator
by robartes (Priest) on Sep 30, 2002 at 22:14 UTC
    In your first example: $interface->handler($client)->parse($local_file_name); the method that is called is the parse method of the object referenced by: $interface->handler($client). The arrow operator associates left to right, hence the above result.

    Your second example

    $Person->name('Homer') ->job('safety inspector') ->wife('Marge') ->fav_food('Duff');

    seems to be just plain weird. I might be (and almost certainly am) missing something - the same thing as you in that case :) - but I read this as "execute the method fav_food on the object returned by executing wife on the object returned by executing job on the object returned by executing name on the thingy referenced in $person" (arguments left out to save what little shreds of clarity remaining). Beats me. Help.

    CU

    Robartes -

      You are right, it does appear to be plain weird. It should evaluate differently than The_Don expected, with the -> operators operating left to right, so you did read it correctly. BrowserUK made a note about the Java APIs working this way, perhaps name(),job(),wife(), and (presumably)fav_food() all return the object that called it, that much is not clear.
      Personally, when writing classes I tend to have my mutators (set()s) return nothing, making a clear distinction between accessors and mutators (except in certain circumstances).
Re: Getting Confused with the '->' operator
by clintp (Curate) on Oct 01, 2002 at 00:28 UTC
    Others have offered explanations and if you'd like another example (perhaps something a little less textbook-like) I just grepped this from my scratch directory. It's hideous, yes, but demonstrates the point at hand.

    Newlines added for "clarity":

    print LWP::UserAgent->new()-> request( HTTP::Request->new(GET => 'http://geeksalad.org') )->content;
    Of course, there's no error checking in there (I didn't want it at the time). That'd make it look a bit more like:
    if (($_=LWP::UserAgent->new()-> request( HTTP::Request->new(GET=>'http://geeksalad.org') ))->is_success) { print $_->content; }
    I'm assuming, of course, that HTTP::Request isn't going to fail (unlikely anyway). And this doesn't allow me the opportunity to do anything useful with the UserAgent object other than what I could have accomplished with LWP::Simple. I have no idea why this was there, other than to serve as an example of some kind. Whether this was to demonstrate something good or bad, I can no longer remember. :)

    This mess is more commonly written as something like (edited from the LWP manpage):

    # Create a user agent object use LWP::UserAgent; $ua = new LWP::UserAgent; my $req = new HTTP::Request POST => 'http://geeksalad.org'; my $res = $ua->request($req); if ($res->is_success) { print $res->content; } else { print "Bad luck this time\n"; }
    So what my code snippet above did was exactly what's being done below, except that I don't put the request object into a variable ($req), and I don't put the user agent object ($ua) in one either. The only thing I stash away is the result ($res/$_) object because I have to call two methods (content, is_success) on it. Neither of these returns the original object, so I can't chain these together with ->'s.
Re: Getting Confused with the '->' operator
by the_Don (Scribe) on Oct 01, 2002 at 20:45 UTC

    I would again like to thank the Monastery for their responses. I have come to the final assumption that each call to the objects that set an attribute return the object; thus, 'set' calls can be chained.

    The final answer, which is so simple I that I apparently ignored, is that the '->' is left associative. This behavior as best I can tell mimics Java completely and I understand completely (I was taught computer science using Java).

    To address why I did not resort to source code for a definitive answer. The code that the system uses automatically creates accessor methods using a %fields hash. I do not have enough knowledge of existing modules to know where / how these accessors are automagically created nor if the auto-functions are a result of a CPAN module, an in-house module, or a hybrid. However, my past experience with the system has shown me that the level of extension with OO Perl reaches levels so deep and convoluded that it was a much better use of time to ask for assistance from strangers with no knowledge of the innner-workings than to seek assistance in-house.

    Again, I would like to thank everyone for their help. ++ for everyone ! :-)

    the_Don
    ...making offers others can't rufuse.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2024-04-19 01:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found