Hello, all!

Sometimes I use in my programs constant subroutines. As a typical example

sub DEBUG {0} print "blabla" if DEBUG;
Good.

At the second side we all know that Perl optimises away 'if (0) {...};' constructs. Let me demonstrate.

C:\>perl -MO=Deparse -e "print 'this' if $x" print 'this' if $x; -e syntax OK C:\>perl -MO=Deparse -e "print 'this' if 0" '???'; -e syntax OK
More good.

Now let's produce third thought out of those first two thoughts.

C:\>perl -MO=Deparse -we "sub DEBUG{0}print 'this' if DEBUG;" sub DEBUG { 0; } print 'this' if DEBUG ; -e syntax OK C:\>perl -MO=Deparse -we "sub DEBUG(){0}print 'this' if DEBUG;" sub DEBUG () { 0; } '???'; -e syntax OK
Do you see? Not that good anymore.
sub DEBUG{0} internally is NOT constant subroutine whereas sub DEBUG(){0} IS!
After I've discovered this I understood how to let Perl know about subroutine that it is constant sub, and let it optimize away debug information, thus speeding up my code a bit!

Let us name subs like sub DEBUG{0} as "almost constant sub" :) and sub DEBUG(){0} just "constant subs".

As a conclusion I wrote a tiny snippet that searches for almost constant subs in nearest modules that I tend to use.

Examples of modules that contain almost constant subs are:
Win32.pm
Win32::OLE::Variant
Tk::Widget

Most perl core modules contain just constant subs, but there are some that use almost constant subs.
As to name a couple (from latest perl):
threads::shared
Encode::Unicode (seems to me more important than the first)
Encode::Encoding

I searched documentation for explanation on this but found nothing that explains this. I think this should be documented.

So, here are my few thoughts, and right now I will open my favourite editor and slightly speed up my programs.

Good luck to you all,
Courage, the Cowardly Dog.
PS. Something fishy is going on there, or my name is Vadim Konovalov. And it's not.

Replies are listed 'Best First'.
Re: Constant subroutines thoughts
by tadman (Prior) on Jun 09, 2002 at 03:35 UTC
    Maybe for discussion rather than revelation, but why use constants as sub-routines?

    Constant functions can be used to optimize away parts of your program, are just as fast as regular scalars, and they can't be modified "accidentally". You can create these automatically with use constant FOO => 'bar';

    Regular variables can be created faster (no module import required), used inside strings without special handling, and are often more "user friendly" in this regard.

    There was a module called Tie::Const which created "read-only" variables using, of course, tie. The end result is slower scalars, just so you can put them in strings directly and have the piece of mind that they aren't being modified. This seems like a sub-optimal solution, and indeed, the module has been decommissioned.

    I'd rather see something like this in the future:
    my const $FOO = 'bar'; # This is preferable, excuse my C++ my $FOO : const = 'bar'; # This is "more Perly"
    const is really useful when applied correctly, but Perl has no such mechanism. This is a huge drawback when it comes to optimization.

      my $FOO : const = 'bar'; # This is "more Perly"

      my $foo is const = 'bar';
      According to Exegesis 3.

      - Yes, I reinvent wheels.
      - Spam: Visit eurotraQ.
      

      I see your point, and agree with you completely.

      Why I used constant subroutines instead of doing use constant FOO => 'bar';? Because, as I saw everywhere else sub SOME_CONST{0}, and only now I discovered details about this.

      Additionally I want to note that use constant FOO => 'bar'; internally does things similar to sub FOO(){'bar'} - I checked this right now.

      Most important point of my initial message - that my places in programs, such as do{'a lot of debug stuff'} if DEBUG were NOT optimized away, whereas adding a prototype '()' to 'sub DEBUG' makes them to be optimized away!

      Courage, the Cowardly Dog.
      PS. Something fishy is going on there, or my name is Vadim Konovalov. And it's not.

        It would be nice if you could declare inline functions explicitly rather than implicitly using this empty bracket "trick". I had no idea that Perl did this sort of magic for you under special circumstances. Maybe I haven't read enough of the latest Camel Book, because the older one didn't seem to make much of a big deal about it.

        I think the reason I was so befuddled by it in the first place is because it didn't make any sense that Perl would do that sort of thing, I mean, other languages you've got to tell them to do this for you.
Re: Constant subroutines thoughts
by cybear (Monk) on Jun 09, 2002 at 03:34 UTC
    Sorry, I don't get what you are trying to demonstrate. Neither do I understand which side you are advocating, the almost constant constant, or the truly constant constant.

    and just to help out the newer monks, why would this make a difference?

      Sorry for not being 100% clear.

      I was not advocating for usage of "almost constant subs" as opposed of usual subs. But I'll summarize this at the end of a message.

      Okay, Now let us cover more details on things that you did not understood.

      First, how I do 'deparse' and why I see that something was optimized away. You can read how to use deparse using command perldoc B::Deparse with many good examples.

      Note how you can 'deparse' your snippet, or may be entire script:

      C:\>perl -MO=Deparse -e "print 'this' if $x" print 'this' if $x; -e syntax OK
      Okay. But what goes on when we see following:
      C:\>perl -MO=Deparse -e "print 'this' if 0" '???'; -e syntax OK
      Those question marks are here because entire 'print' statement goes away. When you enter command perldoc B::Deparse again, there is an explanation there about those questions marks.

      As an additional demonstration try to analyze following:

      D:\>perl -MO=Deparse -e "sub MY_CONST(){'bla-bla'};$a=MY_CONST;print M +Y_CONST;" sub MY_CONST () { 'bla-bla'; } $a = 'bla-bla'; print 'bla-bla'; -e syntax OK
      You see? That constant subroutine never called, instead it's value inlined everywhere, thus giving us an optimization.
      Then again, let's change our sample snippet a bit.
      D:\>perl -MO=Deparse -e "sub MY_CONST{'bla-bla'};$a=MY_CONST;print MY_ +CONST;" sub MY_CONST { 'bla-bla'; } $a = MY_CONST(); print MY_CONST(); -e syntax OK
      Everywhere our "almost constant sub" is called, thus slowing down things a bit.
      But sometimes this may be considered good and intentional, because in this case you're able to override or redefine your sub in sub-modules.

      Good.

      Now why I said 'Not that good anymore' in my initial message:

      C:\>perl -MO=Deparse -we "sub DEBUG{0}print 'this' if DEBUG;" sub DEBUG { 0; } print 'this' if DEBUG ; -e syntax OK C:\>perl -MO=Deparse -we "sub DEBUG(){0}print 'this' if DEBUG;" sub DEBUG () { 0; } '???'; -e syntax OK
      Because in first case my program was a bit slower and bigger, because everywhere all my statements 'if DEBUG' were recalculataed again, and again, and again, whereas in second case they were just thrown away during compilation stage!

      After I explained more details, let me explain why I was not advocating for either of them.
      Okay, that was not my goal.
      Additionally, may be sometimes module authors intentinally want to leave constant sub to be overridable in sub-class, or something like this.

      But in most cases (like in family of Win32::* modules) they probably should be corrected to use really constant subroutines, so we'll gain speed and probably memory a bit.

      Let me know if I still did not covered something.

      Good luck,
      Courage, the Cowardly Dog.
      PS. Something fishy is going on there, or my name is Vadim Konovalov. And it's not.

Re: Constant subroutines thoughts
by Courage (Parson) on Jun 08, 2002 at 17:50 UTC
    Okay, I see this well documented in perlsub.pod at "Constant Functions", so I badly searched in documentation.

    Sorry

    But the point still remains.

    Courage, the Cowardly Dog.
    PS. Something fishy is going on there, or my name is Vadim Konovalov. And it's not.

      Which point? That perl's optimizer is pretty simple-minded? It is. Or that some modules aren't using the most constant constant subs that they can? They're not.

      The modules in question probably need some updating. OTOH, you can, at runtime, override the non-constant constant subs, while you can't override the constant constant subs. (Whether the module authors were considering this or not is up in the air--they might've, or they might just have misread the docs)

        I consider optimizer to be really good.

        That "point" is about modules, especially core ones, which could be slightly improved.

        But even more point for me is to learn from what I wrote and to write a bit better code by not using "almost constant subs" :)

        Courage, the Cowardly Dog.
        PS. Something fishy is going on there, or my name is Vadim Konovalov. And it's not.