in reply to Detecting an imported function

For the heck of it, I'll suggest the low-tech approach of building a list of routines at BEGIN time and excluding these from the list of traits built at run time.

It isn't obvious from a quick glance when / how the post-compilation moving of all subroutines happens (I guess when the trait-implementing package gets imported), but that must already be happening. So all you need to add is code to cache the list of to-exclude subroutines when Class::Trait::import is called (and then exclude them, of course).

Of course, this means that the user needs to 'use' modules that import non-traits before 'use'ing Class::Trait. But it also means that the user can do creative things that 'import' subroutines that are meant to be traits... Which I find rather appealing.

- tye        

  • Comment on Re: Detecting an imported function (exclude time)

Replies are listed 'Best First'.
Re^2: Detecting an imported function (exclude time)
by diotalevi (Canon) on Nov 17, 2005 at 16:11 UTC
    For what its worth, I'd prefer the flexibility tye's proposing than something as inlexible as I originally brought up (though it does answer the question very succinctly).
Re^2: Detecting an imported function (exclude time)
by Ovid (Cardinal) on Nov 17, 2005 at 16:31 UTC

    How do I do I build a list of subs at BEGIN time without trying to parse Perl?

    package Foo; BEGIN { # &routine is not yet defined and therefore # can't be added to any list } sub routine { ... }

    Or am I missing something obvious?

    Cheers,
    Ovid

    New address of my CGI Course.

      Since BEGIN-phase processing is when subs get defined, and the processing goes top-to-bottom, put your BEGIN block after the subs.
      use warnings; use strict; BEGIN { print "Before: $_\n" for grep /f/, keys %{main::}; } sub foo { print "I am defined\n"; } BEGIN { print "After: $_\n" for grep /f/, keys %{main::}; }

      Caution: Contents may have been coded under pressure.

        Programmers traditionally put their "use" statements near the top of a package. If they do that and put the BEGIN near the bottom, I'm back where I started. Having an arbitrary convention to handle this problem breaks as soon as someone forgets/ignores the convention.

        package Trait::Foo; use strict; use warnings; use Some::Other::Module::Which::Exports::Stuff; sub foo { ... } sub bar { ... } BEGIN { # S:O:M:W:E:S's exported stuff will get picked up # here. That's bad. }

        Otherwise, you're saying subs first, then BEGIN blocks and then other "use" statements. That basically means telling trait authors to write their traits upside down.

        Cheers,
        Ovid

        New address of my CGI Course.

      You fetch the list of subs the same way the list of subs is already being fetched.

      package Limit::Traits; use POSIX ':limits_h'; use Class::Traits ...; # Fetching now will give you "USHRT_MAX" etc. # but not "foo" nor "bar" sub foo { ... } sub bar { ... }

      Later, when Limit::Traits is used, you'll want to export a bunch of subroutines so you fetch the list of all code references in that package again but don't export the ones that were already there when you fetched that same list the first time (in Class::Traits::import).

      - tye        

        You're arguing for a solution which requires that programmers remember to put their "use" statements in the correct order lest things break, right? So if a programmer forgets and slips in a "use" statement after using "Class::Trait", the code mysteriously breaks in a rather hard to debug way.

        There's no small amount of irony here as one of the rationales of traits is to get around ordering problems of mixins and inheritence heirarchies.

        Cheers,
        Ovid

        New address of my CGI Course.