Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re^2: Number of times I've used goto in Perl

by Eily (Monsignor)
on Sep 26, 2018 at 13:01 UTC ( #1223064=note: print w/replies, xml ) Need Help??


in reply to Re: Number of times I've used goto in Perl
in thread Number of times I've used goto in Perl

Well the people mentioning AUTOLOAD are actually talking about this version of goto. For example this post explicitly mentions goto &{ $AUTOLOAD };.

The interest of goto isn't only about the fact that it transmits the current value of @_ to the called sub. Actually this is already the case when you do this:

sub exportFunctionName { &_internalImplementation; }
this is documented in perlsub
If a subroutine is called using the & form, the argument list is optional, and if omitted, no @_ array is set up for the subroutine: the @_ array at the time of the call is visible to subroutine instead. This is an efficiency mechanism that new users may wish to avoid.
Actually I'm pretty sure there was a post about goto being slower than a simple function call (because it has to exit the the local changes) but I couldn't find it.

So the main interest of goto lies in the fact that it doesn't add a function to the calling stack but instead replaces the current one. This means that with this code:

sub A { goto &_A; } sub _A { B(); }
The B function will never see &A in the calling stack, but only &_A. This can be used for debbuging, when you want to call a wrapper function (to print "About to enter &function", or check the input). I remember this question where this was precisely what the OP asked for.

Replies are listed 'Best First'.
Re^3: Number of times I've used goto in Perl
by HugoNo1 (Novice) on Sep 26, 2018 at 18:34 UTC

    According to the official Documentation on

    https://perldoc.perl.org/perlperf.html#Assigning-and-Dereferencing-Variables.
    > The difference is clear to see and the dereferencing approach is slower.

    Dereferencing Variables is slower than Passing the References through.

    Therefore a Code like:

    package MyClass1; sub newFunctionName { #Doing my stuff } sub oldFunctionName { my $self = shift; $self->newFunctionName(@_); }

    As you would do it in other Programming Languages. Will be slower than the goto Implementation:

    package MyClass2; sub newFunctionName { #Doing the stuff } sub oldFunctionName { goto &newFunctionName; }

    That is what I exactly was looking for but couldn't find any concrete Example for it.

    This makes Sense because in the MyClass1::oldFunctionName() implemention the $self variable must be created in memory first which consumes CPU Processing Time.
    Which is confirmed by the official Documentation.

      That doesn't contradict my point, which was that goto has 3 effects: transmitting @_ directly, removing the current function from the call stack and clearing the effect of local. If all you want to do is jump to another function without touching @_, this can be done like this:

      sub oldFunctionName { &newFunctionName; }
      I have quoted the relevant documentation in my previous post.

      Besides, since goto does this extra work, I wouldn't be confident about saying that it uses less CPU. Also perl does plenty of things under the hood, and the documentation calls it "magic". I would never conclude that a feature takes less CPU time based on the description of what it does alone.

      There is no dereferencing in your code though, dereferencing would like one of those lines:

      $$self; ${$self}; @{$self}; %{$self}; $self->{Key}; $self->[0];
      Sadly the syntax for a method call works only on (some) references, and also uses the arrow operator ( -> ) so it's quite confusing.

        I wrote a little benchmark test to check the performance of different implementations

        package MyClass1;
        
        sub new
        {
          my $invocant = shift;
          my $class    = ref($invocant) || $invocant;
          my $self     = undef;
        
        
            #Set the Default Attributes and assign the initial Values
            $self = {
                "_report" => "",
                "_count" => 0
            };
        
        
            #Bestow Objecthood
            bless $self, $class;
        
        
            #Give the Object back
            return $self;
          
        }
        
        sub newFunctionName
        {
          my $self = shift;
          
          $self->{"_count"} = shift;
          $self->{"_report"} = __PACKAGE__ . " - run no. '" . $self->{"_count"} . "'\n";
        }
        
        sub oldFunctionName
        {
          my $self = shift;
          
          $self->newFunctionName(@_);
        }
        
        
        package MyClass2;
        
        sub new
        {
          my $invocant = shift;
          my $class    = ref($invocant) || $invocant;
          my $self     = undef;
        
        
            #Set the Default Attributes and assign the initial Values
            $self = {
                "_report" => "",
                "_count" => 0
            };
        
        
            #Bestow Objecthood
            bless $self, $class;
        
        
            #Give the Object back
            return $self;
          
        }
        
        sub newFunctionName
        {
          my $self = shift;
          
          $self->{"_count"} = shift;
          $self->{"_report"} = __PACKAGE__ . " - run no. '" . $self->{"_count"} . "'\n";
        }
        
        sub oldFunctionName
        {
          goto &newFunctionName;
        }
        
        
        package MyClass3;
        
        sub new
        {
          my $invocant = shift;
          my $class    = ref($invocant) || $invocant;
          my $self     = undef;
        
        
            #Set the Default Attributes and assign the initial Values
            $self = {
                "_report" => "",
                "_count" => 0
            };
        
        
            #Bestow Objecthood
            bless $self, $class;
        
        
            #Give the Object back
            return $self;
          
        }
        
        sub newFunctionName
        {
          my $self = shift;
          
          $self->{"_count"} = shift;
          $self->{"_report"} = __PACKAGE__ . " - run no. '" . $self->{"_count"} . "'\n";
        }
        
        sub oldFunctionName
        {
          &newFunctionName;
        }
        
        
        package main;
        
        use Benchmark;
        
             
        my $o1 = MyClass1->new;
        my $o2 = MyClass2->new;
        my $o3 = MyClass3->new;
        my $icnt = 0;
        
             
             
        print "count 0: '$icnt':\n";
        
        print "o1 report 0 (count: '" . $o1->{"_count"} . "'): '" . $o1->{"_report"} . "'\n";
        print "o2 report 0 (count: '" . $o2->{"_count"} . "'): '" . $o2->{"_report"} . "'\n";
        print "o3 report 0 (count: '" . $o3->{"_count"} . "'): '" . $o3->{"_report"} . "'\n";
        
         timethese( 10000000, {
         'MyClass1'  => sub { 
         
         $icnt = 0 if($o1->{"_count"} == 0);
         
         $icnt++;
         $o1->oldFunctionName($icnt);
         
        
        },
         'MyClass2'  => sub { 
        
         $icnt = 0 if($o2->{"_count"} == 0);
         
         $icnt++;
         $o2->oldFunctionName($icnt);
        
        
         },
         'MyClass3'  => sub { 
        
         $icnt = 0 if($o3->{"_count"} == 0);
         
         $icnt++;  
         $o3->oldFunctionName($icnt);
        
        
         },
         });
        
             
        print "count 0: '$icnt':\n";
        
        print "o1 report 0 (count: '" . $o1->{"_count"} . "'): '" . $o1->{"_report"} . "'\n";
        print "o2 report 0 (count: '" . $o2->{"_count"} . "'): '" . $o2->{"_report"} . "'\n";
        print "o3 report 0 (count: '" . $o3->{"_count"} . "'): '" . $o3->{"_report"} . "'\n";
        

        The test result was:

        count 0: '0':
        o1 report 0 (count: '0'): ''
        o2 report 0 (count: '0'): ''
        o3 report 0 (count: '0'): ''
        Benchmark: timing 10000000 iterations of MyClass1, MyClass2, MyClass3...
          MyClass1:  8 wallclock secs ( 7.48 usr +  0.00 sys =  7.48 CPU) @ 1336898.40/s (n=10000000)
          MyClass2:  7 wallclock secs ( 6.61 usr +  0.00 sys =  6.61 CPU) @ 1512859.30/s (n=10000000)
          MyClass3:  6 wallclock secs ( 5.96 usr +  0.00 sys =  5.96 CPU) @ 1677852.35/s (n=10000000)
        count 0: '10000000':
        o1 report 0 (count: '10000000'): 'MyClass1 - run no. '10000000'
        '
        o2 report 0 (count: '10000000'): 'MyClass2 - run no. '10000000'
        '
        o3 report 0 (count: '10000000'): 'MyClass3 - run no. '10000000'
        '
        

        I repeated the test several times and it gives always the same result pattern.
        - The slowest performant implementation is MyClass1 with the $self->newFunctionName(@_); call
        - The MyClass2::oldFunctionName() implementation with the goto statement performs already better.
        - But the best performance is achieved with the MyClass3::oldFunctionName() implementation with the &newFunctionName; call

        I didn't know this possible Syntax yet.
        So thank you very much!

      87 core Perl (5.28.0) modules (out of 650) use goto 253 times:
      
      _charnames
      Archive::Tar
      attributes
      autodie
      autodie::Util
      AutoLoader
      AutoSplit
      autouse
      B
      B::Concise
      B::Deparse
      B::Op_private
      bytes
      Class::Struct
      Compress::Raw::Bzip2
      Compress::Raw::Zlib
      Config
      CPAN
      CPAN::Distribution
      DB_File
      Devel::Peek
      Devel::PPPort
      diagnostics
      DynaLoader
      Encode
      Exporter
      ExtUtils::CBuilder::Base
      ExtUtils::Command::MM
      ExtUtils::Constant
      ExtUtils::Liblist
      ExtUtils::MM_VMS
      Fatal
      fields
      File::Compare
      File::Copy
      File::DosGlob
      File::Glob
      File::Path
      File::stat
      Filter::Simple
      Getopt::Long
      Hash::Util
      if
      IO::Select
      IO::Socket::IP
      IO::Uncompress::Base
      IPC::SysV
      List::Util
      Locale::Codes::Language_Codes
      Memoize
      Module::Load
      mro
      Net::FTP
      Net::hostent
      Net::netent
      Net::protoent
      Net::servent
      ok
      Opcode
      open
      Pod::Functions
      Pod::Simple::BlackBox
      Pod::Simple::LinkSection
      POSIX
      SelfLoader
      sigtrap
      strict
      Sys::Syslog
      TAP::Parser
      TAP::Parser::Aggregator
      TAP::Parser::Result::Test
      Term::ANSIColor
      Term::Cap
      Test2::EventFacet::Meta
      Test2::IPC
      Test::Tester
      Test::Tester::Delegate
      Text::Balanced
      threads
      Tie::Memoize
      Time::HiRes
      Unicode::UCD
      User::grent
      User::pwent
      utf8
      warnings
      XSLoader
      

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1223064]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (6)
As of 2019-10-17 21:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?