2

When I run this Perl script:

#!/bin/perl 
use XML::Bare; 
$ob = new XML::Bare(text=>'<xml><name>Bob</name></xml>'); 
for $i (keys %{$ob->{xml}}) {print "KEY: $i\n";} 

I get no output. However, if I put $ob inside a my():

#!/bin/perl 
use XML::Bare; 
my($ob) = new XML::Bare(text=>'<xml><name>Bob</name></xml>'); 
for $i (keys %{$ob->{xml}}) {print "KEY: $i\n";} 

I get this output:

KEY: _z 
KEY: _i 
KEY: xml 
KEY: _pos 

Why does my() change this behavior so drastically, especially given that I'm at the top level where my() should have no effect at all?

friedo
  • 65,762
  • 16
  • 114
  • 184

2 Answers2

11

First of all, you should always begin your Perl scripts with

use strict;
use warnings;

This will force you to declare all your variables with my which catches many typos and simple mistakes.

In your case, it's not actually the my that causes the changed behavior, but the parentheses, which put $ob in list context.

Looking at the source of XML::Bare, we find this in the constructor:

sub new { 
    ...
    bless $self, $class;
    return $self if ( !wantarray );
    return ( $self, $self->parse() );
}

Notice that the second return line calls ->parse on the new object for you, which you forgot to do in your first example, which is why that one didn't have any data in it.

So you can say

my $obj = XML::Bare->new(text=>'<xml><name>Bob</name></xml>'); # in scalar context
$obj->parse;

Or

my ( $obj ) = XML::Bare->new(text=>'<xml><name>Bob</name></xml>'); # in list context

and they should be equivalent.

This is a pretty strange interface choice, but I'm not familiar with XML::Bare.

Notice also that I've avoided indirect method syntax (XML::Bare->new instead of new XML::Bare). This helps to avoid some nasty problems.

Community
  • 1
  • 1
friedo
  • 65,762
  • 16
  • 114
  • 184
  • Thanks! I was using parse() earlier, but became surprised when my() appeared to do an automatic parse. I keep incorrectly thinking that "my $foo" is equivalent to "my($foo)". –  Jul 12 '12 at 01:42
  • 2
    `my ($foo)` is equivalent to `(my $foo)`, and `(...) =` tells Perl to use a list assignment operator instead of a scalar assignment operator. See [Mini-Tutorial: Scalar vs List Assignment Operator](http://www.perlmonks.org/?node_id=790129) – ikegami Jul 12 '12 at 03:53
1

The XML::Bare module is intentionally designed to work in 2 different ways.

Way #1:

my $ob = XML::Bare->new( text => "<xml/>" );
my $tree = $ob->parse();

Way #2:

my ( $ob, $tree ) = XML::Bare->new( text => "<xml/>" );

You are using the module in an undocumented way #3:

my ( $ob ) = XML::Bare->new( text => "<xml/>" );
my $tree = $ob->{'xml'};

This third way happens to work, because the module stores the tree within it's own object. I would recommend avoiding using it in this way, because it is confusing, and may change in future versions of the module.

nanoscopic
  • 41
  • 2