forked from szabgab/perlmaven.com
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathglobal-symbol-requires-explicit-package-name.tt
178 lines (122 loc) · 4.07 KB
/
global-symbol-requires-explicit-package-name.tt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
=title Global symbol requires explicit package name
=timestamp 2012-09-13T12:45:56
=indexes strict, my, package, global symbol
=status show
=books beginner_book
=author szabgab
=index 1
=archive 1
=feed 1
=comments 1
=social 1
=abstract start
<b>Global symbol requires explicit package name</b> is a common,
and IMHO very misleading error message of Perl. At least for beginners.
The quick translation would be "You need to declare the variable using <b>my</b>."
=abstract end
<h2>The simplest example</h2>
<code lang="perl">
use strict;
use warnings;
$x = 42;
</code>
And the error is
<code>
Global symbol "$x" requires explicit package name at ...
</code>
While the actual error message is correct,
this is little use for the beginner Perl programmer.
They have probably not learned what packages are.
Nor do they know what can be more explicit than $x ?
This error is generated by <b>use strict</b>.
The explanation in the documentation is:
<i>
This generates a compile-time error if you access a variable that wasn't
declared via "our" or "use vars", localized via "my()", or wasn't fully qualified.
</i>
A beginner will hopefully start every script with <b>use strict</b>,
and will probably learn about <b>my</b> long before any of the other possibilities.
I don't know if the actual text can and should be changed in perl. That's not the point
of this post. The point is to help beginners understand in their own language what does
this error message mean.
To eliminate the above error message one needs to write:
<code lang="perl">
use strict;
use warnings;
my $x = 42;
</code>
That is, one needs to <b>declare the variable using my before its first use.</b>.
<h2>The bad solution</h2>
The other "solution" is to remove <b>strict</b>:
<code lang="perl">
#use strict;
use warnings;
$x = 23;
</code>
that would work but this code will generate a
<a href="/name-used-only-once-possible-typo">Name "main::x" used only once: possible typo at ...</a>
warning.
In any case, normally you would not drive a car without the safety belt, would you?
<h2>Example 2: scope</h2>
Another case I often see with beginners looks like this:
<code lang="perl">
use strict;
use warnings;
my $x = 1;
if ($x) {
my $y = 2;
}
print $y;
</code>
The error we get is the same as above:
<code>
Global symbol "$y" requires explicit package name at ...
</code>
which is surprising for many people. Especially when they start their coding.
After all they declared <hl>$y</hl> using <hl>my</hl>.
First, there is a little visual problem. The indentation of <hl>my $y = 2;</hl> is missing.
If it was indented a few spaces or a tab to the right, as in the next example,
the source of the problem might be more obvious:
<code lang="perl">
use strict;
use warnings;
my $x = 1;
if ($x) {
my $y = 2;
}
print $y;
</code>
The problem is, that the variable <hl>$y</hl> is declared within the block,
(the pair of curly braces) which means it does not exist outside of that block.
This is called the <b>scope</b> of the variable.
The whole idea of <b>scope</b> is different among programming languages.
In Perl, a block enclosed in curly braces creates a scope.
What is declared inside using <hl>my</hl> will not be accessible outside the block.
(BTW the <hl>$x = 1</hl> is there only to have a legitimate-looking condition that creates the scope.)
The solution is either to call the <hl>print</hl> inside the block:
<code lang="perl">
use strict;
use warnings;
my $x = 1;
if ($x) {
my $y = 2;
print $y;
}
</code>
or to declare the variable outside the block (and not inside!):
<code lang="perl">
use strict;
use warnings;
my $x = 1;
my $y;
if ($x) {
$y = 2;
}
print $y;
</code>
Which way you do will depend on the actual task. These are just the syntactically possible correct solutions.
Of course, if we forget to remove the <hl>my</hl> from inside the block, or if <hl>$x</hl> is false,
then we get a <a href="/use-of-uninitialized-value">Use of uninitialized value</a> warning.
<h2>The other ways</h2>
Explaining what <hl>our</hl>, and <hl>use vars</hl> do, or how can one
fully qualify a variable name is left to another post.