Re: Composing or chaining subroutines
by BrowserUk (Patriarch) on Jan 14, 2006 at 18:40 UTC
|
You're effectively talking about in-lining the subroutines.
I did once think that it might be possible to create a true macro facility in Perl 5 by using B::Generate. The basic idea was that you could introspect the code generated by the macro using B::Bblock and similar modules, alias the formal/actual parameters, and then patch the code into the expansion scope using B::Generate.
Unfortunately, I never managed to get B::Generate to compile here, so the idea died with those attempts.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
|
The biggest hurdle there is that you have to clone branches of opcodes, lest you rethread the next and child pointers in one instance and break them for all instances. That's quite difficult, as if dodging segfaults and infinite loops weren't enough.
| [reply] |
|
|
| [reply] |
|
|
True. That was remiss of me.
I think that given the lack of informed response I got from my question here, combined with the either totally absence of any response; condecending "you don't know what your doing, so I'm just gonna quietly close this bug report as 'user error'"; or outright hostile rants; I've received in the past, I guess I couldn't face the hassle.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
|
|
|
|
|
|
| [reply] |
|
|
I think that you may have misunderstood. I was not talking about source filter macros, but 'proper' macros.
The macro body would be an ordinary subroutine compiled by Perl in exactly the same way as any other subroutine. Then at INIT{} or CHECK() time, the calls to that subroutine would be inlined at the call site. That is, the opcode tree built for the macro body, would be cloned and inserted into the opcode tree in place of the call opcode, with references to it's formal arguments replaced by references to the actual arguments.
There would probably have to be some fairly strict restrictions on what the macro body could do, like
- no references to variables outside the scope of it's body.
- no recursion--either self or mutual.
- probably a lot of other things I haven't thought of.
I've also played with source filter macros, and got somethings to work--but they quickly get messy and never play nice with other source filters.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
Re: Composing or chaining subroutines
by traveler (Parson) on Jan 14, 2006 at 18:34 UTC
|
Is something like this what you need?
#first a simple demo
sub foo{ print "foo ",scalar caller,"\n";goto &bar}
sub bar{ print "bar ",scalar caller,"\n";goto &baz}
sub baz{ print "baz ",scalar caller,"\n";goto &bunk}
sub bunk{ print "bunk ",scalar caller,"\n";}
# now the chained functions
sub foo1{ print "foo1 ",scalar caller,"\n";chain(@list)}
sub bar1{ print "bar1 ",scalar caller,"\n";chain(@list)}
sub baz1{ print "baz1 ",scalar caller,"\n";chain(@list)}
sub bunk1{ print "bunk1 ",scalar caller,"\n";chain(@list)}
sub chain{
if(@list){
my $func = shift @list;
goto &$func;
}
}
# run the demo
foo();
# now establish the chain and call the funcs
#
@list = qw(foo1 bar1 baz1 bunk1);
chain(@list);
| [reply] [d/l] |
Re: Composing or chaining subroutines
by xdg (Monsignor) on Jan 14, 2006 at 18:30 UTC
|
1. There is a slight performance gain when you're dealing with more than 3-4 subroutines
That sounds like something that would have to happen in XS.
2. Debugging is much clearer because your callstack only has the subroutine called by the client and not all the intermediate subroutines.
Sub::Uplevel could be used, but that adds overhead instead of subtracting it. (There's also an off-by-one bug in it; I sent a patch to Schwern several months ago but it seems to be way low on his tuit list.)
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
| [reply] |
Re: Composing or chaining subroutines
by jeffa (Bishop) on Jan 17, 2006 at 17:04 UTC
|
use strict;
use warnings;
my $chain1 = chain(qw( rev Foo::uc b2_ ));
my $chain2 = chain(qw( Foo::uc b2_ rev ));
print for $chain1->(qw( foo bar baz ));
print for $chain2->(qw( foo bar baz ));
sub chain {
my $str = '@_';
$str = '&' . "$_($str)" for @_;
return sub { eval $str };
}
sub rev { map scalar reverse, @_ }
sub b2_ { my @a=@_;map {s/b/_/g;$_} @a }
package Foo;
sub uc { map ucfirst, @_ }
| [reply] [d/l] |
|
|
class Foo => {
class_method 'c_foo' =>
signature (Int, Num(5)),
body => { ... };
method 'foo' =>
signature (Any, Hash),
returns ( Int ),
body => { ... };
};
Foo->add_post_process(
methods => 1,
class_methods => 0,
action => sub { ... },
);
The idea being that you first have a check for if the referent is a class name or a blessed reference into that class. Then, you have a check on the parameters being passed in. All of these are really easily done as closures. Except, now every single method call has some 10-40 subroutines that stack 2-3 above the body of the method which, itself, is stacked. That's a massive performance penalty, plus it makes debugging errors extremely difficult.
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] [d/l] |
Re: Composing or chaining subroutines
by awwaiid (Friar) on Jan 17, 2006 at 23:42 UTC
|
Based on other responses I may be missing the point... but how about:
sub chain {
my (@subs) = @_;
sub { my (@p) = @_;
foreach (@subs) {
@p = $_->(@p);
}
}
}
sub a { $_[0] += 1; print "a - $_[0]\n"; @_ }
sub b { $_[0] += 2; print "b - $_[0]\n"; @_ }
sub c { $_[0] += 3; print "c - $_[0]\n"; @_ }
$x = chain(\&a, \&b, \&c);
$x->(7);
# Output:
# a - 8
# b - 10
# c - 13
| [reply] [d/l] |
|
|
I don't want to call the other functions. I want to create a function that acts as if I was doing what your function does. See my response to jeffa earlier in the thread as to why I want to do this.
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |