Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

what does main->{x} = 1 do?

by ganeshk (Monk)
on May 13, 2008 at 23:22 UTC ( #686400=perlquestion: print w/replies, xml ) Need Help??

ganeshk has asked for the wisdom of the Perl Monks concerning the following question:

Please excuse me for a very basic question yet again! I just want to understand how this works
main->{x} = 1; print $main->{x}; # prints 1
main is supposed to be a package name. How does it also act as a hashref?

Thanks in advance

Replies are listed 'Best First'.
Re: what does main->{x} = 1 do?
by ikegami (Patriarch) on May 14, 2008 at 00:29 UTC

    EXPR->{EXPR} is a shorthand for ${EXPR}{EXPR}. Normally, the first EXPR would be a scalar holding a reference, but Perl also support symbolic references. Symbolic references allow variable names to be strings.

    >perl -le"$x = "var"; ${$x} = "abc"; print $var;" abc

    Furthermore, barewords are treated as strings literals by default (unless they refer to a known function or a file handle is expected where the bareword is located).

    >perl -le"$x = main; print $x" main

    Using symbolic references is strongly dissuaded. use strict 'refs'; (and therefore just use strict;) prevent them from being used.

    Using barewords as string literals is also strongly disuaded. use strict 'subs'; (and therefore just use strict;) prevent them from being used.

    So in short, had you used use strict; as you should have, trying to run your snippet would have failed for two different reasons.

      Thanks very much for the explanation.
Re: what does main->{x} = 1 do?
by samtregar (Abbot) on May 13, 2008 at 23:29 UTC
    Does't work for me with Perl v5.8.8 on Linux:

    $ perl -le 'main->{x} = 1; print $main->{x}'

    But this does:

    $ perl -lwe 'main->{x} = 1; print $main{x}' 1

    The reason is that "main" is being treated as a symbolic reference to the global hash %main. Strict mode catches the error for you:

    $ perl -Mstrict -lwe 'main->{x} = 1; print $main{x}' Can't use bareword ("main") as a HASH ref while "strict refs" in use a +t -e line 1.

    -sam

      Thank you very much Sam and Wade for the response. strict refs mode is fine. But I just wanted to know if I understood right! When you use the -> operator the '$' sigil is not necessary! Perl automatically understands the type i.e whether array or hash. And also the variable is defined in the current package. Is that correct? I actually ran into problem while just trying to auto-generate getter/setters for a class. So just before installing the methods into the target class, the strict 'refs' is turned off! So the getter/setter code was something like this
      sub { if ( @_ == 1 ) { $_[0]->{$name} # this was initially $_[0]{$name} } else { $_[0]->{$name} == $_[1]; # initially $_[0]{$name} = $_[1]; } }
      This seems to be ok as long as the method is called on an object. But say you call the method on a class(say by mistake), then it was causing problems without the arrow operator. But when the arrow operator was included it was working fine although the method was meant to be an object method. So then I saw I needed to brush up some fundametals! So if I understand it correctly what happens here is that the hash variable is actually defined in the package where the code belongs. And it happens because strict refs is off. Thanks in advance for the help. Thanks again!

        When you use the -> operator the '$' sigil is not necessary!

        It has nothing to do with the -> operator. Few if any operators requires its operands to have a $ since they work on expressions, not specifically scalars.

        For example, here are 4 different operators and not a sigil in sight:

        foo()->{x} foo() + bar() !foo() print(foo())

        Perl automatically understands the type i.e whether array or hash.

        Correct.
        EXPR->[...] expects EXPR to return an array reference.
        EXPR->{...} expects EXPR to return a hash reference.
        EXPR->(...) expects EXPR to return a code reference.

        And also the variable is defined in the current package. Is that correct?

        No. Symbolic references can access variables in any package.

        >perl -le"$x='Foo::var'; ${$x}='abc'; print $Foo::var;" abc

        And it happens because strict refs is off.

        strict shouldbe used. It's there to prevent specifically these kinds of odd and hard to debug problems.

        Thank you very much Sam and Wade for the response. strict refs mode is fine. But I just wanted to know if I understood right! When you use the -> operator the '$' sigil is not necessary! Perl automatically understands the type i.e whether array or hash.

        I personally believe you're right. More precisely, with the symrefs thingy others duly explained to you, the -> dereferentiation operator, complete of the correct parens -AFAICS it doesn't exist by itself- is unambiguous enough for the correct slot to be selected. However you should not use symrefs, anyway. (But under particular circumstances.) Rather, I feel like pointing out that main->{x} = 1; is still valid syntax, under strictures, although it has to be associated with a different semantics than yours:

        $ perl -Mstrict -wle ' > my %x; sub main () { \%x }; > main->{x} = 1; > print $x{x}' 1
        --
        If you can't understand the incipit, then please check the IPB Campaign.

        $_[0]->{$name} and $_[0]{$name} are equivalent. Always, no matter the status of use strict 'refs'. The -> between subscripts is optional. This is in no way related to symbolic references or typeglobs or packages.

        If you obtained different results, you must have changed something more.

Re: what does main->{x} = 1 do?
by wade (Pilgrim) on May 13, 2008 at 23:30 UTC

    'main' can be a hash ref, or an array, or whatever -- differentiated by the character in front and what's been put in there (I'm a little shaky on the Perl internals). The code that you had, in order to print '1' needed to have a '$' in front of the 'main' in the first line.

    Now, if you:

    use strict; use warnings; use diagnostics;

    Then you get a 'bareword' error without the '$' and you get a 'undefined' error with the '$' -- all as expected.

    --
    Wade
Re: what does main->{x} = 1 do?
by Burak (Chaplain) on May 14, 2008 at 09:20 UTC
    That's a very nasty side effect and I've experienced that "feature" in a code. And it's also not easy to detect. Imagine you have an X class and you can access it's methods via $o = X->new; But since X does not use strict, you can also access them as static methods like X->foo(123) and if foo() is like this:
    sub foo { my $self = shift; $self->{bar} = shift; $self->{bar} }
    it will succeed. And if you're inheriting several levels from that X class..? I think that every code that does not use strict must be forced to use it. Especially if the code is a CPAN module. There are several modules that do not use strict I think...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://686400]
Approved by samtregar
Front-paged by samtregar
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (4)
As of 2023-05-31 03:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?