Using symbolic references to invoke package methods - good or bad practice?

Discussion in 'Perl Misc' started by jhumanski, Apr 20, 2012.

  1. jhumanski

    jhumanski Guest

    At my place of employment, a philosophical discussion is going on
    within the development group. Say you have the following package
    definition:

    package MyPackage;

    use strict;
    ....
    sub new {
    my $class = shift;

    my $self = bless {}, $class;
    $self->_init();
    return $self;
    }

    sub _init {
    my $self = shift;

    foreach my $property ('func1', 'func2', 'func3', 'func4') {
    $self->$property();
    }
    }

    sub func1 {...}
    sub func2 {...}
    sub func3 {...}
    sub func4 {...}

    In this example, the private method _init is invoking package methods
    using symbolic references.

    Many in the development team don't have a problem with this. They
    consider it a clean and extendible solution. While they recognize
    that symbolic references in general are bad, they justify this
    solution by stating that the use of the symbolic references is
    controlled and, hence, with little risk.

    I am in the minority. I am looking for justification (other than the
    standard mantra that symbolic references are bad) that this practice
    should be discouraged. I have googled this topic but have not found
    any specific examples that state why this practice is bad.

    I am looking for this group's opinion. Any examples that demonstrate
    why this is bad (or good) practice are appreciated.
     
    jhumanski, Apr 20, 2012
    #1
    1. Advertising

  2. jhumanski <> writes:

    > I am in the minority. I am looking for justification (other than the
    > standard mantra that symbolic references are bad) that this practice
    > should be discouraged. I have googled this topic but have not found
    > any specific examples that state why this practice is bad.


    You should not be generalizing solely based on a mantra. You need to
    understand the reason for the mantra, that is you need to understand why
    symbolic references are a bad idea.

    Then you can discusse if the same reasons holds for method calls.

    One reason not to like symbolic references is that they are only working
    for package variables (globals) and silently ignores the existence of
    lexical variables. Globals are as such discouraged for it own reasons,
    and ignoring lexical variables can mean some action on a distance where
    the meaning of code can change in a radical way due to seemingly
    unrelated code changes.

    This problem with symbolic references does not hold for methods as
    lexical methods does not exists in the same way.


    There are other problems with symbolic references. For some of them it
    could be argued that it also applies to symbolic method calls other
    problems can be dismissed.

    In the end it is up to your team to decide if the advantages outweights
    the problems.

    //Makholm
     
    Peter Makholm, Apr 20, 2012
    #2
    1. Advertising

  3. jhumanski <> writes:
    > At my place of employment, a philosophical discussion is going on
    > within the development group. Say you have the following package
    > definition:
    >
    > package MyPackage;
    >
    > use strict;
    > ...
    > sub new {
    > my $class = shift;
    >
    > my $self = bless {}, $class;
    > $self->_init();
    > return $self;
    > }
    >
    > sub _init {
    > my $self = shift;
    >
    > foreach my $property ('func1', 'func2', 'func3', 'func4') {
    > $self->$property();
    > }
    > }
    >
    > sub func1 {...}
    > sub func2 {...}
    > sub func3 {...}
    > sub func4 {...}
    >
    > In this example, the private method _init is invoking package methods
    > using symbolic references.


    This is a standard, documented feature of Perl, cf

    The right side of the arrow typically is the method name, but
    a simple scalar variable containing either the method name or
    a subroutine reference can also be used.
    [perlobj(1)]

    [...]

    > I am looking for justification (other than the standard mantra that
    > symbolic references are bad) that this practice should be
    > discouraged.


    If you have no idea why it should be discouraged, why should it be
    discouraged?
     
    Rainer Weikusat, Apr 20, 2012
    #3
  4. jhumanski

    Uri Guttman Guest

    >>>>> "j" == jhumanski <> writes:

    j> package MyPackage;

    j> sub new {
    j> my $class = shift;

    j> my $self = bless {}, $class;
    j> $self->_init();
    j> return $self;
    j> }

    j> foreach my $property ('func1', 'func2', 'func3', 'func4') {
    j> $self->$property();

    j> In this example, the private method _init is invoking package methods
    j> using symbolic references.

    to be accurate those are not symbolic references. methods are always
    looked up in the symbol table (late binding) when they are called (there
    is some caching for speed). lexical vars are handled at compile time and
    so can be made strict which disallows symrefs in the proper sense.

    the technique of using late binding of methods is actually a good one
    and it can be very powerful. it can be seen as the method version of a
    dispatch table which is for procedural calls.

    j> Many in the development team don't have a problem with this. They
    j> consider it a clean and extendible solution. While they recognize
    j> that symbolic references in general are bad, they justify this
    j> solution by stating that the use of the symbolic references is
    j> controlled and, hence, with little risk.

    your issue is not whether it is a good idea but conflating late binding
    of method calls with symbolic references. they are not the same beast at
    all and so they shouldn't be compared.

    j> I am in the minority. I am looking for justification (other than the
    j> standard mantra that symbolic references are bad) that this practice
    j> should be discouraged. I have googled this topic but have not found
    j> any specific examples that state why this practice is bad.

    j> I am looking for this group's opinion. Any examples that demonstrate
    j> why this is bad (or good) practice are appreciated.

    it is used in many modules on cpan whereas symrefs are not commonly used
    (except when actually munging the symbol table which should be their
    only use). you may not find examples easily but they are out there. this
    is a perfectly fine perl idiom so don't fret over it and just use it.

    uri
     
    Uri Guttman, Apr 20, 2012
    #4
  5. jhumanski

    Tim McDaniel Guest

    I *wish* "use strict" would do more compile-time checking for subs.
    But it doesn't flag anything for

    foreach my $property (\&func1, \&func2, \&func5) {
    ...
    sub func1 { print "func1\n"; }
    sub func2 { print "func2\n"; }
    sub func3 { print "func3\n"; }

    until runtime, when it goes to call the missing func5.

    Personally, I still prefer the explicit function reference, if for no
    other reason that, even if you only look at
    foreach my $property (\&func1, \&func2, \&func5) {
    it's clearly a list of sub references and it's likely that they will
    be called, but for
    foreach my $property ('func1', 'func2', 'func5') {
    you have to look down to see how $property is being used to know what
    they are.

    But I'm unusual in liking to be explicit about things: initializations
    and uses and such. I like to use fully-qualified names like
    ThisMod::ThatMod::SomeSub() even if there has been importing, just to
    make it clear where it's from. Or
    my @result = ();
    just to make it clear that I've considered it and I do really need it
    to be an empty array, or
    {
    my @working = ();
    ...
    }
    to make it clear where the variable dies.

    --
    Tim McDaniel,
     
    Tim McDaniel, Apr 20, 2012
    #5
  6. (Tim McDaniel) writes:
    > I *wish* "use strict" would do more compile-time checking for subs.
    > But it doesn't flag anything for
    >
    > foreach my $property (\&func1, \&func2, \&func5) {
    > ...
    > sub func1 { print "func1\n"; }
    > sub func2 { print "func2\n"; }
    > sub func3 { print "func3\n"; }
    >
    > until runtime, when it goes to call the missing func5.
    >
    > Personally, I still prefer the explicit function reference, if for no
    > other reason that, even if you only look at
    > foreach my $property (\&func1, \&func2, \&func5) {
    > it's clearly a list of sub references and it's likely that they will
    > be called


    That won't work in this case because it was about method calls, see
    contrived example below:

    -------------------
    package Parent;

    sub new {
    return bless([], $_[0]);
    }

    sub blah
    {
    print("Blah!\n");
    }

    package Child;

    our @ISA = qw(Parent);

    sub blubb
    {
    print("Blubb!\n");
    }

    package main;

    my $c = Child->new();

    # call the method
    #
    $c->$_() for (qw(blubb blah));

    # this doesn't work
    #
    eval {
    $c->$_() for (\&blubb, \&blah);
    };
    print("$@");

    # neither does this
    #
    eval {
    $c->$_() for (\&Child::blubb, \&Child::blah);
    };
    print("$@");
     
    Rainer Weikusat, Apr 20, 2012
    #6
  7. jhumanski

    Tim McDaniel Guest

    In article <>,
    Rainer Weikusat <> wrote:
    > (Tim McDaniel) writes:
    >> Personally, I still prefer the explicit function reference, if for no
    >> other reason that, even if you only look at
    >> foreach my $property (\&func1, \&func2, \&func5) {
    >> it's clearly a list of sub references and it's likely that they will
    >> be called

    >
    >That won't work in this case because it was about method calls, see
    >contrived example below:


    Summary of the example: Package Parent has blah(). Package Child ISA
    Parent and adds blubb(). Instantiate Child->new().

    In package main, plain \&blubb and \&blah don't work because they are
    equivalent to \&main::blubb and \&main::blah, which don't exist.
    \&Child::blubb and \&Child::blah don't work because &Child::blah
    doesn't exist.

    He didn't mention \&Parent::blubb and \&Parent::blah, but they
    wouldn't work either, because &Parent::blubb doesn't exist and
    (if Child were to redefine blah) &Parent::blah would bypass Child's
    override.

    But calling the literal strings 'blubb' and 'blah' work fine, and they
    follow inheritance.

    Well, blah! That's a "blah!" directed at Perl and the entire
    situation, not at Rainer, who provided a most help example. Thank
    you.

    --
    Tim McDaniel,
     
    Tim McDaniel, Apr 21, 2012
    #7
  8. jhumanski

    Tim McDaniel Guest

    In article <>,
    Ben Morrow <> wrote:
    >Well, yes? Don't treat methods as though they were functions.


    Well, when you see "sub foo", it kinda makes you think of functions
    somehow ...

    >Are you looking for ->can? This resolves the method and returns a
    >coderef: it's effectively the equivalent of \&foo for methods. (And,
    >just like \&foo, it will under some circumstances return a stub,
    >which may or may not turn out to resolve to a real method when you
    >call it.)


    I had written a paragraph asking about that but deleted it before
    posting. Congratulations on the telepathy!

    For anyone else who hadn't heard of it, a little Web search shows that
    it's in built-in class UNIVERSAL, so "man UNIVERSAL" or
    http://perldoc.perl.org/UNIVERSAL.html

    The doc mentions some concerns with AUTOLOAD, as you alluded to
    above. I assume that, like any deep pointer, $obj->can has the
    limitation that it's good only for the current state of $obj, so you
    won't get a pointer with serious mojo that works even if $obj is later
    changed to be some other type of object. CLASS->can works anyway.

    --
    Tim McDaniel,
     
    Tim McDaniel, Apr 21, 2012
    #8
  9. Ben Morrow <> writes:
    > Quoth :


    [...]


    >> But calling the literal strings 'blubb' and 'blah' work fine, and they
    >> follow inheritance.

    >
    > Are you looking for ->can? This resolves the method and returns a
    > coderef: it's effectively the equivalent of \&foo for methods. (And,
    > just like \&foo, it will under some circumstances return a stub, which
    > may or may not turn out to resolve to a real method when you call
    > it.)


    As addition to the already posted code (tested on 5.10.1):

    -------------
    # nor this
    #'
    eval {
    $c->can($_)->() for qw(blubb blah);
    };
    print("$@");

    # nor this
    #'
    eval {
    $c->$_() for map { Child->can($_); } qw(blubb blah);
    };
    print("$@");
    -------------

    NB: At least with Perl 5.10.1, using map in this way together with for
    is not a good idea: At the implementation level, this is a two pass
    algorithm which first iterates over all of the 'input' values in order
    to create the list returned by map and then loops over this list,
    executing the actual loop body.
     
    Rainer Weikusat, Apr 22, 2012
    #9
  10. jhumanski

    Tim McDaniel Guest

    In article <>,
    Rainer Weikusat <> wrote:
    >Ben Morrow <> writes:
    >> Quoth :

    >
    >[...]
    >
    >
    >>> But calling the literal strings 'blubb' and 'blah' work fine, and they
    >>> follow inheritance.

    >>
    >> Are you looking for ->can? This resolves the method and returns a
    >> coderef: it's effectively the equivalent of \&foo for methods. (And,
    >> just like \&foo, it will under some circumstances return a stub, which
    >> may or may not turn out to resolve to a real method when you call
    >> it.)

    >
    >As addition to the already posted code (tested on 5.10.1):
    >
    >-------------
    ># nor this
    >#'
    >eval {
    > $c->can($_)->() for qw(blubb blah);
    >};
    >print("$@");
    >
    ># nor this
    >#'
    >eval {
    > $c->$_() for map { Child->can($_); } qw(blubb blah);
    >};
    >print("$@");


    To expand on that:

    The example had package Parent with sub blah, package Child ISA Parent
    and adding sub blubb, "my $c = Child->new();". Both of the two evals
    above result in the error messages

    Undefined subroutine &Child::blah called at ...

    Which I don't understand, given that "man UNIVERSAL" on my current
    system says

    "$obj->can( METHOD )"
    "CLASS->can( METHOD )"
    "eval { VAL->can( METHOD ) }"

    "can" checks if the object or class has a method called
    "METHOD". If it does, then it returns a reference to the sub.
    If it does not, then it returns undef. This includes methods
    inherited or imported by $obj, "CLASS", or "VAL".

    --
    Tim McDaniel,
     
    Tim McDaniel, Apr 22, 2012
    #10
  11. jhumanski

    Tim McDaniel Guest

    In article <>,
    Ben Morrow <> wrote:
    >
    >Quoth :
    >> In article <>,
    >> Rainer Weikusat <> wrote:
    >> >
    >> >As addition to the already posted code (tested on 5.10.1):
    >> >
    >> >-------------
    >> ># nor this
    >> >#'
    >> >eval {
    >> > $c->can($_)->() for qw(blubb blah);
    >> >};
    >> >print("$@");
    >> >
    >> ># nor this
    >> >#'
    >> >eval {
    >> > $c->$_() for map { Child->can($_); } qw(blubb blah);
    >> >};
    >> >print("$@");

    >>
    >> To expand on that:
    >>
    >> The example had package Parent with sub blah, package Child ISA Parent
    >> and adding sub blubb, "my $c = Child->new();". Both of the two evals
    >> above result in the error messages
    >>
    >> Undefined subroutine &Child::blah called at ...

    >
    >What code are you running, exactly? If I run
    >
    > #!/usr/bin/perl
    >
    > {
    > package Parent;
    > sub new { bless [], $_[0] }
    > sub blah { warn "blah" }
    > }
    >
    > {
    > package Child;
    > our @ISA = "Parent";
    > sub blubb { warn "blubb" }
    > }
    >
    > my $c = Child->new;
    >
    > eval {
    > $c->$_() for map { Child->can($_); } qw(blubb blah);
    > };
    > warn "err: $@";
    >
    >I get
    >
    > blubb at can line 12.
    > blah at can line 6.
    > err: at can line 20.
    >
    >Just to be sure something weird wasn't going on, I even checked with
    >5.10.1.


    5.10.1 here, and the test program in 102.pl is as follows: it's the
    example from a few articles back with Rainer's. I know so
    little about packages and classes and such in Perl that I can't start
    to see what might be significant about differences. You wrap the
    backages in blocks and the original does not.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    package Parent;

    sub new {
    return bless([], $_[0]);
    }

    sub blah
    {
    print("Blah!\n");
    }

    package Child;

    our @ISA = qw(Parent);

    sub blubb
    {
    print("Blubb!\n");
    }

    package main;

    my $c = Child->new();

    # call the method
    #
    $c->$_() for (qw(blubb blah));

    # this doesn't work
    #
    eval {
    $c->$_() for (\&blubb, \&blah);
    };
    print("$@");

    # neither does this
    #
    eval {
    $c->$_() for (\&Child::blubb, \&Child::blah);
    };
    print("$@");

    # nor this
    #'
    eval {
    $c->can($_)->() for qw(blubb blah);
    };
    print("$@");

    # nor this
    #'
    eval {
    $c->$_() for map { Child->can($_); } qw(blubb blah);
    };
    print("$@");

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    The output:

    $ perl local/test/102.pl
    Blubb!
    Blah!
    Undefined subroutine &main::blubb called at local/test/102.pl line 32.
    Blubb!
    Undefined subroutine &Child::blah called at local/test/102.pl line 39.
    Blubb!
    Undefined subroutine &Child::blah called at local/test/102.pl line 46.
    Blubb!
    Undefined subroutine &Child::blah called at local/test/102.pl line 53.
     
    Tim McDaniel, Apr 23, 2012
    #11
  12. jhumanski

    Tim McDaniel Guest

    In article <>,
    Ben Morrow <> wrote:
    >
    >Quoth Rainer Weikusat <>:
    >> Ben Morrow <> writes:
    >> >
    >> > Are you looking for ->can? This resolves the method and returns a
    >> > coderef: it's effectively the equivalent of \&foo for
    >> > methods. (And, just like \&foo, it will under some circumstances
    >> > return a stub, which may or may not turn out to resolve to a real
    >> > method when you call it.)

    >>
    >> As addition to the already posted code (tested on 5.10.1):
    >>
    >> -------------
    >> # nor this
    >> #'
    >> eval {
    >> $c->can($_)->() for qw(blubb blah);
    >> };
    >> print("$@");

    >
    >This isn't supposed to work: the coderef returned by can does not
    >include an implicit invocant, you have to provide one explicitly.
    >
    >> # nor this
    >> #'
    >> eval {
    >> $c->$_() for map { Child->can($_); } qw(blubb blah);
    >> };
    >> print("$@");

    >
    >This works just fine


    It took me a bit of looking at the second to decode the first
    comment. Is this what it means?

    $c->can('blubb') or whatever returns a reference to a sub --
    specifically a reference to a class method. To use any class method,
    you need to apply it to something, like an instance of the class. So
    $c->($c->can('blubb'))->() should work (and I think you need not put
    in the last "->").

    Given that the subs in the example code I was working from (just
    posted in anothe rfork of this thread) do not refer to @_, do these
    particular subs really need to be invoked for an object?

    --
    Tim McDaniel,
     
    Tim McDaniel, Apr 23, 2012
    #12
  13. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >> Ben Morrow <> writes:
    >> >
    >> > Are you looking for ->can? This resolves the method and returns a
    >> > coderef: it's effectively the equivalent of \&foo for methods. (And,
    >> > just like \&foo, it will under some circumstances return a stub, which
    >> > may or may not turn out to resolve to a real method when you call
    >> > it.)

    >>
    >> As addition to the already posted code (tested on 5.10.1):
    >>
    >> -------------
    >> # nor this
    >> #'
    >> eval {
    >> $c->can($_)->() for qw(blubb blah);
    >> };
    >> print("$@");

    >
    > This isn't supposed to work: the coderef returned by can does not
    > include an implicit invocant, you have to provide one explicitly.


    There is no such thing as 'an invocant' in perl. A class is a package
    and a method is nothing but a subroutine located in a specific way (by
    looking at the package the 'invocant' was blessed into in order to
    determine where to start search for a sub of the given name). Provided
    such subroutine was found, it is then called with the 'invocant' as
    $_[0] and the remaining arguments following after it. Since can is
    supposed to do a method search, there's no need for doing another
    method search: The result is a sub reference which can be called like
    any other sub reference. Since neither of the two looks at @_, there's
    no need to pass any arguments to it.

    That was the technical explanation. Replacing the (correct) code I was
    using with the kind of code you believe to be correct, namely,

    -----------
    # nor this
    #'
    eval {
    for (qw(blubb blah)) {
    $m = $c->can($_);
    $c->$m();
    }
    };
    print("$@");
    ----------

    leads to the exact same result:

    Blubb!
    Undefined subroutine &Child::blah called at a.pl line 48.

    NB: The $c->$m() can also be written as $m->($c).

    [...]

    >> $c->$_() for map { Child->can($_); } qw(blubb blah);


    [...]

    >> NB: At least with Perl 5.10.1, using map in this way together with for
    >> is not a good idea: At the implementation level, this is a two pass
    >> algorithm which first iterates over all of the 'input' values in order
    >> to create the list returned by map and then loops over this list,
    >> executing the actual loop body.

    >
    > It is in principle a little less efficient than a streaming
    > implementation, yes, though for a list of two elements (or, indeed, 200)
    > this is extremely unlikely to be visible in practice. Trying to avoid
    > temporary lists means effectively avoiding 'for' altogether, and it's
    > far too useful for that.


    You seem to have missed the point of my text: I wasn't writing about
    'temporay lists' but about a two-pass algorithm: The for ... map is
    compiled to code which executes two loops instead of one (at least on
    Perl 5.10.0). And this implies that the mapping step should rather be
    done as part of the loop body. It would be nice if perl could do this
    conversion (or something which accomplished the same thing)
    implicitly.
     
    Rainer Weikusat, Apr 23, 2012
    #13
  14. Ben Morrow <> writes:
    > From: Ben Morrow <>
    > Subject: Re: Using symbolic references to invoke package methods - good or bad practice?
    > Newsgroups: comp.lang.perl.misc
    > Date: Mon, 23 Apr 2012 15:39:52 +0100
    >
    >
    > Quoth Rainer Weikusat <>:
    >>
    >> -----------
    >> # nor this
    >> #'
    >> eval {
    >> for (qw(blubb blah)) {
    >> $m = $c->can($_);
    >> $c->$m();
    >> }
    >> };
    >> print("$@");
    >> ----------
    >>
    >> leads to the exact same result:
    >>
    >> Blubb!
    >> Undefined subroutine &Child::blah called at a.pl line 48.

    >
    > No it doesn't.


    It does. The code is the one I originally posted with some appended/
    modified parts. In this case the reason for the error message was
    that it contained a \&Child::blah before the can invocation. This
    effectively kills the overload mechanism for blah because it creates
    an 'undefined' Child::blah sub which exists in the symbol table of
    Child. Trying to invoke the method in the usual way also won't work
    afterwards.

    [...]

    >> You seem to have missed the point of my text: I wasn't writing about
    >> 'temporay lists' but about a two-pass algorithm: The for ... map is
    >> compiled to code which executes two loops instead of one (at least on
    >> Perl 5.10.0). And this implies that the mapping step should rather be
    >> done as part of the loop body. It would be nice if perl could do this
    >> conversion (or something which accomplished the same thing)
    >> implicitly.

    >
    > I understood perfectly: the map runs one loop, which builds a temporary
    > list, and the for runs another which consumes it. I see the temporary
    > storage required as more of a 'problem' than the two loops:
    >
    > the two loops perform the same steps as one would have, they just do
    > them in a different order.


    [...]

    They don't. That was what I was writing about. The additional steps
    are the operations required to perform the second loop. This implies
    that using map in this way has twice the looping overhead of a loop
    which does the transformation 'inline'.
     
    Rainer Weikusat, Apr 23, 2012
    #14
  15. Ben Morrow <> writes:
    > From: Ben Morrow <>
    > Subject: Re: Using symbolic references to invoke package methods - good or bad practice?
    > Newsgroups: comp.lang.perl.misc
    > Date: Mon, 23 Apr 2012 15:39:52 +0100
    >
    >
    > Quoth Rainer Weikusat <>:
    >>
    >> -----------
    >> # nor this
    >> #'
    >> eval {
    >> for (qw(blubb blah)) {
    >> $m = $c->can($_);
    >> $c->$m();
    >> }
    >> };
    >> print("$@");
    >> ----------
    >>
    >> leads to the exact same result:
    >>
    >> Blubb!
    >> Undefined subroutine &Child::blah called at a.pl line 48.

    >
    > No it doesn't.


    It does. The code is the one I originally posted with some appended/
    modified parts. In this case the reason for the error message was
    that it contained a \&Child::blah before the can invocation. This
    effectively kills the inheritance mechanism for blah because it creates
    an 'undefined' Child::blah sub which exists in the symbol table of
    Child. Trying to invoke the method in the usual way also won't work
    afterwards.

    [...]

    >> You seem to have missed the point of my text: I wasn't writing about
    >> 'temporay lists' but about a two-pass algorithm: The for ... map is
    >> compiled to code which executes two loops instead of one (at least on
    >> Perl 5.10.0). And this implies that the mapping step should rather be
    >> done as part of the loop body. It would be nice if perl could do this
    >> conversion (or something which accomplished the same thing)
    >> implicitly.

    >
    > I understood perfectly: the map runs one loop, which builds a temporary
    > list, and the for runs another which consumes it. I see the temporary
    > storage required as more of a 'problem' than the two loops:
    >
    > the two loops perform the same steps as one would have, they just do
    > them in a different order.


    [...]

    They don't. That was what I was writing about. The additional steps
    are the operations required to perform the second loop. This implies
    that using map in this way has twice the looping overhead of a loop
    which does the transformation 'inline'.
     
    Rainer Weikusat, Apr 23, 2012
    #15
  16. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >> Ben Morrow <> writes:


    [...]

    >>> I understood perfectly: the map runs one loop, which builds a temporary
    >>> list, and the for runs another which consumes it. I see the temporary
    >>> storage required as more of a 'problem' than the two loops:
    >>>
    >>> the two loops perform the same steps as one would have, they just do
    >>> them in a different order.

    >>
    >> They don't. That was what I was writing about. The additional steps
    >> are the operations required to perform the second loop. This implies
    >> that using map in this way has twice the looping overhead of a loop
    >> which does the transformation 'inline'.

    >
    > Oh, I see; yes, I suppose that's true, but if you've got to the point of
    > worrying about the overhead of the for or map loop itself you shouldn't
    > be writing in Perl any more. If you need that level of efficiency, you
    > need to do it in C.


    Once upon a time the past, there was a guy called Rasumus Lehrdorf who
    had a homepage. He tried to pep it up a little by adding various CGI
    scripts written in Perl to it but somehow, he couldn't get his Perl
    code to perform adequately. So, he then set off and wrote a simple HTML
    preprocessor in C which he christened the Personal HomePage tools
    and published them on the net (and the rest - as they say - is history
    ....).

    I use Perl serious system programming tasks and because of this, I
    absolutely do care about the performance of the Perl code I write: I'm
    fine with burning cycles in exchange for some tangible benefit, eg,
    aggressively partition code into subroutines in order to make it
    easier to maintain _intermittently_ (I'm not living inside some huge
    body of code written by no-one-knows-who where I wander around in
    order to explore it so that I can occasionally make minor changes
    without breaking something. The typical situation is rather that I
    need to add a new, not entirely trivial feature to something I haven't
    seen for 20 months and preferably quickly). I'm not at all keen on
    burning cycles just because I can do so easily.

    In this particular case, using a somewhat silly simple example,

    ------------
    #!/usr/bin/perl

    use Benchmark;

    sub wmap {
    my @out;

    push(@out, $_) for map { $_ + 1; } @_;
    return @out;
    }

    sub nmap {
    my @out;

    push(@out, $_ + 1) for @_;
    return @out;
    }


    timethese(-10,
    {
    wmap => sub { wmap(1 .. 5); },
    nmap => sub { nmap(1 .. 5); }});
    -------------

    the variant using map needs to execute four more ops per input element
    and the other, the actual counts (perl -MO=Concise,-exec) being 13 and
    9, respectively, and the corresponding quotient appears also in the
    measured execution speed: The subroutine which has about 1.44... times
    more elementary operation runs at about 1/(1.4) of the speed of the
    other.
     
    Rainer Weikusat, Apr 24, 2012
    #16
    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. vlsidesign
    Replies:
    26
    Views:
    1,048
    Keith Thompson
    Jan 2, 2007
  2. SM
    Replies:
    9
    Views:
    533
  3. rantingrick
    Replies:
    44
    Views:
    1,304
    Peter Pearson
    Jul 13, 2010
  4. Rajesh

    doubt regarding Symbolic references

    Rajesh, Mar 8, 2005, in forum: Perl Misc
    Replies:
    3
    Views:
    95
    Chris Mattern
    Mar 8, 2005
  5. mike

    can't create symbolic references

    mike, Mar 26, 2006, in forum: Perl Misc
    Replies:
    1
    Views:
    88
    Matt Garrish
    Mar 26, 2006
Loading...

Share This Page