question about "package" and variable scope...

Discussion in 'Perl Misc' started by Raymundo, Sep 22, 2008.

  1. Raymundo

    Raymundo Guest

    Hi all,

    I wrote a file that contains two packages:

    ----------------------------
    #!/usr/bin/perl
    use strict;
    use warnings;

    # "main" package, implicitly
    sub foo {
    print "sub foo in main\n";
    }
    our $foo = "scalar foo in main";

    foo(); # no problem
    print "$foo\n"; # no problem

    # "Test" package begins here
    package Test;

    foo(); # This is an error, because this calls
    "&Test::foo()" that doesn't exist
    ----------------------------

    The last "foo();" results in an error, as you know, because "&foo"
    exists in "main", not in "Test". It should be "main::foo();".


    Ok, then... here is my question...

    ----------------------------
    # (omit the same code as above)

    # "Test" package begins here
    package Test;

    print "$foo\n"; # I think this is an error, too.
    ----------------------------

    Execution result:

    sub foo in main
    scalar foo in main
    scalar foo in main -- $main::foo is printed...


    I thought that the last line would result in an error (just like the
    above case).
    And I thought it would, if "use strict" is ignored in the scope of
    "Test", print null string (the value of $Test::foo).
    But the last line printed the value of "$main::foo" variable...

    I can't understand this.. Any help would be apprecieated.
     
    Raymundo, Sep 22, 2008
    #1
    1. Advertising

  2. Raymundo <> writes:

    > our $foo = "scalar foo in main";
    > package Test;
    >
    > print "$foo\n"; # I think this is an error, too.


    It isn't an error, it's just confusing. There are two things going on:

    * Scoping.

    our() has lexical scope, so as far as scope is concerned, it doesn't
    care about packages at all. It works basically the same as:

    my $foo = "lexical foo"; # lexicals are NOT bound to any package
    package Test;
    print "$foo\n";

    * Association between the variable name and the package variable.

    As I understand it, our() works as if it creates a new lexical
    variable that is aliased to a package variable of the same name in the
    current package. That is: the current package *at the our()
    statement*, NOT the current package at whatever time you use the
    variable.

    See also perldoc -f our:

    ''An "our" declaration declares a global variable that will be visible
    across its entire lexical scope, even across package boundaries. The
    package in which the variable is entered is determined at the point of
    the declaration, not at the point of use.''

    --
    Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
     
    Joost Diepenmaat, Sep 22, 2008
    #2
    1. Advertising

  3. Raymundo <> writes:

    > I can't understand this.. Any help would be apprecieated.


    That's just "our" doing its job as designed. Your code is basically
    the same as the example given in "perldoc -f our":

    An "our" declaration declares a global variable that will be
    visible across its entire lexical scope, even across package
    boundaries. The package in which the variable is entered is
    determined at the point of the declaration, not at the point of
    use. This means the following behavior holds:

    package Foo;
    our $bar; # declares $Foo::bar for rest of lexical scope
    $bar = 20;

    package Bar;
    print $bar; # prints 20, as it refers to $Foo::bar

    sherm--

    --
    My blog: http://shermspace.blogspot.com
    Cocoa programming in Perl: http://camelbones.sourceforge.net
     
    Sherm Pendley, Sep 22, 2008
    #3
  4. Raymundo

    Raymundo Guest

    Oh my God... I misunderstood "our" completely...;;;

    Thank you very much.

    So, both "our" and "my" have lexical scope... Then, if I want to
    declare a variable that is visible in "only this package"... is there
    any way to do so? (other than using braces that enclose the entire
    package)


    On 9¿ù22ÀÏ, ¿ÀÈÄ11½Ã06ºÐ, Joost Diepenmaat <> wrote:
    > Raymundo <> writes:
    > > our $foo = "scalar foo in main";
    > > package Test;

    >
    > > print "$foo\n"; # I think this is an error, too.

    >
    > It isn't an error, it's just confusing. There are two things going on:
    >
    > * Scoping.
    >
    > our() has lexical scope, so as far as scope is concerned, it doesn't
    > care about packages at all. It works basically the same as:
    >
    > my $foo = "lexical foo"; # lexicals are NOT bound to any package
    > package Test;
    > print "$foo\n";
    >
    > * Association between the variable name and the package variable.
    >
    > As I understand it, our() works as if it creates a new lexical
    > variable that is aliased to a package variable of the same name in the
    > current package. That is: the current package *at the our()
    > statement*, NOT the current package at whatever time you use the
    > variable.
    >
    > See also perldoc -f our:
    >
    > ''An "our" declaration declares a global variable that will be visible
    > across its entire lexical scope, even across package boundaries. The
    > package in which the variable is entered is determined at the point of
    > the declaration, not at the point of use.''
    >
    > --
    > Joost Diepenmaat | blog:http://joost.zeekat.nl/| work:http://zeekat.nl/
     
    Raymundo, Sep 22, 2008
    #4
  5. Raymundo <> writes:

    > Oh my God... I misunderstood "our" completely...;;;
    >
    > Thank you very much.
    >
    > So, both "our" and "my" have lexical scope... Then, if I want to
    > declare a variable that is visible in "only this package"... is there
    > any way to do so? (other than using braces that enclose the entire
    > package)


    You can use vars (which is also useful in some other situations):

    #!/usr/bin/perl
    use strict;
    use warnings;

    use vars qw($foo);

    $foo = "scalar foo in main";

    package Test;

    print "$foo\n"; # error: Global symbol "$foo" requires explicit package name


    --
    Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
     
    Joost Diepenmaat, Sep 22, 2008
    #5
  6. Raymundo

    Raymundo Guest

    On 9¿ù23ÀÏ, ¿ÀÀü12½Ã15ºÐ, Joost Diepenmaat <> wrote:
    > Raymundo <> writes:
    > > Oh my God... I misunderstood "our" completely...;;;

    >
    > > Thank you very much.

    >
    > > So, both "our" and "my" have lexical scope... Then, if I want to
    > > declare a variable that is visible in "only this package"... is there
    > > any way to do so? (other than using braces that enclose the entire
    > > package)

    >
    > You can use vars (which is also useful in some other situations):
    >
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    >
    > use vars qw($foo);
    >
    > $foo = "scalar foo in main";
    >
    > package Test;
    >
    > print "$foo\n"; # error: Global symbol "$foo" requires explicit package name
    >
    > --
    > Joost Diepenmaat | blog:http://joost.zeekat.nl/| work:http://zeekat.nl/



    Ooops.. I couldn't even imagine that "our" and "use vars" have
    different scope rule...

    Thanks again Joost for your helpful post.
     
    Raymundo, Sep 23, 2008
    #6
  7. Raymundo <> wrote:

    > Ooops.. I couldn't even imagine that "our" and "use vars" have
    > different scope rule...



    Simply read their documentation...

    perldoc -f our

    ... within the lexical scope of the C<our> declaration ...

    perldoc vars

    the "use vars" and "use subs" declarations are not BLOCK−scoped.
    They are thus effective for the entire file in which they appear...


    --
    Tad McClellan
    email: perl -le "print scalar reverse qq/moc.noitatibaher\100cmdat/"
     
    Tad J McClellan, Sep 23, 2008
    #7
  8. Raymundo

    Hans Mulder Guest

    Raymundo wrote:
    > Then, if I want to
    > declare a variable that is visible in "only this package"... is there
    > any way to do so? (other than using braces that enclose the entire
    > package)


    Package variables are global in scope: you can access them from anywhere
    using the $package::name notation.

    > (other than using braces that enclose the entire package)


    Even that won't help:

    $foo = "foo from main\n";

    {
    package Foo;

    $foo = "foo from Foo\n";
    }

    print $foo; # foo from main
    print $Foo::foo; # foo from Foo

    You can use the $Foo::foo notation to access variables in packages
    that aren't mentioned anywhere else in your script. Perl will
    silently create the package if that's what it takes to make this work.

    If you want to restrict visibility, you'll have to use "my". But "my"
    pays attention only to braces and file boundaries, not to packages.

    Hope this helps,

    -- HansM
     
    Hans Mulder, Sep 23, 2008
    #8
  9. Sherm Pendley wrote :
    > Raymundo <> writes:
    >
    >> I can't understand this.. Any help would be apprecieated.

    >
    > That's just "our" doing its job as designed. Your code is basically
    > the same as the example given in "perldoc -f our":
    >
    > An "our" declaration declares a global variable that will be
    > visible across its entire lexical scope, even across package
    > boundaries. The package in which the variable is entered is
    > determined at the point of the declaration, not at the point of
    > use. This means the following behavior holds:
    >
    > package Foo;
    > our $bar; # declares $Foo::bar for rest of lexical scope
    > $bar = 20;
    >
    > package Bar;
    > print $bar; # prints 20, as it refers to $Foo::bar
    >

    This does not work("print $bar" will not print anything in this case),
    if Bar is in a separate file Bar.pm and included with 'use Bar;

    Why?
    How can I use variables across Packages wich are in separate files?

    Thanks in advance
    regards
    Martin

    --
    perl -e '$S=[[73,116,114,115,31,96],[108,109,114,102,99,112],
    [29,77,98,111,105,29],[100,93,95,103,97,110]];
    for(0..3){for$s(0..5){print(chr($S->[$_]->[$s]+$_+1))}}'
     
    Martin Kißner, Sep 24, 2008
    #9
  10. Martin Kißner <> writes:

    > Sherm Pendley wrote :
    >> Raymundo <> writes:
    >>
    >>> I can't understand this.. Any help would be apprecieated.

    >>
    >> That's just "our" doing its job as designed. Your code is basically
    >> the same as the example given in "perldoc -f our":
    >>
    >> An "our" declaration declares a global variable that will be
    >> visible across its entire lexical scope, even across package
    >> boundaries. The package in which the variable is entered is
    >> determined at the point of the declaration, not at the point of
    >> use. This means the following behavior holds:
    >>
    >> package Foo;
    >> our $bar; # declares $Foo::bar for rest of lexical scope
    >> $bar = 20;
    >>
    >> package Bar;
    >> print $bar; # prints 20, as it refers to $Foo::bar
    >>

    >
    > This does not work("print $bar" will not print anything in this case),
    > if Bar is in a separate file Bar.pm and included with 'use Bar;
    >
    > Why?


    Our declares variables as being global within a lexical context; a
    different file is in a different lexical context.

    > How can I use variables across Packages wich are in separate files?


    Use the full package name - i.e. "print $Foo::bar;"

    Or, have a look at 'perldoc Exporter' if you'd like to make the
    "short" form available to code that uses your module.

    sherm--

    --
    My blog: http://shermspace.blogspot.com
    Cocoa programming in Perl: http://camelbones.sourceforge.net
     
    Sherm Pendley, Sep 24, 2008
    #10
  11. Raymundo

    Ben Morrow Guest

    Quoth Martin =?UTF-8?Q?Ki=C3=9Fner?= <>:
    > Sherm Pendley wrote :
    > > Raymundo <> writes:
    > >
    > >> I can't understand this.. Any help would be apprecieated.

    > >
    > > That's just "our" doing its job as designed. Your code is basically
    > > the same as the example given in "perldoc -f our":
    > >
    > > An "our" declaration declares a global variable that will be
    > > visible across its entire lexical scope, even across package
    > > boundaries. The package in which the variable is entered is
    > > determined at the point of the declaration, not at the point of
    > > use. This means the following behavior holds:
    > >
    > > package Foo;
    > > our $bar; # declares $Foo::bar for rest of lexical scope
    > > $bar = 20;
    > >
    > > package Bar;
    > > print $bar; # prints 20, as it refers to $Foo::bar
    > >

    > This does not work("print $bar" will not print anything in this case),
    > if Bar is in a separate file Bar.pm and included with 'use Bar;


    No. Seperate files have separate lexical scopes: 'my' variables are
    never visible across files, and 'our' variables must be referred to by
    their full package name.

    > Why?
    > How can I use variables across Packages wich are in separate files?


    The first question is: are you sure you need to? It's often a bad idea
    to do this; it may be better to provide a function or OO interface to
    the variable.

    That said, you have three options:

    1. Refer to the variable by its fully-qualified name, $Foo::bar.

    2. Export the variable into the 'Bar' namespace with Exporter,
    something like this:

    package Foo;

    use base qw/Exporter/;
    our @EXPORT_OK = qw/$bar/;

    1;

    package Bar;

    use Foo qw/$bar/;

    1;

    3. Make a new 'our' variable in the second file that refers to
    $Foo::bar:

    package Bar;

    #...

    package Foo;
    our $bar;
    package Bar;

    #...

    1;

    Ben

    --
    The Earth is degenerating these days. Bribery and corruption abound.
    Children no longer mind their parents, every man wants to write a book,
    and it is evident that the end of the world is fast approaching.
    Assyrian stone tablet, c.2800 BC
     
    Ben Morrow, Sep 24, 2008
    #11
  12. Raymundo

    John Bokma Guest

    John Bokma, Sep 24, 2008
    #12
  13. Sherm Pendley wrote :
    > Martin Kißner <> writes:
    >
    >> Sherm Pendley wrote :


    >> if Bar is in a separate file Bar.pm and included with 'use Bar;
    >>
    >> Why?

    >
    > Our declares variables as being global within a lexical context; a
    > different file is in a different lexical context.


    Thank you. I wasn't aware of this.

    >
    >> How can I use variables across Packages wich are in separate files?

    >
    > Use the full package name - i.e. "print $Foo::bar;"
    >
    > Or, have a look at 'perldoc Exporter' if you'd like to make the
    > "short" form available to code that uses your module.


    'perldoc Exporter' explains how to use Exporter in modules (I didn't
    read it thoroughly yet).
    Is it also possible to use it in the main script to make variables
    declared in the main script accessible inside the module?

    I know I can use '$main::variablename' but I am just interested if I
    could could also use Exporter for this.

    regards
    Martin

    --
    perl -e '$S=[[73,116,114,115,31,96],[108,109,114,102,99,112],
    [29,77,98,111,105,29],[100,93,95,103,97,110]];
    for(0..3){for$s(0..5){print(chr($S->[$_]->[$s]+$_+1))}}'
     
    Martin Kißner, Sep 24, 2008
    #13
  14. Tad J McClellan wrote :
    > Raymundo <> wrote:
    >
    >> Ooops.. I couldn't even imagine that "our" and "use vars" have
    >> different scope rule...

    >
    >
    > Simply read their documentation...
    >
    > perldoc -f our
    >
    > ... within the lexical scope of the C<our> declaration ...


    I wasn't aware that the lexical scope is restricted to the file.
    Thanks to sherm I am now.

    regards
    Martin


    --
    perl -e '$S=[[73,116,114,115,31,96],[108,109,114,102,99,112],
    [29,77,98,111,105,29],[100,93,95,103,97,110]];
    for(0..3){for$s(0..5){print(chr($S->[$_]->[$s]+$_+1))}}'
     
    Martin Kißner, Sep 24, 2008
    #14
  15. Martin Kißner <> writes:

    > 'perldoc Exporter' explains how to use Exporter in modules (I didn't
    > read it thoroughly yet).
    > Is it also possible to use it in the main script to make variables
    > declared in the main script accessible inside the module?


    Not that I know of, and for good reason. Modules should be self-
    contained, with as little knowledge as possible of anything outside of
    their own package. If the main program needs to provide some variable
    to the module, it should either set a variable in the module's
    package, or pass it to a function (or method) that the module
    supplies.

    For example, when you're using the CGI.pm module, you use a variable
    in the module's name space ($CGI::pOST_MAX) to set the maximum amount
    of data that will be accepted from a form.

    sherm--

    --
    My blog: http://shermspace.blogspot.com
    Cocoa programming in Perl: http://camelbones.sourceforge.net
     
    Sherm Pendley, Sep 24, 2008
    #15
  16. Sherm Pendley wrote :
    > [...] If the main program needs to provide some variable
    > to the module, it should either set a variable in the module's
    > package, or pass it to a function (or method) that the module
    > supplies.


    This is how I do it right now.
    Actually I am talking about a script and a couple of selfmade modules
    which I use to build a multilingual website with a MySQL database in the
    background. I also use HTML::Template.

    My modules need access to the server variables and some other global
    information.
    For the sake of shortness and readability I declared some variables in
    the main script for this purpose like:

    my $language = de; # or en or nl ...
    my $uri = $ENV{REQUEST_URI};
    my $docroot = $ENV{DOCUMENT_ROOT};
    ....

    Since these variables never change during one run of the script I
    thought there must be an easier way to pass them to functions/methods
    inside the modules than always passing them with every call of one of
    those functions/methods. $main::uri will do but there might be another
    option.

    > For example, when you're using the CGI.pm module, you use a variable
    > in the module's name space ($CGI::pOST_MAX) to set the maximum amount
    > of data that will be accepted from a form.


    I didn't consider this possibility until now. This might be helpful in
    other situations but if I load different modules depending on conditions
    I think this might not be very comfortable.

    Thank you for your help
    regards
    Martin

    --
    perl -e '$S=[[73,116,114,115,31,96],[108,109,114,102,99,112],
    [29,77,98,111,105,29],[100,93,95,103,97,110]];
    for(0..3){for$s(0..5){print(chr($S->[$_]->[$s]+$_+1))}}'
     
    Martin Kißner, Sep 24, 2008
    #16
  17. Raymundo

    John Bokma Guest

    Martin =?UTF-8?Q?Ki=C3=9Fner?= <> wrote:

    > my $language = de; # or en or nl ...
    > my $uri = $ENV{REQUEST_URI};
    > my $docroot = $ENV{DOCUMENT_ROOT};


    my $settings = {

    language => ...
    uri => ...
    docroot => ...
    };

    You might want to create a module Settings with a get class method that
    just returns that.

    --
    John http://johnbokma.com/ - Hacking & Hiking in Mexico

    Perl help in exchange for a gift:
    http://johnbokma.com/perl/help-in-exchange-for-a-gift.html
     
    John Bokma, Sep 24, 2008
    #17
  18. Raymundo

    Hans Mulder Guest

    Martin Kißner wrote:

    > $main::uri will do but there might be another option.


    You could spell $main::uri as $::uri

    That way, you can still tell at a glance which variables are
    global, and this notation is hardly longer than normal variables.

    Hope this helps,

    -- HansM
     
    Hans Mulder, Sep 24, 2008
    #18
  19. Martin Kißner <> wrote:
    > Tad J McClellan wrote :
    >> Raymundo <> wrote:
    >>
    >>> Ooops.. I couldn't even imagine that "our" and "use vars" have
    >>> different scope rule...

    >>
    >>
    >> Simply read their documentation...
    >>
    >> perldoc -f our
    >>
    >> ... within the lexical scope of the C<our> declaration ...

    >
    > I wasn't aware that the lexical scope is restricted to the file.
    > Thanks to sherm I am now.



    Another resource that would have revealed the "restricted to file"
    scope of lexical variables would be

    "Coping with Scoping":

    http://perl.plover.com/FAQs/Namespaces.html


    --
    Tad McClellan
    email: perl -le "print scalar reverse qq/moc.noitatibaher\100cmdat/"
     
    Tad J McClellan, Sep 25, 2008
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Paul Opal
    Replies:
    12
    Views:
    1,009
    Paul Opal
    Oct 11, 2004
  2. ann
    Replies:
    13
    Views:
    697
    Patricia Shanahan
    Sep 13, 2005
  3. Steven T. Hatton
    Replies:
    9
    Views:
    521
  4. David Filmer
    Replies:
    19
    Views:
    281
    Kevin Collins
    May 21, 2004
  5. Andrew Falanga
    Replies:
    2
    Views:
    217
    Andrew Falanga
    Nov 22, 2008
Loading...

Share This Page