6macros: discussing the finer points of Perl 6 macros, Qtrees, and how to stay sane | irclog: irclog.perlgeek.de/6macros/today
Set by moderator on 28 July 2015.
02:57 ilbot3 joined 09:10 cgfbee joined 09:25 cgfbee joined 09:45 Ven`` joined
Ven`` masak: are you not gonna say? :) 09:46
masak I explained it to sergot in privmsg the other day. let me make you a gist 10:38
Ven``: gist.github.com/masak/4ed7ec0fe455...eb20cb113a 10:43
Ven`` oh, ok. it's been a while since I've seen sergot write here. 10:44
OK, I see 10:46
masak makes sense? 10:47
I still rope sergot++ in via privmsg quite a lot. he doesn't have a lot of time to hack on 007, but he's often available as a sounding-board
Ven`` sure, makes sense. 10:49
masak I'm still not 100% sure of what the "new thing" is, the one that has a different $.outer-frame each time 10:58
Ven`` I still feel like this is one of those self-inflicted issues by choosing to do it "The Perl Way". 11:08
14:36 <masak> to make that clear, if we don't do anything about that, the output would be "1\\nNone\\n" 14:37 <masak> because at compile time, the value of `z` is None
that really ought to be irrelevant. in `macro moo(z){} var y = 2; moo(z)`, what we pass to moo isn't 2. it's a "variable" 11:09
I'm not sure I agree with the foo/bar nested sub examples. There's nothing to "refresh", unless we suppose "our" semantics. 11:13
(and I've always been vocal about forbidding our subs in subs, method in method, etc)
masak ok, one thing at a time 11:31
first off, I had no idea you were against subs in subs. I find it hard to imagine a world without them. I have no idea why you would want to forbid them. 11:32
yes, of course we're taking on self-inflicted issues by choosing to do it The Perl Way. that's basically the whole raison d'ĆŖtre for 007 ;) 11:33
if I just wanted to do Lisp macros the Lisp way, we'd been done a long time ago
I disagree on a factual basis with "There's nothing to 'refresh'", and I'm willing to back it up with proof 11:34
in fact, that last bit feels like the most pressing one to find common ground on, if you're up for it 11:35
conceptually, even though that's not at all the implementation in 007, named subs are "hoisted", like in JavaScript. which is why you can call a sub before its declaration. 11:36
and so `sub bar() { say(y) }` is equivalent to `my bar = sub() { say(y) };`, except that the code inside `foo` becomes more equivalent to `my y; my bar = sub() { say(y) }; y = x + 1; return bar;` 11:38
either way, `bar` refreshes because it gets assigned every time on `foo` entry. which is twice in the example in question. 11:39
Ven`` masak: I'm against *our* subs in subs. The keyword "our"/ 11:48
not the english word "our". 11:49
masak ah 11:52
sorry, missed the "our" in there
now it makes a whole lot more sense
yes, all sane people are against `our` subs in subs. can't put a bigger thing in a smaller thing, after all
methods in methods are dubious, I agree. I don't really know how I feel about them. they won't be syntactically allowed in 007 ;) 11:53
but I do maintain there is something to refresh, as above 11:54
S04 even has a long section on it, `=head1 When is a closure not a closure` 11:55
Ven`` by hoisted, you mean that `my x = 1; sub bar { say(x) }` becomes `my x; sub bar { say(x) }; x = 1;`?
masak aye
Ven`` right
masak but more than that
there's an *assignment* in there, to `bar`
Ven`` it means you can actually do `bar(); sub bar {print(1); }` then?
oh yeah, i forgot to rewrite the assignment 11:56
masak yes, you can call before defining. it's worked in 007 for ages. try it.
the assignment is the important bit, because it happens once per `foo` call
Ven`` well, JS hoists every single declaration. I sometimes get caught trying to cheat when writing lua.
the foo is the outer sub, aye? 11:57
masak the only thing that gets hoisted in 007 is statement subs
aye
Ven`` that's where we disagree, then. I don't believe in "reusing" structure.
I'm not sure I can explain this properly. But what you say sounds wrong to me on a fundamental level, because it assumes that there's a "bar" that lives, even after foo returns
masak not the name, but the value in that variable, absolutely 11:58
Ven`` yes, but the *variable* surviving makes no sense to me.
masak it's a functional value, which in this case means function + environment
I'm not talking about the variable surviving. maybe we're still at cross purposes
I'm talking about the mechanism behind the thing in `bar` knowing its OUTER
Ven`` i'm saying there's a new bar every single time that foo is called. 11:59
masak well, yes and no
Ven`` so there's nothing to "refresh", because bar was created when foo was entered, and thus keeps its everything
masak there's only ever one declaration in the code
Ven`` BRB food
masak but there are two memory allocations
because two `foo` calls
if you disagree with the usage of the word "refresh", then I'll grant you that 12:00
they are completely distinct things; they only share the same underlying function code
but this is exactly where I'm not 100% clear with the Q::Expr::BlockAdapter for the macro argument; because it presumably *does* stick around and needs to be refreshed 12:01
...I'm not sure how it will work, exactly 12:02
it feels wrong to modify anything inside a Q node at runtime
though my desperation meter is set at "pretty desperate" at this point, and I'd like to merge `macro infix:<ff>` even if it means taking on some technical debt to sort out later 12:16
12:31 Ven`` joined
Ven`` masak: where does the Q::Expr::BlockAdapter come in? 12:32
in the argument?
at this point it's pretty clear I don't understand what "refresh" is supposed to mean in this context 12:35
masak I wrote ⦃z⦄ in the gist becuase `z` comes from the mainline, and the ⟦...⟧ already switched us into the injectile's scope 12:40
both of those types of scope switching are done with Q::Expr::BlockAdapter
(modulo the fact that I haven't implemented it for the macro args yet, not even in the infix:<ff> branch) 12:41
Q::Expr::BlockAdapter contains a Q::Block, which has a $.frame 12:42
the macro expansion leaves the $.frame of ⦃z⦄ as the mainline's static frame -- that's both a best effort kind of thing and really the only option 12:43
but at runtime, it needs to be the mainline's runtime frame
hence "refresh"
notice that if the macro argument that was inserted was ⦃do BEGIN { z }⦄ (*handwave*), then it's actually correct that the OUTER is the mainline's static frame 12:45
Ven`` well 13:46
macro moo(y){var x = 2; quasi { print(x + {{{y}}}); } }; var z = 3; moo(z); 13:54
desugars, to, basically, var SCOPEOUTER::z; var SCOPEMACRO::x; z = 3; BEGIN SCOPEMACRO::x = 2; print(SCOPEMACRO::x + SCOPEOUTER::z); 13:55
that's the very basic premise 13:57
now the point is – here, the frame doesn't appear on the *frame*, it appears on *variables*
masak because... when the macro expands, `z` has been replaced by `SCOPEOUTER::z`, some kind of variable-in-a-package? 14:14
trying to understand here
Ven`` yes. that was also what I was trying to explain when linking to some racket stuff 14:25
the variable isn't just a identifier, it's also a "where from".
masak 007 had that model for a long time. we're now sort of leaving it behind again. 14:28
it's not completely too late to halt that process, but I've documented fairly well why we're doing so
Ven`` I need to go (re)read that then. Because it seems like it 14:37
's what schemes do.
github.com/masak/007/issues/212 15:10
is that the issue I need to re-read, masak ?
> The pathology can be summarized as "attach all identifiers in the quasi (regardless of depth) to the scope outside the quasi (typically the macro's scope)". This is wildly, hilariously wrong. 15:12
I think I can sum up the issue with this, here.
I think this is perfectly correct. 15:13
...to one extent.
when you see macro moo(y){var x;}, *both* should be variables with moo's lexical scope as their scope
y's *value*, however, is an identifier, with a different scope. Namely the outer scope. 15:14
this is *partly* why we need {{{ }}}, anyway.
to sum up the first (reduced) case: 15:17
macro moo(a) { return quasi { my x = {{{a}}} } }; moo(7)
here, in moo, a is an identifier with scope=the macro's. then we have the quasi, which creates a new scope inheriting the macro's. it declares x with this scope as a parent, and it "melts" a. a is NOT looked up in this scope, but in the macro's 15:19
this is what I meant by "the lisp way". 15:20
(I didn't mean without hygiene)
ah, that one example was fixed anyway
OK, only the unreduced OP code is still broken 15:21
gist.github.com/vendethiel/9e20afc...b5604a158f 15:24
basically, this
18:17 Ven`` joined
masak I am pleased to announce I agree with all of the above 19:32
also, I believe you've found the issue in question
but let me find/quote another bit from it
(from a 2015 commit) "Wrapping everything in carefully crafted blocks doesn't seem to be enough." (so giving identifiers a frame instead) 19:34
(from the Aug 2017 comment in that issue) "Seems we've been walking in a circle for the past two years... but that's fine too as long as we come back to the original point having learned something."
19:56 Ven`` joined 19:57 Ven`` joined 22:29 Ven`` joined 22:38 Ven`` joined