I guess I can build a 'closure' object that knows how to dump itself but there is still the problem of dumping use'd CPAN modules I don't think that's possible without 5-on-6 one possible solution is, perl5 modules are loaded twice - at compile and runtime assuming you can be sure of getting the same one... or at least one that has the same interface Ada was always big on separating the interface from the implementation so you could swap out the implementation without changing the interface the reload trick should work find for Perl 6, because we guarantee that the user can't modify the used. and we also guarantee that modules installed in the library have version numbers so in an a.b.c the b theoretically guarantees a unique interface. and you already presumably know how to save your own closures, or you wouldn't a compiler... # - kp6 needs a way to export subs to the runtime use Data::Dump::Streamer; use strict; sub X { print "ok" } print Dump( \&X ); __END__ xxxx - Possible BEGIN workflow: # there is no subs in a namespace - everything is either our or my our $main::var; # in declaration order package Main; my $y; my $z; our $_SUB_begin_001_ = sub { my $x; $y = sub { $x }; $z = sub { $x } } INIT { $Main::_SUB_begin_001_->() } #--- use Data::Dump::Streamer; use strict; my $x; BEGIN { $x = 4 }; # turns into my $__CEV_x1 = \do { my $x }; INIT { $$__CEV_x1 = 4; print Dump $__CEV_x1; } print Dump $__CEV_x1; #--- BEGIN { use X @list; } # turns into BEGIN { require X; # no X calls 'unimport' instead of 'import' X.import( @list ) if UNIVERSAL::can('X', 'import'); } # from perldoc -f require sub require { my ($filename) = @_; if (exists $INC{$filename}) { return 1 if $INC{$filename}; die "Compilation failed in require"; } my ($realfilename,$result); ITER: { foreach $prefix (@INC) { $realfilename = "$prefix/$filename"; if (-f $realfilename) { $INC{$filename} = $realfilename; $result = do $realfilename; last ITER; } } die "Can't find $filename in \@INC"; } if ($@) { $INC{$filename} = undef; die $@; } elsif (!$result) { delete $INC{$filename}; die "$filename did not return true value"; } else { return $result; } } #--- my $__CEV_x1 = \do { my $x }; INIT { say $$__CEV_x1; LEAVE { undefine $__CEV_x1 } } #--- my $y; my $z; BEGIN { my $x; $y = { $x }; $z = { $x } } __END__ - BEGIN blocks are executed at parse time token BEGIN { BEGIN { execute_begin; return ... } } - CEV = "compile-time existing variables" (luqui++) - This is one case when BEGIN has a variable which doesn't exist at compile-time: for 1,2 { my $x = sub { my $y; BEGIN { $y = 42 }; say $y }; $x() } so, how about this: it is illegal to assign to non-existant varaibles at compile-time we just need to define 'exists' appropriately a variable exists if... it is in a closure that cannot be cloned? that is, if $x can only ever refer to one thing, then it exists at compile-time I like that... so crap like this: for 1,2 { my $x; BEGIN { $x = 10 }; say $x } is illegal but: { my $x; BEGIN { $x = 10 }; sub foo() { $x } } is not (assuming that closure was in void context...) then, in the pad structure, you can store existent variables and reasonably initialize them at the beginning of runtime inside their scope... it could work like this - each 'my' decl creates a new pad, at compile-time and BEGIN blocks are moved to the start of the pad code where by "moved to " you mean "executed and then the pad's environment is dumped at" ? my $y; for 1..rand(10) { my $x = $_; BEGIN { $y = { $x } } } $y() now what? I assume it will be 1 if the body ever gets executed and undef otherwise so to clarify, $y() can return undef, but regardless $y is a code object, and has to refer to something whether we can get the "first time through" uses compiler's pad thing to work is the real issue, I expect I agree with luqui on the general principle--a BEGIN can only influence structures that exist at compile time by side effect. Other than that, all it can do is return a value. the "extra" question is whether there are extraordinary structures we can have at compile time that do things at run time and I think the answer is, don't sweat it for now. right. I think you can generate code to initialize all "compile-time existing" variables at the beginning of their scopes, and the semantics will be correct (though it is indeed a bit tricky if they refer to each other) my $x; INIT { $x = 1 } BEGIN { $x = 2 }; say $x; or even: that's a problem n/m oh dear I was going to say that you have to move side-effects to the beginning of the scope where the affected variables were however: *** koye [i=milan@195.252.85.84] has joined #perl6 my $x; ...stuff { my $y; BEGIN { $x = { $y }; $y = { $x } } ...stuff } ahh, pathological examples, my favorite it is impossible to initialize $x at the beginning of its scope ok... so, BEGIN blocks can only work on "compile-time existing variables" (this assumption is getting more and more useful) so you don't scope them they are all global then you can rig them to refer to each other but of course, that has GC problems... I'm compiling to "desugared p6", which compiles either to p5 or parrot *** theorbtwo [n=theorb@dyn-62-56-59-40.dslaccess.co.uk] has joined #perl6 <[particle]> you'll need weak references hmm, so we need something where the creation of an object can claim a reference instead of creating it this is not a standard language feature :-( let's see here (brainstorming commencing) all compile-time existing variables (CEVs) are globals with an extra level of indirection what's a non-CEV example? *** hexmode [n=mah@pool-162-83-250-134.ny5030.east.verizon.net] has quit [Read error: 54 (Connection reset by peer)] so: "my $x; BEGIN { $x = 4 };" turns into "my $__CEV_x1 = \do { my $x }; $$__CEV_x1 = 4;" non-CEVs are things like $x in for 1..3 { my $x } k then you undef the reference at the end of its scope so: "{ my $x; say $x }" turns into "my $__CEV_x1 ... ...; { say $$__CEV_x1; LEAVE { undefine $__CEV_x1 } } the initialization of all CEVs happens first thing in the the program before any other INIT blocks I think that actually does solve the circular-dependency pathology and the GC problem it's just... ugly my $y; my $z; BEGIN { my $x; $y = { $x }; $z = { $x } } $x is not CEV, but you have to express that the variable that $y and $z are referencing are the same one --- is a BEGIN block compiled, and then executed - or is it compiled/executed a statement at a time BEGIN just compiles like a normal closure, but executes after final } it can have a BEGIN inside it, right? yes but you don't need statement granulatity on you compiler pipeline closure granularity is good enough what about a BEGIN with an END in it? the END doesn't care still executes when the run-time is exiting all END/CHECK/INIT do are push a closure on a queue perhaps just push everything and let the caller decide pop vs shift. then the list always reflects lexical order, for which there is something to be said. especially if people add new blocks with weird execution orders, like dependencies that have to be calculated at run time. --- about 'use' requiring a disassembler is not a reasonable requirement for 6-on-6 I'll try to find other solutions for your own closures, surely you have the original AST or at least "had" at some time in the past... yes - I'm working on that direction... and anything imported just has to have a "true name" that you can relink to at run time. *** GabrielVieira [i=mad@201.79.177.80] has quit [Read error: 110 (Connection timed out)] I wonder if it would be useful to have the program dump'able at any time - as a side effect of having enough info available in fact, "is export" basically just makes a link to a name in a subpackage... the Smalltalkers would like that... but I'm not sure it's practical on every VM basically, you have the source file, global variables, and the pads - only the stack is missing but cps can take care of that could you can't remember foreign stacks in any case, if you've called out to some other runtime that doesn't integrate with your cps which is why cps systems tend to shun outside "help", I suspect. ah we could start a marketing campaign for "100% Pure Perl" I suppose, but it seems a bit unperlish... I suppose if you can replay all the API events to a non-cps system you can fake a continuation. ignoring side effects. and assuming you could restart the API in a consistent state. well, not today's problem. sure :) anyway, assuming all imports are done with true names, a re-use at runtime only has to do a require, not an import. *** penk [n=ubuntu@218-162-96-76.dynamic.hinet.net] has joined #perl6 course, the whole point of pragmas is to cheat... but maybe we can help them "cheat fair" *** spx2 [n=chatzill@89.37.70.170] has quit [Read error: 131 (Connection reset by peer)] the 'use' implementation probably needs to install hooks to do the right thing at INIT and I'm saying that hopefully the right thing is just a require require just says "make sure the package aka (true names) are populated" normal importation should have mapped all aliases to package symbols that require will bring in so nothing needs to be realiased at run time. you mean, the generated code is something like this? require X; *s = \&X::s; that implies to me that "use Foo" resolves to "use Foo-1.2.3-JRANDOM" at compile time well, P6 does lexical imports by default, not typeglobs what does it desugars to? require Foo-1.2.3-JRANDOM; s := X::s how do you import a sub? I'm saying that if you have something aliased to X::s at compile time, the dump of that structure should preserve the alias without having to regenerate it a run time. I mean, what does the dump would look like? how do you dump lexicals currently with their latest compile-time value? I call a subroutine that is defined inside the lexical scope an 'inspector' sub so if you've got "my $importsub = \&X::s" there... it just needs to find a way at run time to remap $importsub back to the "X::s" true name aka symbolic reference so basically linking is turning symbolic refs back into hard ones, I guess. what is the p6 syntax for this? "my $importsub = \&X::s" phone & pesky phones my &importsub := &X::s; hmm - when to use ::= ? we might have to limit the exportation of anonymous subs though, I suppose. or assign them an obfuscated true name for linking purposes. for now we can just make "sub is export {...}" illegal *** renormalist [n=ss5@renormalist.net] has joined #perl6 and if there's a custom import sub, it can handle its own semantics presumably... I guess I need to start implementation - I'd like to have something runnable to experiment with including, presumably handing the user a thunk to poke into the INIT queue. for now assume you don't have to save anything anonymous across a use boundary. that's the main point of package namespaces, after all--to hold the public interface why can't you use Data::Dump::Streamer as a catch-most method? *** elmex [n=elmex@pD9E9FE6B.dip.t-dialin.net] has joined #perl6 luqui: one reason is that it renames variables hmp another reason is to avoid cheating - this is 6-on-6, and it doesn't have a disassembler ahh okay, that makes sense v6.pm does use DDS --- compilation x parsing - These things must be emitted and created (eval'ed) right after they are parsed: sub, variable, method declaration no assignment, no binding note that signatures can also declare variables: sub x ( &todo ) { ... } for @a -> $x { ... } - what kind of things should not be executed? - no restrictions - need a global 'current compiler pad' - how to make it lexical? - maybe use $?GRAMMAR to store it, or COMPILING::<$?PAD>