develooper Front page | perl.perl6.language | Postings from August 2001

sub --> macro optimization v. qe//

David L. Nicol
August 9, 2001 14:08
sub --> macro optimization v. qe//
Message ID:

> > [MJD] gets a factor of three speedup with the macro version.  Because,
> > guess what, it avoids the function call overhead.  Perhaps you made a
> > mistake.
> [SCHWERN] wrapped the thing up in a block.  David implied his macros would do
> that.  That's where all the overhead goes, entering a new block.

I also thought that empty blocks are stripped by the existing compiler.

use Benchmark;

sub one() { return $$ }


		noblock => sub { $$ },
		oneblock => sub {{ $$ };},
		twoblock => sub {{{ $$ };};},
		noblockS => sub { one },
		oneblockS => sub {{ one };},
		twoblockS => sub {{{ one };};}


I was wrong, whoops. Entering a block that doesn't do anything is
still very small though -- unless it's a constant, in which case
it gets "folded."

> I'd *love* to have a macro system in Perl.  The problem I have is
> hijacking the subroutine syntax to declare them.  It implies all sorts
> of magic is going to happen to avoid blasting off various limbs
> (ie. that it's a safe, drop-in replacement for a subroutine like
> constants are).
> If all we have is a slightly smarter version of cpp (ie. one that can
> intellegently find function calls rather than just a dumb s///) I'm
> happy.  You can put all sorts of clever module wrappers around it to
> make it safer (but slower).

Simple expression folding is a possible macro system, but it lacks the
use eases that C and Scheme macros have over subroutines. Evaluated-once
code is another possibility, and it would have a completely different
calling convention than a subroutine lookalike, although aliasing
@_ to the arguments would work.

	$myincrement = eval "sub(\$){\$_[0]+=$IncrementAmount";



succeeds in eliminating the variable lookup of $IncrementAmount,
or freezes it at a moment in time.

Could the one-time eval string be used as a macro system?  Eval-string
and normal-sub both persist with the bindings of variables as they are
at the time of their compilation.  C and Scheme macros use variable names
in their environment of deployment, which is what gives them their
strange power.

Maybe the qe// eval-but-don't execute 
quoting operators could take some postfix flags to indicate disposition as
to the time of name binding.  Levels:

	E	: early.  Bind all names at first sight
	L	: late. Defer binding names until 
	C	: complex (default.) Bind names local to current block 
		  early, bind all others late.
	e	: "eval" just like with s///, pre-evaluates string.

With this convention, the definition and use of a variable incrementing
operator might look like this:

	{ my $Increment = $IncrementAmount;
	  # $Increment can be treated like a constant:
	  $myincrement = qe/$_[0]+=$Increment/;

	$myincrement2 = qe/$_[0]+=$Increment/L;


	# becomes, $VC += (whatever IA was at def. time)

	# becomes, $VC2 += $Increment, bound in context of deployment

####### stopping here is reccommended: incomplete thoughts follow:

Another possibility would be to mimic eval(qq/.../) more closely
and have late-binding variables' sigils prefixed with backslashes.
While qq// causes unprotected scalars to be replaced with their
values at evaluation time, qe// might cause them to be replaced with
dynamic references to their mutable values:

	$TCVI = "The current value is";
	$CurrentValueString = qe/join('',$TCVI,\$Value)/;

that would wreak havoc with any code that produced references, so it would
not work, unless qe always does a qq pass (like qr and qx do) before
doing its own special operation on the resulting string -- if you wanted
references, you'd have to double your backslashes in there.

or if qo// did that, so you could store the text of a complex operation
in a variable, and then have dozens of lines like:

	$A = qo/$ComplexOp/;
	$B = qo/$ComplexOp/;

Or maybe the special quotes retain their meaning, so if you want
an initial qq pass on your expression to be evaluated, you use doublequotes
around it:

	$CurrentValueString = qe"$TCVI{$UserLanguage} \$Value";
	# equivalent to:
	# {my $P = $TCVI{$UserLanguage};
	# TieFetch CurrentValueString => sub { join(' ',$P,$Value) }
	# , assuming a TieFetch function that does what I want here 
	print $CurrentValueString;
	# or print &$CurrentValueString; # if we must

But we still don't have late binding, without doing an eval of some
kind in the deployment context.

AAAD? Yes, very.  that's what macros do for you.

                                           David Nicol 816.235.1187
"Tomato!" Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About