Does "my" vs "our" explain this problem?

Does "my" vs "our" explain this problem?

am 08.02.2006 17:01:42 von CedricCicada

Greetings!

I have a script that calls a module. In the script, I define a global
variable using "my" and assign it a value. In the module, I use
$main::myGlobal to read the global variable, and I find that it is
empty. Should I define the global variable using "our" instead?

mymoduletest.pl:

use MyModule;
my $myGlobal = "This is a global variable.";
MyModule::myMethod();

MyModule.pm:

sub myMethod()
{
print "Global variable contains $main::myGlobal\n";
}

Thanks very much!

RobR

Re: Does "my" vs "our" explain this problem?

am 08.02.2006 17:28:07 von Paul Lalli

CedricCicada@gmail.com wrote:
> Greetings!
>
> I have a script that calls a module. In the script, I define a global
> variable using "my" and assign it a value.

That is a contradiction in terms. 'my' variables, by definition, are
not global. They are lexically scoped to the innermost block in which
they were declared. If there is no block, they are file-scoped.

> In the module, I use
> $main::myGlobal to read the global variable, and I find that it is
> empty. Should I define the global variable using "our" instead?

'our' is the only way to "declare" a global variable*. You did not
have a global variable. You had a lexical variable.

Google for "Coping with Scoping."

> mymoduletest.pl:
>
> use MyModule;
> my $myGlobal = "This is a global variable.";

No, it's not. It's a lexical variable, who's scope happens to be the
entire scope of the file mymoduletest.pl. Anywhere outside that file,
that variable does not exist.

> MyModule::myMethod();
>
> MyModule.pm:
>
> sub myMethod()
> {
> print "Global variable contains $main::myGlobal\n";

This is the global variable $myGlobal that belongs to the package main.
> }

This is, in general, really bad form. Your packages should not have
any access to the package 'main' without very good reason (and I can't
think of any good reasons right now). While it makes more sense for
package main to have access to your module's variables, it's still bad
form - declare all variables lexically, and right accessor subroutines
and methods.

Paul Lalli

* 'our' doesn't actually "declare" global variables, because global
variables are not declared, they simply exist. 'our' simply allows you
to use that global variable without fully qualifying it (ie, preceding
it with its package's name) even though strict vars is in scope, for
the duration of the lexical scope. Anywhere outside the 'our''s scope,
you still have to fully qualify the variable if strict is in effect.

Re: Does "my" vs "our" explain this problem?

am 08.02.2006 18:54:23 von CedricCicada

Paul,

Thank you very much for your reply. I think I'm starting to get a
handle on this issue, but I still have questions.

First, if "my $myGlobal" only declared a lexical variable defined
within moduletest.pl, why didn't I get a compile error when I tried to
use it in Module.pm?

Second, assuming that I really do need to access $myGlobal inside
Module.pm, will the use of "our" let me do it?

I am a professional software developer, just not a Perl developer. I
understand the ugliness of global variables. In this case, I want the
variable to hold the name of the folder that contains my data files.
When I was on a Unix host, "../data" worked fine. Now that we've moved
to a Windows host, I can't assume that the folder named "data" is on
the same level as my working folder. Therefore, in my main routine I
store the complete path to my data folder in a variable named
$dataPath. Rather than passing it individually to each method in all
of my modules that needs it, I want it accessible globally.

Hmmm... Maybe this is a place where I should use a BEGIN block. In
every module, the BEGIN code would read the global $dataPath. Or I
could even rebuild $dataPath there, since it is built in a single line
of code. That would answer my concern about modifying every method in
every module, while eliminating the need to use the global variable.

Or I could declare a method in my main module (moduletest.pl, in this
case) that would return the path. Then, myMethod would become
something like:

sub myMethod()
{
my $theDataPath = main::GetDataPath();
print "Data path: $theDataPath\n";
}

Am I warmer?

RobR

Re: Does "my" vs "our" explain this problem?

am 08.02.2006 19:01:55 von CedricCicada

Paul,

Thank you very much for your reply. I think I'm starting to get a
handle on this issue, but I still have questions.

First, if "my $myGlobal" only declared a lexical variable defined
within moduletest.pl, why didn't I get a compile error when I tried to
use it in Module.pm?

Second, assuming that I really do need to access $myGlobal inside
Module.pm, will the use of "our" let me do it?

I am a professional software developer, just not a Perl developer. I
understand the ugliness of global variables. In this case, I want the
variable to hold the name of the folder that contains my data files.
When I was on a Unix host, "../data" worked fine. Now that we've moved
to a Windows host, I can't assume that the folder named "data" is on
the same level as my working folder. Therefore, in my main routine I
store the complete path to my data folder in a variable named
$dataPath. Rather than passing it individually to each method in all
of my modules that needs it, I want it accessible globally.

Hmmm... Maybe this is a place where I should use a BEGIN block. In
every module, the BEGIN code would read the global $dataPath. Or I
could even rebuild $dataPath there, since it is built in a single line
of code. That would answer my concern about modifying every method in
every module, while eliminating the need to use the global variable.

Or I could declare a method in my main module (moduletest.pl, in this
case) that would return the path. Then, myMethod would become
something like:

sub myMethod()
{
my $theDataPath = main::GetDataPath();
print "Data path: $theDataPath\n";
}

Am I warmer?

RobR

Re: Does "my" vs "our" explain this problem?

am 08.02.2006 20:18:56 von Paul Lalli

Rob Richardson wrote:
> Thank you very much for your reply. I think I'm starting to get a
> handle on this issue, but I still have questions.
>
> First, if "my $myGlobal" only declared a lexical variable defined
> within moduletest.pl, why didn't I get a compile error when I tried to
> use it in Module.pm?

You didn't try to use it in Module.pm. In Module.pm, you used
$main::myGlobal, which is a global variable belonging to package main.
It is 100% unrelated to the $myGlobal lexical you declared in the
moduletest.pl file.

Package variables are Global variables in Perl. They "belong" to a
certain package, but can be accessed from anywhere, by any package.

> Second, assuming that I really do need to access $myGlobal inside
> Module.pm, will the use of "our" let me do it?

What happened when you tried it?

> I am a professional software developer, just not a Perl developer. I
> understand the ugliness of global variables. In this case, I want the
> variable to hold the name of the folder that contains my data files.
> When I was on a Unix host, "../data" worked fine. Now that we've moved
> to a Windows host, I can't assume that the folder named "data" is on
> the same level as my working folder. Therefore, in my main routine I
> store the complete path to my data folder in a variable named
> $dataPath. Rather than passing it individually to each method in all
> of my modules that needs it, I want it accessible globally.

More bad design.

Your main file should not be making the configuration options. You
should have a separate configuration module that contains these
details, and any module that needs it should use that configuration
module.

Something like:

package MyConfig;
use strict;
use warnings;
use base 'Exporter';
our @EXPORT = qw/get_path/;

my %config = (
path => 'data',
file => 'stuff.txt',
user => 'joesmith',
#etc
);

sub get_path {
return $config{path};
}

1;

Then, in your module:
package MyModule;
use strict;
use warnings;
use MyConfig;

my $path = get_path();

> Hmmm... Maybe this is a place where I should use a BEGIN block. In
> every module, the BEGIN code would read the global $dataPath.

Stop thinking about globals. If you're a professional software
designer, and you know the danger and ugliness of globals, why do you
keep insisting on using them?

The 'use MyCofing;' from above does implicitly use a BEGIN{} block.

> Or I could declare a method in my main module (moduletest.pl, in this
> case) that would return the path. Then, myMethod would become
> something like:

This does not belong in your main file. Main files use modules. Not
the other way around.

> sub myMethod()
> {
> my $theDataPath = main::GetDataPath();
> print "Data path: $theDataPath\n";
> }
>
> Am I warmer?

Yes, but not yet hot.

See also the multitude of configuration modules available on CPAN.
Just go to http://search.cpan.org and search for "Config"

Paul Lalli