http://www.perlmonks.org?node_id=1070985

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

use strict; use warnings; use diagnostics; use 5.014; my $newbook = Lib::Book->new( isbn => 'ISBN', ); say $newbook->isbn; package Lib::Book; use Moo; has isbn => ( is => 'rw', ); 1;

My code, in which I can see no material differences from the documentation (http://search.cpan.org/~haarg/Moo-1.004002/lib/Moo.pm), crashes as follows:

Z:\Data\Library\Dancer2>sopw.pl Can't locate object method "isbn" via package "Lib::Book" at Z:\Data\Library\Dancer2\sopw.pl line 9 (#1) (F) You called a method correctly, and it correctly indicated a pa +ckage functioning as a class, but that package doesn't define that parti +cular method, nor does any of its base classes. See perlobj. Uncaught exception from user code: Can't locate object method "isbn" via package "Lib::Book" at Z +:\Data\Library\Dancer2\sopw.pl line 9.

I'm slightly surprised by the error message's reference to an "object method" when I'm trying to address a property, but I suspect that this is merely a Perl idiosyncracy. The assignment in the "new" command works - printing the object using Data::Dumper reveals the isbn property set as I would expect. I tried inserting the "namespace::clean" line from the docs, but that changed nothing.

What should I look at next, please?

Regards,

John Davies

Replies are listed 'Best First'.
Re: Moo error message not understood
by tangent (Parson) on Jan 17, 2014 at 18:50 UTC
    hi davies. You would normally keep your modules in a separate file, in this case 'Book.pm' in a directory 'Lib', and I think the documentation assumes that is the case. If you do that (and use Lib::Book; in your script) the problem will go away.
Re: Moo error message not understood (BEGIN block missing)
by Anonymous Monk on Jan 17, 2014 at 17:57 UTC
    Its your basic order of compilation deal ...

    Lib::Book->new happens before  has isbn happens ...

    basically because that is what you typed, at the time new is called the class doesn't have isbn yet

    If you add  BEGIN { ... } around package Lib::Book, all that should happen before Lib::Book->new as you expect

    Don't know where all this is documented, maybe Simple Module Tutorial ... maybe its also discussed in tyes template at (tye)Re: Stupid question (and see one discussion of that template at Re^2: RFC: Creating unicursal stars

      Thanks. Your advice works perfectly, but I'm still confused. I don't see how, if the "new" happens before "has", the text gets into the object as shown by Data::Dumper. Maybe I shouldn't be worrying, but I'm scared there's a trap lying in wait for me.

      Regards,

      John Davies

      Update: Thanks again. I won't pretend to understand everything at first glance late on a Friday evening, but it's a relief to know that there is a sound explanation. I will work through it, but I won't guarantee how many attempts it will take to get it into my skull. I knew there were aspects of Perl I didn't have a clue about, and this is clearly one that I need to understand better.

        the text gets into the object as shown by Data::Dumper.

        Yes it does ... doesn't mean there is an accessor created (accessors are just "methods" aka "subroutines")

        without has bar

        use Data::Dump qw/ dd /; dd( my $f = Foo->new(qw/ bar 1 /) ); $f->bar; {package Foo; use Moo; } __END__ bless({ bar => 1 }, "Foo") Can't locate object method "bar" via package "Foo" at - line 3.

        you can cheat and use $f->{bar} ... this is cheating / breaking encapsulation / peeking inside object / not using official api / so if sometime in the future you internally rename bar attribute to barps, anyone using ->{bar} would have to update program, anyone using the documented api ->bar wouldn't (because you'd update that too) ... yeah seems convoluted example but thats how they work :)

        with has bar Without BEGIN block there is no bar accessor (accessor is subroutine ... all $obj->whatever is subroutines)

        use Data::Dump qw/ dd /; dd( my $f = Foo->new(qw/ bar 1 /) ); $f->bar; {package Foo; use Moo; has( qw/ bar is rw / ); } __END__ bless({ bar => 1 }, "Foo") Can't locate object method "bar" via package "Foo" at - line 3.

        with has bar and With BEGIN block no death :)

        use Data::Dump qw/ dd /; dd( my $f = Foo->new(qw/ bar 1 /) ); $f->bar; BEGIN{package Foo; use Moo; has( qw/ bar is rw / ); } __END__ bless({ bar => 1 }, "Foo")

        with has bar and Without begin block no death (moved to line 1)

        {package Foo; use Moo; has( qw/ bar is rw / ); } use Data::Dump qw/ dd /; dd( my $f = Foo->new(qw/ bar 1 /) ); $f->bar; __END__ bless({ bar => 1 }, "Foo")

        got that? See also perlobj, A Method is Simply a Subroutine, Attributes

Re: Moo error message not understood
by ikegami (Patriarch) on Jan 17, 2014 at 18:28 UTC
    use Some::Module;
    can be inlined as
    BEGIN { ... Contents of Some/Module.pm ... $INC{'Some/Module.pm'} = 1; } use Some::Module;

    (There are differences, such as lexical pragmas before the BEGIN block will also affect the BEGIN block, but it's a good starting point.)

    So what you want:

    use strict; use warnings; use diagnostics; use 5.014; BEGIN { package Lib::Book; use Moo; has isbn => ( is => 'rw', ); $INC{"Lib/Book.pm"} = 1; } use Lib::Book; my $newbook = Lib::Book->new( isbn => 'ISBN', ); say $newbook->isbn;