in reply to Re^3: Removing AUTOLOAD from CGI.pm
in thread Removing AUTOLOAD from CGI.pm

Not sure why AUTOLOAD is needed in CGI anyway, the allowed HTML-tags seem to be exported from CGI to the local namespace, but only spring into existence within the stash of %CGI:: after first use! ¹

Speed can't be that relevant, CGI doesn't do any syntax validation, so the same generic function could be installed at import time for all html-tags, maybe with a closed over $tag_name if necessary.

What am I missing?

Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)

PS: Je suis Charlie!

¹) didn't know it's possible to predeclare an AUTOLOADed sub ... (scratch)

update

interesting...

DB<181> package Test; sub AUTOLOAD { $AUTOLOAD,\@_ } DB<182> bar(1,2,3) Undefined subroutine &main::bar called at (eval 196)[multi_perl5db.pl: +644] line 2. DB<183> Test::bar(1,2,3) => ("Test::bar", [1, 2, 3]) DB<184> *bar=\&Test::bar DB<185> bar(1,2,3) => ("Test::bar", [1, 2, 3])

but

DB<186> *foo=*Test::foo DB<187> foo(1,2,3) Undefined subroutine &Test::foo called at (eval 206)[multi_perl5db.pl: +644] line 2.

Replies are listed 'Best First'.
Re^5: Removing AUTOLOAD from CGI.pm
by leej (Monk) on Feb 24, 2015 at 12:36 UTC

    > Not sure why AUTOLOAD is needed in CGI anyway, the allowed HTML-tags seem to be exported from CGI to the local namespace, but only spring into existence within the stash of %CGI:: after first use! Speed can't be that relevant, CGI doesn't do any syntax validation, so the same generic function could be installed at import time for all html-tags, maybe with a closed over $tag_name if necessary.

    I believe the original reason was to defer the compilation so the majority of functions, not just html functions, were wrapped in quotes and then eval'd and added to the namespace when called. Or you could pass -compile (or call ->compile) to force them to compile at import time. It was kind of a way to fix the God object problem when compiling a 4000+ line module was slow. An added side effect was the ability to call CGI with arbitrary tags not included in the module... it was future proofed! You could call CGI->wibble and get a <wibble> tag.

    Anyway it's all gone now, or soon will be.

      Hi

      I wasn't criticizing CGI but trying to analyze the conditions for a new HTML DSL module. :)

      I'm sure compilation speed shouldn't matter when generating closures. (I will add a benchmark later this day)

      But CGI was designed for Perl 4 and I suppose Perl 4 wasn't able to closure... IIRC it didn't even have lexical variables.

      Your wibble-tag is implemented as a method call, so it wouldn't depend on exporting and pre declaration anyway.

      But DSLs are at the very least just syntactic sugar to avoid method calls.

      > Anyway it's all gone now, or soon will be

      Thanks for your work! :)

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)

      PS: Je suis Charlie!

        > I'm sure compilation speed shouldn't matter when generating closures. (I will add a benchmark later this day)

        Here a simplified example which showed that installing subs with closures¹ is 5 times faster than eval.

        That's less dramatic than I thought, but eval performance also heavily depends on the length of code.

        So adding 10 no-ops already made eval 10 times slower while closure didn't change.

        use strict; use warnings; use Time::HiRes qw/time/; BEGIN { $\="\n"; my $count=1000; sub noop { }; my $start=time; sub tag_gen { my ($tag)=@_; sub { noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); "<$tag>",@_,"</$tag>"; } } { no strict 'refs'; for my $x (1..$count) { my $tag="h$x"; *{$tag}=tag_gen($tag); } } print "Closure: ",time-$start; $start = time; for my $x (1..$count) { my $tag="H$x"; eval sprintf <<'__CODE__', $tag; sub %1$s { noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); noop("Ipse Lorum"); "<%1$s>",@_,"</%1$s>"; } __CODE__ } print "Eval: ",time-$start; } print h1 h2 "closure"; print H1 H2 "eval";

        output:

        Closure: 0.0279860496520996 Eval: 0.343567132949829 <h1><h2>closure</h2></h1> <H1><H2>eval</H2></H1>

        One has to keep in mind that 15-20 years ago machines were factor 1000 slower, i.e. auto loading was relevant.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)

        PS: Je suis Charlie!

        update

        fixed bug with no-ops.

        ¹) currying to be precise

      > it was future proofed! You could call CGI->wibble and get a <wibble> tag.

      I wasn't able to reproduce this without explicitly importing "wibble"

      DB<100> use CGI qw(:all wibble) DB<101> wibble => "<wibble />"

      but

      DB<100> use CGI ':all' DB<101> $x=CGI->new() DB<102> $x->wibble() Undefined subroutine CGI::wibble at (eval 24)[multi_perl5db.pl:644] line 2

      So autoloading makes not much sense in this case.

      It doesn't make the code more flexible it only delays the installation, which could already happen in the importer.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)

      PS: Je suis Charlie!

        You had to use :any to get this behaviour:

        $ pmvers CGI 3.59 $ perl -E 'use CGI qw/:any/; say CGI->new->wibble({foo=>"bar"},"baz")' <wibble foo="bar">baz</wibble>