views:

110

answers:

3

All over the place, especially in DBI, I see this message come up all the time. It's confusing, because the first thing that comes to mind is that the arguments I'm passing the function are set to undef (or something similar), but it's clearly not the case.

Given a module and a corresponding script...

Module: ./lib/My/Module.pm

package My::Module;

use strict;
use warnings;

sub trim {
    my $str = shift;
    $str =~ s{ \A \s+ }{}xms; # remove space from front of string
    $str =~ s{ \s+ \z }{}xms; # remove space from end of string
    return $str;
}

Script: ./test.pl

#!/usr/bin/perl

use strict;
use warnings;
use My::Module qw(trim);

print $My::Module->trim( " \t hello world\t \t" );

I get back the error message

Can't call method "trim" on an undefined value at ./text.pl line 7.

Infact, if I call $My::Module->notamethod( "hello world" ); it gives a similar error.

What's wrong with the above script/module?

What is that error Can't call method “X” on an undefined value at ${SOMEFILE} line ${SOMELINE} really saying? Does this refer to the context of the method call (passed here to print), or the context of the arguments?

+5  A: 

That syntax is looking for an object or classname in the variable $My::Module and calling its trim method, but that variable is undefined.

Instead, you want to just say print My::Module::trim( " \t hello world\t \t" ); to call the My::Module::trim() function.

From the use line, it looks like you are trying to import trim() into the local package so you can just call it without the My::Module:: qualification, but your module doesn't look like it is set up to support exporting.

In your regexes, the /s and /m flags don't have any effect - they only change what ., ^, and $ match, and you don't use any of those.

ysth
I tend to put those in when writing regex's because I like to put comments inline :). I just forgot to take them out for the sake of example.
The Daemons Advocate
@The Daemons Advocate, /s and /m have nothing to do with inline comments. That's /x.
cjm
A: 

It is just how Perl does OO. The difference is in between the way you call the methods.

This just calls the trim sub in the My::Module package:

 My::Module::trim('foo')

On the other hand,

 My::Module->trim('foo)

automatically becomes a call to the trim sub in the My::Module package with the string "My::Module" as the first argument. Objects work the same way:

 my $m = My::Module->new; # Corrected. Thanks for pointing this out.
 $m->trim('foo');

Turns into a call to the same sub, but this time with a reference to the $m object as the first argument.

What you are trying to do is:

$My::Module->trim('foo');

Which translates to a dereference of the variable $My::Module (which does not exist), thus the error message "Can't call method X on an undefined value". If $My::Module were an actual reference to an object, this would result in a call to trim() on that object, with the reference as an implicit first argument.

Edit: Both commenters are correct. This answer was originally intended as a comment to the accepted answer. (Is there a way to fix that?)

Sorry for the confusion. I've added a little more detail here so hopefully it becomes more clear how it relates to the original question (dereferencing an undefined variable).

Tore A.
You should not use the indirect method syntax for your `new` line. See here for why: http://stackoverflow.com/questions/429657/what-is-the-difference-between-new-someclass-and-someclass-new-in-perl/429798#429798
friedo
The information in this post is true, but it doesn't really have anything to do with the question.
jrockway
+4  A: 

You're conflating several different ways to handle modules and objects - and ending up with one that doesn't work.

Here are four approaches that do work:

1/ My::Module is a library. trim is not exported.

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

sub trim {
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

# Note: No $ and :: not ->
print My::Module::trim( " \t hello world\t \t" );

2/ My::Module is a library. trim is exported.

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

use Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(trim);

sub trim {
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

print trim( " \t hello world\t \t" );

3/ MyModule is a class. trim is a class method.

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

sub trim {
  # Note class name passed as first argument
  my $class = shift;
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

# Note: Not $ and -> not ::
print My::Module->trim( " \t hello world\t \t" );

4/ MyModule is a class, trim is an object method.

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

# Need a constructor (but this one does nothing useful)
sub new {
  my $class = shift;

  return bless {}, $class;
}

sub trim {
  # Note: Object method is passed an object (which is ignored here)
  my $self = shift;
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

my $trimmer = My::Module->new;

print $trimmer->trim( " \t hello world\t \t" );

I think that you were trying for option 1. In this case, I think I'd recommend option 2.

And to answer your final question. You are getting that error because you are trying to call a method on a variable ($My::Module) which is undefined.

davorg