sub foo() is export {...}
Rather than the P5:
@EXPORT=qw(foo);
sub foo;
Which is fine, except that in P5 we could say:
use Foo qw(foo);
@EXPORT=qw(foo);
Now, I know that the Apoc on modules has not been written, and by that
time Larry will have thought of this, but I thought I'd point out that
some mechanism will have to exist in modules to indicate not only that
they acquire certain subroutines, variables, etc. of other modules, but
that they re-export them as their own.
I'm deliberately NOT proposing how that would be done, as I have
significant faith that Larry can manage that small bit of magic on his
own, and doesn't need me spewing random ideas and, even worse, syntax
suggestions.
--
Aaron Sherman <a...@ajs.com>
Senior Systems Engineer and Toolsmith
"It's the sound of a satellite saying, 'get me down!'" -Shriekback
But still, you get the idea, I hope ;-)
> At the end of A12, "Exportation" covered the idea that you will now say:
>
> sub foo() is export {...}
>
> Rather than the P5:
>
> @EXPORT=qw(foo);
> sub foo;
>
> Which is fine, except that in P5 we could say:
>
> use Foo qw(foo);
> @EXPORT=qw(foo);
>
> Now, I know that the Apoc on modules has not been written, and by that
> time Larry will have thought of this, but I thought I'd point out that
> some mechanism will have to exist in modules to indicate not only that
> they acquire certain subroutines, variables, etc. of other modules, but
> that they re-export them as their own.
My proposal for that issue is just:
module Bar;
use Foo «foo»;
sub foo is export {...}
This works perfectly in Perl 5 under the Perl6::Export module (now on the CPAN):
package Bar;
use Perl6::Export;
use Foo qw(foo);
sub foo is export;
Damian
That's on the right track, but has some difficulties, insofar as it's
not clear that the intent is to redefine "foo" retroactively rather
than actively. And it doesn't necessarily work for variables, nor
does it tell the "use" whether you were intending to import «foo»
as a package name or a lexical name.
What I've been envisioning in that regard involves making declarations
that simultaneously look like declarations and can have their names
"harvested" for use by the C<use>. As a "placeholder", let's postulate
a funny macro called "namely", that works something like this:
module Bar;
use Foo namely(
my sub foo is export {...}
my Int $foocount is export(:MANDATORY);
our sub bar {...}
my %huz ::= %zah;
);
which, to the C<use>, ends up looking something like
use Foo «foo $foocount bar %zah»
except that the exporter presumably has access to all the extra
information it needs to make sure the types and renamings stay sane.
The syntax is, of course, totally up for grabs, but please note that
we can't use curlies instead of parentheses, or the scoping goes
all wrong.
The alternative approach is to have a means of marking the "use" as
lazy, and a way of marking each individual declaration as an alias
from a particular module. That can get rather more verbose though.
use Foo :lazily;
my sub foo is from(Foo) is export {...}
my Int $foocount is from(Foo) is export(:MANDATORY);
our sub bar is from(Foo) {...}
my %huz ::= %Foo::zah;
On the other hand, the renaming syntax is a little more toward. Maybe they're
all renamings:
my sub foo is export ::= Foo::foo;
my Int $foocount is export(:MANDATORY) ::= $Foo::foocount;
our sub bar ::= Foo::bar;
my %huz ::= %Foo::zah;
That gets rid of the spurious {...}, at least. At the expense of colon
overload, though...
And it's not like we can't do that already. It's the moral equivalent
of Perl 5's glob aliasing. As such it's pretty darn ugly. Which means
it's fine for exceptions, but lousy for normal use.
The main reason for separate declarations in normal use is to specify
whether you want to import lexically or packagely. So a more minimal
approach is to allow
use Foo my &foo, my $foocount, our &bar;
for the normal declarations (ignoring re-exportation issues), and
then resort to ::= for renamings.
If we make lexical importation the default, that reduces to
use Foo «foo $foocount», our &bar;
Of course, for re-export you'd have to say
use Foo my &foo is export,
my $foocount is export(:MANDATORY),
our &bar;
For that to work, C<my> and C<our> would have to be sufficiently
context sensitive to know when they were in use list. The alternative
is a macro like namely(), which would also have the benefit of letting
you use semicolons between declarations rather than commas.
Larry
> On Sat, Apr 24, 2004 at 09:52:12AM +1000, Damian Conway wrote:
> : My proposal for that issue is just:
> :
> : module Bar;
> :
> : use Foo «foo»;
> :
> : sub foo is export {...}
>
> That's on the right track, but has some difficulties, insofar as it's
> not clear that the intent is to redefine "foo" retroactively rather
> than actively.
Err. It's just a declaration that Bar has a subroutine named &foo and that
that subroutine is exportable. The fact that that subroutine exists in Bar
because it's imported from Foo is utterly orthogonal, isn't it?
> And it doesn't necessarily work for variables
True. Just quietly, I would consider that a *feature*! ;-)
But see below for a possible solution.
> does it tell the "use" whether you were intending to import «foo»
> as a package name or a lexical name.
This is, IMO, the real issue. But, as you ponder below, it's an issue of how
the "imporation" (;-) from Foo is specified, not how the "exporation" from Bar
is handled.
> The main reason for separate declarations in normal use is to specify
> whether you want to import lexically or packagely. So a more minimal
> approach is to allow
>
> use Foo my &foo, my $foocount, our &bar;
>
> for the normal declarations (ignoring re-exportation issues), and
> then resort to ::= for renamings.
>
> If we make lexical importation the default, that reduces to
>
> use Foo «foo $foocount», our &bar;
This seems to be by far the least annoying approach.
> Of course, for re-export you'd have to say
>
> use Foo my &foo is export,
> my $foocount is export(:MANDATORY),
> our &bar;
I don't see why. Import to- and export from- a module could (and probably
should) be entirely orthogonal. So perhaps exportation should be via mixin:
use Foo «foo $foocount», our &bar;
&foo does export;
$foocount does export(:MANDATORY);
sub localsub does export {...}
my $localvar does export;
sub AUTOLOAD {...} # implements &baz and &qux
sub baz does export {...} # stub for autoloaded sub
That separates the two concerns (import vs export) very cleanly, doesn't
require much extra typing,seems to handle all kinds of referents (not just
subroutines), and also supports exporting things that are not locally defined
in *other* ways besides having been imported (such as things implemented as
AUTOWHATEVERS).
Damian
> how would you handle %EXPORT_TAGS and @EXPORT_OK?
Export-only-by-request (i.e. @EXPORT_OK) becomes the default.
The tag names become arguments to C<is export>:
sub foo is export(:BAR, :FOOLISH) {...} # Now in two named tagsets
Every exportable is automatically also in the :ALL tagset.
To export-by-default (i.e. the @EXPORT behaviour) you write:
sub foo is export(:DEFAULT) {...}
To export-in-all-cases (not currently possible) you write:
sub foo is export(:MANDATORY) {...}
See Perl6::Export for details and implementation (but bear in mind that those
details are almost certain to change as a result of this very thread).
Damian
DC> I don't see why. Import to- and export from- a module could (and
DC> probably should) be entirely orthogonal. So perhaps exportation should
DC> be via mixin:
DC> use Foo «foo $foocount», our &bar;
DC> &foo does export;
DC> $foocount does export(:MANDATORY);
DC> sub localsub does export {...}
DC> my $localvar does export;
DC> sub AUTOLOAD {...} # implements &baz and &qux
DC> sub baz does export {...} # stub for autoloaded sub
how would you handle %EXPORT_TAGS and @EXPORT_OK?
i do like marking each exportable thing with does export as that removes
the redunancy of the names in the declaration and the @EXPORTS. but it
trades it for many copies of does export which i think is ok.
uri
--
Uri Guttman ------ u...@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
Hmmm... it seems to me that:
use Foo;
our $bar is export := $Foo::bar;
should solve that, no? Now I just want a tied array called @EXPORT that
acts as a macro, adding "is export" to the symbols I put into it ;-)
Seriously, I did kind of like the code-as-documentation pseudo-feature
of seeing all of the exported symbols listed up-front in a module. It's
too bad Perl 6 will lack that.
> > Now, I know that the Apoc on modules has not been written, and by that
> > time Larry will have thought of this, but I thought I'd point out that
> > some mechanism will have to exist in modules to indicate not only that
> > they acquire certain subroutines, variables, etc. of other modules, but
> > that they re-export them as their own.
>
> My proposal for that issue is just:
Damian, Larry not to contradict you, but over the weekend, I had an idea
that may help (and might be tangential to the other ways of doing this).
If we have the syntax:
class a { does b; }
for classes and roles, then wouldn't it make sense to say:
module b { sub x() is export {...} }
module a { does b; }
to say that a also exports all of b's exportables (including x). In
theory that should allow a to re-export b in a structured manner,
including tags, etc.
IMPLEMENTATION DETAILS:
In a more general sense, could we say that a role is a module with a bit
of extra class-specific behavior, but the does method is defined inside
of MetaModule, and inherited by MetaRole, and overridden as invalid by
MetaClass? That is:
class MetaModule { method does() {...} }
class MetaRole { is MetaModule; }
class MetaClass {
is MetaModule;
method does() {
throw SyntaxError, "Can only call 'does' in Roles";
}
}
At least logically, though the Meta* gang might be written in Parrot or
be part of the compiler....
This seems to me to be the cleanest way to have module a absorb the
calling interface of module b.