Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A6: macro invocants

6 views
Skip to first unread message

Dave Whipp

unread,
Mar 11, 2003, 8:35:34 PM3/11/03
to perl6-l...@perl.org
The effect of a macro is lexical; but "the name may be installed in
either a package or a lexical scope". If the name is installed in a
class, can it be invoked via a variable of that class?

Example (SQL query integrated via macro):

my Database $db = MySqlDatabase.connect(...);
$db.select * FROM Foo WHERE Foo.bar LIKE a%b;

Could I implement this with the select function being a macro on the
Database base class: but invoked via the $db invocant? I am aware that
the macro would be a compile-time operation: but it could resolve into a
run-time mechanism that uses the invocant.


Dave.
--
http://dave.whipp.name

Larry Wall

unread,
Mar 12, 2003, 1:23:33 PM3/12/03
to perl6-l...@perl.org
On Tue, Mar 11, 2003 at 05:35:34PM -0800, Dave Whipp wrote:
: The effect of a macro is lexical; but "the name may be installed in

If you use a module or class that defines macros, you can import the
syntax at that point as well as the name. Might take an explicit import
of the particular name to accomplish that though.

But basically, yes, you can do that. Macros would be pretty darn useless
if you couldn't import them.

Larry

Larry Wall

unread,
Mar 12, 2003, 1:27:31 PM3/12/03
to perl6-l...@perl.org
On Tue, Mar 11, 2003 at 05:35:34PM -0800, Dave Whipp wrote:
: The effect of a macro is lexical; but "the name may be installed in

To answer your actual question, you either need to have some keyword out
front to start the alternate parsing, or you need to treat ".select"
as an infix macro that has an ordinary expression on the left ($db) and
a specially parsed argument on the right (* FROM Foo WHERE Foo.bar LIKE a%b)

Larry

Dave Whipp

unread,
Mar 12, 2003, 6:35:58 PM3/12/03
to perl6-l...@perl.org
Larry Wall replied:

> : my Database $db = MySqlDatabase.connect(...);
> : $db.select * FROM Foo WHERE Foo.bar LIKE a%b;

> To answer your actual question, you either need to have some keyword out


> front to start the alternate parsing, or you need to treat ".select"
> as an infix macro that has an ordinary expression on the left ($db) and
> a specially parsed argument on the right (* FROM Foo WHERE Foo.bar LIKE a%b)

This feels a bit clunky. The sort of hack one makes when its too late to
fix it.

If we define .select as an infix macro, it is then not scoped to the
invocant. This means that it would confict with any other .select method
that one might wish to call. E.g.

$io.select(...);

(OK, thats not a good example, but you get the gist). If sure it would
be possible to write the macro in such a way that it looks at its LHS
arg -- and ignores itself if its not a Database object ... but that
places an overly large burden on the macro writer. To avoid this burden,
I'd like to propose C<macromethod> as a counterpart to C<submethod>. A
macromethod would enable me to write an invocant-scoped macro, without
polluting the lexical namespace:

class Database
{
...
macromethod select ($lhs, $rhs:) is parsed /<sql.select.body>/
{
"$lhs.do_sql('select $rhs')"
}
}

Without this mechanism, then we need a way to prevent an infinite
regress on macro processing. I am assuming that, if the output of a
macro is a string, then that string will be re-parsed and any macros in
it will be expanded. How would an infix macro indicate that it didn't
want to handle the "$io.select" example? If it returns its input,
unchanged, then that would be an infinite loop.


Dave.
--
http://dave.whipp.name

Luke Palmer

unread,
Mar 12, 2003, 7:47:22 PM3/12/03
to da...@whipp.name, perl6-l...@perl.org
Dave Whipp wrote:
> (OK, thats not a good example, but you get the gist). If sure it would
> be possible to write the macro in such a way that it looks at its LHS
> arg -- and ignores itself if its not a Database object ... but that
> places an overly large burden on the macro writer. To avoid this burden,
> I'd like to propose C<macromethod> as a counterpart to C<submethod>. A
> macromethod would enable me to write an invocant-scoped macro, without
> polluting the lexical namespace:
>
> class Database
> {
> ...
> macromethod select ($lhs, $rhs:) is parsed /<sql.select.body>/
> {
> "$lhs.do_sql('select $rhs')"
> }
> }
>
> Without this mechanism, then we need a way to prevent an infinite
> regress on macro processing. I am assuming that, if the output of a
> macro is a string, then that string will be re-parsed and any macros in
> it will be expanded. How would an infix macro indicate that it didn't
> want to handle the "$io.select" example? If it returns its input,
> unchanged, then that would be an infinite loop.

Well, if you did that, it surely couldn't be polymorphic, which kind
of defeats most of the purpose of making it a method. Yeah, namespace
pollution is a little issue, but not really. You could scope the
macro to the Database class, so it would be C<Database::select ...>.

Interestingly, it would be almost impossible to get effective methods
that use an C<is parsed> trait. Is it legal to do so?

Luke

Dave Whipp

unread,
Mar 12, 2003, 7:59:35 PM3/12/03
to perl6-l...@perl.org
Luke Palmer wrote:

> Well, if you did that, it surely couldn't be polymorphic, which kind
> of defeats most of the purpose of making it a method.

I disagree. Consider the "template method" patten. This uses a
non-polymorphic method in a base class to invoke a set of polymorphic
methods in a standard sequence. I would consider my "macromethod" in a
similar vain.

Dave.
--
http://dave.whipp.name

Luke Palmer

unread,
Mar 12, 2003, 8:11:05 PM3/12/03
to da...@whipp.name, perl6-l...@perl.org

I'm not quite sure I follow you (I'm not familiar with that pattern).
But the macromethod I imagine is the non-polymorphic one, and the one
it expands to is the polymorphic one, if I'm guessing correctly. And
you certianly could do that. But the actual I<parsing> could not be
polymorphic. Thus, this wouldn't work:

my $db = new Database;
$db.select ...

Because the compiler [may] not know that $db is a Database until
runtime, after it's been parsed. However, this could work:

my Database $db = new Database;
$db.select ...

Which may just be the price you have to pay to use C<macromethod>.
But then, the only advantage that I'm seeing to macromethod, other
than the namespace pollution bit, is that it can handle arbitrarily
complex variable names, which macros ought to do anyway. Which means
you usually have to use a parse tree instead of simple string
substitution (I trust Larry to make it sufficiently easy to do that).

So, what I'm essentially saying is that C<macromethod> doesn't buy you
much save syntactic sugar. Perhaps you can give a concrete
counterexample?

Luke

Larry Wall

unread,
Mar 12, 2003, 7:18:19 PM3/12/03
to perl6-l...@perl.org
On Wed, Mar 12, 2003 at 03:35:58PM -0800, Dave Whipp wrote:
: Larry Wall replied:

: >: my Database $db = MySqlDatabase.connect(...);
: >: $db.select * FROM Foo WHERE Foo.bar LIKE a%b;
:
: >To answer your actual question, you either need to have some keyword out
: >front to start the alternate parsing, or you need to treat ".select"
: >as an infix macro that has an ordinary expression on the left ($db) and
: >a specially parsed argument on the right (* FROM Foo WHERE Foo.bar LIKE
: >a%b)
:
: This feels a bit clunky. The sort of hack one makes when its too late to
: fix it.
:
: If we define .select as an infix macro, it is then not scoped to the
: invocant. This means that it would confict with any other .select method
: that one might wish to call. E.g.
:
: $io.select(...);
:
: (OK, thats not a good example, but you get the gist). If sure it would
: be possible to write the macro in such a way that it looks at its LHS
: arg -- and ignores itself if its not a Database object ... but that
: places an overly large burden on the macro writer. To avoid this burden,
: I'd like to propose C<macromethod> as a counterpart to C<submethod>. A
: macromethod would enable me to write an invocant-scoped macro, without
: polluting the lexical namespace:
:
: class Database
: {
: ...
: macromethod select ($lhs, $rhs:) is parsed /<sql.select.body>/
: {
: "$lhs.do_sql('select $rhs')"
: }
: }

I am uncomfortable with the notion of depending on the declared type of
the left argument for deciding which macro to use, because its failure
mode potentially includes totally misparsing the right argument, and
because the declared type of the object is not necessarily the same
as the actual type, so if a derived class had its own idea of the macro,
the "wrong" macro would be used according to at least one viewpoint.

: Without this mechanism, then we need a way to prevent an infinite

: regress on macro processing. I am assuming that, if the output of a
: macro is a string, then that string will be re-parsed and any macros in
: it will be expanded. How would an infix macro indicate that it didn't
: want to handle the "$io.select" example? If it returns its input,
: unchanged, then that would be an infinite loop.

If the declaration is essentially nailing down a particular class in
a non-virtual sense, then there's really nothing gained over writing

IO::select $io: ...
DB::select $db: ...

other than the obvious obfuscational benefit of having the class
selection defined elsewhere.

I'm not saying that what you want is bad. I'm just uncomfortable
with it. Certainly a macro could be written to pay attention to the
declared type of its left argument, and we could even arrange for
some kind of compile-time multimethod dispatch with whatever syntax
is deemed appropriate. But mixing such compile-time semantics with
a notation that supposedly mandates run-time dispatch is a recipe
for a certain amount of confusion no matter how well we do it.

