develooper Front page | perl.perl6.language | Postings from July 2005

Re: How to write a self.pm (Re: method calls on $self)

Thread Previous | Thread Next
From:
Larry Wall
Date:
July 12, 2005 15:58
Subject:
Re: How to write a self.pm (Re: method calls on $self)
Message ID:
20050712225837.GA1347@wall.org
On Tue, Jul 12, 2005 at 12:36:23PM +0800, Autrijus Tang wrote:
: On Mon, Jul 11, 2005 at 09:04:54PM -0700, Larry Wall wrote:
: > On Tue, Jul 12, 2005 at 10:17:01AM +0800, Autrijus Tang wrote:
: > : On Mon, Jul 11, 2005 at 06:29:28PM -0700, Larry Wall wrote:
: > : The obvious thought is to have yet another magical, $^H like flag, to
: > : denote the current dialect.  If it is set, then the parser can emit
: > : .method as $_.method, instead of $?IMPLICIT_INVOCANT.method.
: > 
: > The parser always emits .method as $_.method under any dialect, or
: > fails.  What has changed is whether $_ sometimes means the invocant.
: 
: But the compiler needs to trigger ambiguity resolution -- i.e. check
: for $?SELF agreement with $_ -- when it sees $?IMPLICIT_INVOCANT.
: 
: No need to do that if it sees $_.method.  So they need to be different.

Well, another approach is to treat .method as invariably $_.method,
and catch the problem at the attempt to rebind $_.  Thomas seems to
think it should already be doing that.  Of course, that would make it
impossible to use given or for inside a method at all...

So the other approach is to give up on compile-time checks and say
that $?IMPLICIT_INVOCANT.method in a method's lexical scope (and
in the absence of "use self") turns into

    ($_ =:= $?SELF ?? $_.method :: fail "Phooey")

: > In any event, SMD methods always have a first argument, so you're never
: > in doubt at that point.  And since .bar always means $_.bar, I don't
: > think you really have a problem here that's any harder than you already
: > had with $_.
: 
: The problem here is for the compiler to detect whether $_ agrees
: with $?SELF, when it sees $?IMPLICIT_INVOCANT.  If they agree,
: $?IMPLICIT_INVOCANT gets replaced by $_; otherwise it is an error.
: 
: Consider this construct:
: 
:     method foo {
: 	$_ := $something_else if rand(2)>1;
: 	.bar;
:     }
: 
: That's one case where it's not possible to detect at compile time,
: so it needs to silently let .bar go thru as $_.bar.

Though Thomas's constant binding notion would presumably catch that.
But then we're getting into the "noalias" zone that Dennis Ritchie hates.
On the other hand, I can see lots of uses for variables that may
not be rebound, at least in terms of reassuring the optimizer that
Weird Things Can't Happen.

: > : Clearly we need a way to statically determine &statement:<given>
: > : and &statement:<for> will always assign at least one argument to
: > : its block argument.  Without that, the compile-time analysis mandated by
: > : Larry is infeasible.
: > 
: > I think you can assume that "given" and "for" always bind at least one
: > argument.  In particular, a "for" that binds 0 arguments will never
: > progress, plus you can recognize it:
: 
: But what in "given" and "for" signify that?  I do not want to special
: case based on function names, and &statement:<given> may be rebound
: to something else.

I understand the desire for generality, but that road also leads to
error messages that are completely opaque to naive users, who are
pretty accurate in their view that features like "given" and "for"
will Stay Put in the normal course of events.  Many of the most useful
diagnostics in Perl 5 are the ones that are guessing based on common
usage patterns.  Users can't do much with messages that when deciphered
come out to mean something like "you called a function passing as
its first argument another function whose first argument's declared
type allows it to be optionally bound to $_ but if we actually try to
make use of that we'll get some ambiguity further on down the road,
and that's bad."  They'd much rather chuck the generality and have
"You can't say .foo inside "given" where the topic could be either $_
or the method's invocant."  Or in the absense of that just blow up
at run time.

Of course, I'm just restating your problem here...

: How does that something else signify that it will
: at least bind at least one argument to its code argument?  Via the
: signature of the code argument, i.e. the <Any> in &code<Any>?
: 
:     sub statement:<given> (Any $topic, &code<Any>) { ... }

Maybe something like:

    sub statement:<given> (Any $topic, *&code:(Any is topic)) { ... }

: If so, what is the signature of "for"?  I can't seem to write it down.

Good question.  I suppose the signature wants to guarantee minimum arity
of 1 somehow.  Maybe

    sub statement:<for> (Lazy *@topics, *&code:(Any is topic, *)) { ... }

or some such.  But whether the outer function is actually functioning
as a topicalizer would still depend on the innards of your function.
Hmm.  We might settle for declaring such functions with a special trait
that indicates that they are *intended* to function as topicializers.
And then maybe the compiler could just depend on those declarations
for its static analysis:

    sub statement:<given> (Any $topic, *&code:(Any)) is topicalizer { ... }

Other that that we rely on the run-time check.  (Which hopefully common
code analysis can factor out multiple copies of.)

: > : Then, we need to figure out the structure for the magic flag set by
: > : self.pm on behalf of its caller.  We are not using $^H anymore, so
: > : there needs to be a way to pass lexical settings to the caller.
: > 
: > Perhaps hints should just be considered lexically scoped $? variables.
: > You export them lexically just the same way you export any other lexically
: > scoped things, however that is. 
: > 
: > How will you handle:
: > 
: >     use Foo :my<$x>;
: > 
: > Seems like this is just a kind of
: > 
: >     use Foo :my<$?MYHINT>
: > 
: > thingy, only perhaps you're just setting $?MYHINT rather than aliasing
: > it back into a Foo variable.
: 
: Yes, that's the main difference.  How does the :my<> form of export work
: in the exporter's end?
: 
:     sub foo is export<my> { ... }
: 
: Will that work?

Hrm, I don't think so.  For standard variables, that's not something
the exporter is supposed to worry about.  It's the importer that
decides what scope to import into.  The "is export<foo>" syntax is
for export tag groups, but those are orthogonal to the final scoping.

But since lexical scoping is the default import scope anyway, all we
need to do is make sure the hint variable gets exported mandatorily whether
requested or not, and maybe not worry about whether the user has a way
to divert the hint into a package variable.  So maybe it's just

    my $?MYHINT is export<MANDATORY> = 1;

Except for the small issue that this would also set $?MYHINT in this
scope.  I suppose

    {
	my $?MYHINT is export<MANDATORY> = 1;
    }

might be a workaround, but more likely we just need to tap into the
underlying exporter mechanism to create the lexical symbol and copy a
1 into it somehow rather than trying to create a spurious alias into
the exporting package that we'll throw away anyway.  Maybe there's
some kind of syntactic sugar for that, like a special declarator:

    importsym $?MYHINT = 1;

where ordinary export looks like

    importsym &foo ::= &bar;

Or whatever fills the niche of Perl 5's glob assignments.  We could go
as far as to just return a glob of code to eval after the "use", though
that's a bit source-filtery.  I think low-level exportation needs to
be done with some kind of generics, but I haven't thought it through yet.

Maybe it looks like some kind of role-ish upscopey block structure.

    EXPORT {
	our $packagevar;
	my $?MYHINT = 1;
	mysym &foo ::= &OUTER::bar;
	reexport Foo.all;	# conjectural (as if the rest isn't...)
    }

where "mysym" is a generic declarator that defaults to "my" but
is user overridable to "our" or "state" (which are also lexically
scoped names but have different dynamic lifetimes).  An EXPORT block
would only promote to a scope that was currently being compiled.
Presumably you could have multiple EXPORT blocks, with implicit EXPORTs
being generated from "is export" declarations.  Or else there's one
EXPORT and you have to call stdexports() from it if you rewrite it.
More likely EXPORTALL is the one export block that calls all the
individual implicit or explicit EXPORT blocks.

: > : Does this seem sane?  The static detection of $_ is the showstopper
: > : currently, and Pugs will need to separate the compiler with PIL evaluator
: > : to implement the pragma.pm above.
: > 
: > I suspect you're making it complicateder than it needs to be, but
: > perhaps I don't understand the problem fully.  Of course, the two are
: > not mutually exclusive...
: 
: Indeed I suspect both are true. :)

As you can plainly see, I also reserve the right to do both of those
at once all by myself.  :-)

Larry

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About