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

Hello!

Some::Module->can( 'can' )

Could you tell me, why doesn't code above make exception, when Some::Module not loaded yet?

I think, method look up use @ISA variable of module, and 'can' method is inherited from UNIVERSAL, so if it doesn't make an exception, why doesn't this code return reference to UNIVERSAL::can? Perl documentation abount UNIVERSAL doesn't talk anything about it.

Sorry for my english and perhaps for silly question.

Thank you

Replies are listed 'Best First'.
Re: Question about UNIVERSAL::can
by tobyink (Canon) on May 27, 2013 at 22:33 UTC

    UNIVERSAL::can() is not designed for checking if a class is loaded. This bug report may shed some light on the matter.

    If you just need to check if a module has been loaded, then check %INC (see perlvar). If you care about the subtle difference between modules and packages, try is_class_loaded from Class::Load.

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name

      Thank you for responce.

      It's not a bug, that implies from your link on bug report. But there are nothing about UNIVERSAL's methods call on unloaded modules in the perl documentation

      Does anybody know how to change it? Who is responsible for that part of documentation and for that part of perl? :)

      Thank you

        I'm not sure the UNIVERSAL documentation is the right place. Maybe perlootut?

        p5p is responsible for all the documentation that comes with Perl. See perlhack and perlrepository for information about contributing to Perl.

        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Question about UNIVERSAL::can
by Arunbear (Prior) on May 29, 2013 at 16:33 UTC
    A package does not have to be loaded to be useful e.g. we can add a sub to a package and then call it, even though we didn't load it:
    % perl -E '*Some::Module::foo = sub { say "hello" }; Some::Module::foo +()' hello
    thus it makes sense to be able to test it with can (whether we loaded it or not).

    It seems that as an empty package can do nothing, searching for 'can' leads to nothing.

    % perl -E 'say Some::Module->can("can")'
    However this is not the case for a non-empty package:

    % perl -E '*Some::Module::foo = sub { }; say Some::Module->can("can")' + CODE(0x259d370)
    or even
    % perl -E '*Some::Module::foo = sub { say "far out man!" }; say Some:: +Module->can("can")->("Some::Module", "foo")->()' far out man! 1

      Thank you for interesting examples.

      It's another interesting result, that follow from tobyink's link

      $ perl -E'package Foo::Bar; say Foo->can("can")' CODE(0x1f4a220)
      I think, perl just show to symbol table and if data about package exists, that means package exists too, so perl starts inheritance. Otherwise it uses UIVERSAL without inheritance.

Re: Question about UNIVERSAL::can (require)
by tye (Sage) on May 28, 2013 at 17:00 UTC

    Unfortunately, "module not loaded yet" is not a well-defined concept in Perl 5. Previous attempts to try to define that have met with quite disappointing results (see base which had to be replaced with parent due to exactly this problem).

    My advice to you is, if you expect to be able to check whether Foo::Bar has yet been loaded, then you should make sure that loading Foo::Bar always sets $INC{'Foo/Bar.pm'}. For the usual case of Foo::Bar declared inside of the Foo/Bar.pm file, that just happens automatically.

    For the unusual case of Foo::Bar declared in some other file, then you want to ensure the declaration looks something like:

    package Foo::Bar; $INC{'Foo/Bar.pm'} = __FILE__;

    (perhaps with a BEGIN thrown in somewhere there.)

    If you want to be able to load Foo::Bar if it is found to not have been loaded already, then you, of course, want to make sure that loading Foo/Bar.pm causes Foo::Bar to be loaded. Which means that you just need to write require Foo::Bar; in order to load it.

    But, if Foo/Bar.pm has already been loaded, then require Foo::Bar; just does a quick hash look-up and nothing more. So, rather than check whether it has been loaded or not and then doing the require, you might as well just do the require.

    - tye