Larry

Dave Whipp

unread,
Mar 12, 2003, 9:16:04 PM3/12/03
to perl6-l...@perl.org
Luke Palmer wrote:
> I'm not quite sure I follow you (I'm not familiar with that pattern).
> But the macromethod I imagine is the non-polymorphic one, and the one
> it expands to is the polymorphic one, if I'm guessing correctly. And
> you certianly could do that.

yes: http://patterndigest.com/patterns/TemplateMethod.html

> But the actual I<parsing> could not be
> polymorphic. Thus, this wouldn't work:
>
> my $db = new Database;
> $db.select ...
>
> Because the compiler [may] not know that $db is a Database until
> runtime, after it's been parsed. However, this could work:
>
> my Database $db = new Database;
> $db.select ...

To a large extent, this depends on how powerful the type-inference
mechanisms are. In theory, if MyDatabase.new "returns Database", then
the type of $db can be inferred. Even if the return type is not
explicitly defined, we can look in the method-body, and see that its
constructing/returning an object of base-type Database.

But you're right, there are situations where the (base) type might not
be knowable: and these could result in syntax errors.

> So, what I'm essentially saying is that C<macromethod> doesn't buy you
> much save syntactic sugar. Perhaps you can give a concrete
> counterexample?

I admit that I have a sweet-tooth: I like syntactic sugar ;-). And I'm
one of those environmentalists who don't like (namespace) pollution.

The sugar I'm using here is to go from

$db.do_sql("select * from Foo");
to
$db.select * from Foo;

I'm sure there is nice way to represent this with a leading keyword: but
one of the things that Perl6 is doing (over perl5) is to make (almost)
everything callable as methods. Thus if we allow (as a standard macro --
though a macromethod would also support it)

select $db: * from Foo;

then we should also allow the method-call syntax. I'll admit that this
is one of those cases where the user already knows that there's some
magic happenning -- that "select" is introducing a new syntax -- but it
would be nice to keep the invocant part looking like Perl6 code.

Perhaps I should back off a bit: Perl6 *will* be powerful enough support
the "Macros::macromethod" module, so perhaps I'll be able to write it in
a year's time, or so. It'll be a good test of the extensability mechanisms.


Dave.
--
http://dave.whipp.name

Brent Dax

unread,
Mar 12, 2003, 9:32:38 PM3/12/03
to Dave Whipp, perl6-l...@perl.org
Dave Whipp:
# But you're right, there are situations where the (base) type
# might not
# be knowable: and these could result in syntax errors.

Except they wouldn't, at least not always.

$db.select * FROM Foo WHERE Foo.bar LIKE a%b;

$db.select() *
FROM(
Foo(
WHERE(
Foo.bar()
)
) LIKE (
a % b
)
);

The only part of that I'm not sure about is infix:LIKE, since such an
operator hasn't been declared. But I assume you get the idea--you could
conceivably have Very Bad Things happen if Perl doesn't catch a
macromethod call.

--Brent Dax <bren...@cpan.org>
@roles=map {"Parrot $_"} qw(embedding regexen Configure)

>How do you "test" this 'God' to "prove" it is who it says it is?
"If you're God, you know exactly what it would take to convince me. Do
that."
--Marc Fleury on alt.atheism


Dave Whipp

unread,
Mar 12, 2003, 10:29:58 PM3/12/03
to perl6-l...@perl.org
Brent Dax wrote:
> Dave Whipp:
> # But you're right, there are situations where the (base) type
> # might not
> # be knowable: and these could result in syntax errors.
>
> Except they wouldn't, at least not always.
>[snip]

>
> The only part of that I'm not sure about is infix:LIKE, since such an
> operator hasn't been declared. But I assume you get the idea--you could
> conceivably have Very Bad Things happen if Perl doesn't catch a
> macromethod call.

But in such cases, the $db variable would not (could not) have a
run-time ".select" method: so you'd still get an error -- albeit at run
time.

Dave.
--
http://dave.whipp.name

Paul

unread,
Mar 13, 2003, 10:39:58 AM3/13/03
to Dave Whipp, perl6-l...@perl.org
> The sugar I'm using here is to go from
>
> $db.do_sql("select * from Foo");
> to
> $db.select * from Foo;

Since we're fishing, call it a circumfix operator, something like
sql...execute.
Like this:

$db.sql select * from Foo;
execute;

__________________________________________________
Do you Yahoo!?
Yahoo! Web Hosting - establish your business online
http://webhosting.yahoo.com

0 new messages