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

sub --> macro optimization v. qe//

From:
David L. Nicol
Date:
August 9, 2001 14:08
Subject:
sub --> macro optimization v. qe//
Message ID:
3B72F99F.C86B1BFE@kasey.umkc.edu

> > [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 $$ }

timethese(200000,

	{
		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";

	...

	&$myincrement($VariableCounter);

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;

	...

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

	$myincrement2($VariableCounter2);
	# 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!"




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