Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

I'm trying to define an OO package that the main:: package will use, and wish to include some common variables that the package will need to reference across all object use (constructors, methods, and so on.)

As a convenience, I'm including the OO package in the same file as the main:: code, ideally at the end as I do not wish to confuse users (read: other staff who don't need to know/care) who may want to learn how the high-level code works or make changes.

Here's where I ran into behavior which I don't really understand. If I put my OO class, called Foo::Bar in the examples below, in the same file at the end, Perl does not let me reference the globally-scoped package namespace variable $Foo::Bar::data within methods of this class. However, if I use the same package code and require or use it from an external library, it seems the non-subroutine (ie: method/constructor/etc) code in the class is run.

I've learned that I can work-around this by using a forward-declaration with our(), combined with a BEGIN block to initialize the package globals. This seems to have the desired result, although I'm wondering if this is really the best way to support using an OO package like this from either a package definition in the same file as main:: or a real module file included with require.

Below is the admittedly contrived proof-of-concept example. Yes, it's a bit silly (my original problem dealt with an OO class that ships its own DBI and SQLite RDBMS, including self-provided schema. Rest assured the example is simply to avoid all of that nonsense in learning how namespace and scoping works!)

Of note here is that removing the BEGIN block surrounding the $data definition prevents the code from ever getting executed, which causes the program to abort during the sanity-check within the text() method.

I'm curious if this is an intentional design limitation of Perl, or merely a side-effect of putting my main:: package code before the Foo::Bar package code. I understand that a require() call will execute the non-subroutine code in the package at that point, but this seems to be in contradiction to how subroutines work; I can call sub_foo() before declaring it, but apparently can't do this with in-file packages.

Here's the proof-of-concept code:

use strict; use warnings; my $foobar_o = Foo::Bar->new( "object o" ); printf "%s\n", $foobar_o->text(1); # -- # Package # -- package Foo::Bar; # Package namespace 'our' globals (which must be forward-declared.) # These go in BEGIN so they work from an in-file package too! our $data; BEGIN { our $data = { 1 => "one", 2 => "two", 100 => "one hundred", }; } # Fairly minimal constructor, passed an optional "name" argument: sub new { my $class = shift; my $name = shift // "<unnamed object>"; $class = ref($class) || $class; # subclass boilerplate. my $self = { name=>$name }; bless $self, $class; return $self; } # Silly example method that returns the "text" keyed by %$data. sub text { my $self = shift; my $query = shift or return ''; # Sanity check, making sure the package namespace $data exists: die "Uh-oh, data is not defined!" unless defined $data; my $s = sprintf( "%s: %s is %s", $self->{name}, $query, $data->{$query} // "<query value not defined>" ); return $s; } # Explicit RC to support require() and use(). # This is only useful when the package is a real module file. 1;

In reply to Behavior of 'our' variables in the package-namespace by Apero

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (3)
As of 2022-05-16 18:15 GMT
Find Nodes?
    Voting Booth?
    Do you prefer to work remotely?

    Results (63 votes). Check out past polls.