Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Capitalized subroutine names and packages

by elusion (Curate)
on Jan 05, 2003 at 19:41 UTC ( #224460=perlmeditation: print w/replies, xml ) Need Help??

Consider the following code. What's the ouput?
#!/usr/bin/perl -w use strict; package Foo; sub new { return "Foo's constructor called\n"; } package Bar; sub new { return "Bar's constructor called\n"; } package main; sub Bar { return "Foo"; } print Bar->new(), "\n"; # what gets printed?

elusion :

Replies are listed 'Best First'.
Re: Capitalized subroutine names and packages
by Corion (Pope) on Jan 05, 2003 at 20:39 UTC

    It prints Foo's constructor called, because of the following circumstances (and that's my interpretation) :

    1. The executed code lives in package main and there is a sub named Bar
    2. That sub returns a string, Foo
    3. That string result is then taken as the package name in which to call new()

    To circumvent this problem, either make it that [Pp]erl dosen't see Bar as a function name :

    print "Bar"->new(), "\n"; # Calls Bar::new()

    or call Bar::new() manually, and specify the wanted class name on the parameter list :

    my $bar = Bar::new("Bar");

    I don't know where in the documentation to look to find some text on this behaviour, but most likely one of the elder Perl users can explain the sequence of events from the documentation (or correct my sequence).

    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
Re: Capitalized subroutine names and packages
by ihb (Deacon) on Jan 06, 2003 at 00:16 UTC
    This is exactly the reason why I append :: to at compile-time known package names. By doing Bar:: instead you can be sure that it won't resolve to anything unintended.

    Using tailing :: has another indirect advantage. For a person like me that makes typos every now and then it can be nice to be given "stricture" on package names. The following code will emit a warning:
    use Test; Tset::->can('can'); # Bareword "Tset::" refers to nonexistent package ...
    Being consistent with this I also quickly spot dynamically loaded modules, something that sometimes can be quite useful.

    Tailing a pair of colons isn't something special for method invocations. If you wish to save a class/package name in a variable you can use this too: my $class = Foo::Bar::;. Agreed, the ::; hurts your eyes, but then again, I consider that a good thing in this case.

    (As merely a parenthesis the indirect object syntax can be pointed out. Since you hopefully don't use this when you really shouldn't, it's likely you won't have to deal with this, but anyway. new Foo (1) x 3 is almost equal to Foo->new(1) x 3. new Foo:: (1) x 3 is equal to Foo::->new((1) x 3). sub Foo { 1 } new Foo; blows up.)

    Hope I've helped,
Re: Capitalized subroutine names and packages
by blokhead (Monsignor) on Jan 05, 2003 at 20:39 UTC
    ++ for this interesting observation. I guessed wrong at first because I thought the sub Bar would have had to have been prototyped as sub Bar() for it to get called in the last statement. Well, I was wrong there, but then I thought for sure if I prototyped it as sub Bar($), Perl would see that Bar alone is not a valid function call, so while examining the last statement it would try to interpret it as a package name instead. Nope, that gives a compile error.

    My shot at an explanation: I'm guessing the -> operator will only do a method call when the left operand is either a bareword or a scalar (a package name or a ref). But since you have Bar defined as a sub in main's symbol table, it can never be a bareword, so it tries to evaluate it to a scalar: i.e., by calling the subroutine Bar. You end up with a scalar "Foo" which is a package name, so you get the package method call equivalent to Foo->new

    I like this because now you can hijack stuff like this: package Stealer; use base 'Exporter'; @EXPORT = qw/CGI/; sub CGI { return 'Stealer'; } sub new { print "Stolen!"; } use CGI; use Stealer; my $q = CGI->new;
    Create a subclass of CGI without changing your CGI->method calls in the client code! Just import the CGI subroutine to the caller's namespace.

    Update: In your code, if you wrap the declaration of the Bar subroutine in an eval q{...} block, the last line will compile "Bar" as a bareword string instead of a subroutine call, and the output will be "Bar's constructor called"


Re: Capitalized subroutine names and packages
by boo_radley (Parson) on Jan 05, 2003 at 23:07 UTC
    This behavior is documented in perlboot (and somewhere else, I'll update when/if I find the other example).

      Another spot this is documented in on p.316 of the Camel book (3e), in the section "Package-Quoted Classes". This section also discusses the conditions under which Perl knows that a particular bareword is a module name, and how that forces a method call.

Re: Capitalized subroutine names and packages
by dreadpiratepeter (Priest) on Jan 06, 2003 at 15:37 UTC
    It seems to ne there is a lot of "doctor, it hurts when I do this" going on here.

    The best workaround here is not to put things in quotes, or use colons; it's to name things properly in the first place. Packages and Classes with a leading uppercase, subroutines and methods without.
    Proper use of naming conventions promotes clean code. It also helps multiple developers work together.
    It sounds obvious, but I've seen too much code that gives me the willies out there not to restate it.

    "Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."

      I agree in spirit but disagree on some of the details. The main thing that should not be done is having a package name that doesn't contain "::".

      I'd rather have a subroutine named "Bar" than one named "bar". Consider sub Log versus sub log and then doing log("Error at....") and you'll get "Argument isn't numeric" and "Can't take log of 0".

      I try to use multi-word subroutine names so that I can avoid conflicts with both poorly named modules and with keywords that have slipped my mind (or got created since I wrote the code, etc.) by using initial lower case and capitals in the middle ("logToFile"). But when I get lazy and use a single-word subroutine name, then I try to remember to capitalize (if you don't, then you need to always call it with a leading ampersand, &log(), to be safe).

      Perl has lots of poorly named modules. The worst two are and But and are also bad names that should be changed. They don't even work well in English because someone says "I'm using CPAN" and I don't know if they are talking about the module or CPAN itself (the Archive Network, ya know, the thing that you'd know I was talking about when I said "CPAN" if it weren't for someone short-sightedly naming a module that).

      All modules should have "::" in their name.

                      - tye
Re: Capitalized subroutine names and packages
by coolmichael (Deacon) on Jan 05, 2003 at 23:50 UTC
    This really surprised me. I figured that main::Bar would be called and return "Foo". But then I thought that "Foo"->new() would be using "Foo" as a string reference, which isn't generally allowed with strict.

    Obviously, there is something deeper here that I do not understand. Could someone please explain why use strict; doesn't complain?


      When you write Bar->new, the "Bar" is already a string. The package is resolved at runtime via the symbol table. It has to, if you think about it.

      Makeshifts last the longest.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://224460]
Approved by jryan
Front-paged by virtualsue
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (5)
As of 2019-07-19 16:26 GMT
Find Nodes?
    Voting Booth?

    No recent polls found