Hello all.
I've just spent a nontrivial amount of time digging into BlockClosure>>once magic because the following code snippet did not work as (I) expected: SomeClass class>>someResource ^[self createSomeResource] once. SomeClass class>>createSomeResource ^Object new. The method #someResource returns new Object each time it is called. It has the following byte code: 1 <44> push self 2 <FA 00 01> make copying block (1) "<-- this is the cause" 5 <CC 01> no-check send once 7 <65> return as opposed to the direct (and working) form: SomeClass class>>someResource ^[Object new] once. which has the following byte code: 1 <1C> push BlockClosure [] in SomeClass class>>someResource 2 <CC 01> no-check send once 4 <65> return In retrospect, I admit that my usage was wrong, but it would be nice if it was documented somewhere (preferably in BlockClosure>>once method comment) because it was not that easy to spot :-) Anyway, happy coding and thank you for reading thus far, Ladislav Lenart _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
On 3/20/2012 4:06 PM, Ladislav Lenart wrote:
> > In retrospect, I admit that my usage was wrong, At quick glance I disagree with that conclusion: why should ^[OtherClass new] once behave differently from ^[self new] once ? R - _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Well, that's why I wrote the post in the first place - to
inform others about this minor but very cleverly hidden glitch :-) But perhaps I formulated my conclusion too roughly. Maybe I should write this instead: The EXPECTED albeit undocumented (and the only working) usage pattern is this: * You have a collection of assets implemented in Assets subclass. Let's call it AssetsSubclass. * AssetsSubclass implements generated class methods, each represents one resource. * Each such method has the form: someResource ^[SomeResource new] once * The purpose of #once is to cache the result of the block ONCE and use it for all subsequent calls to #someResource. * When you later recompile #someResource, the block will be evaluated ONCE again to cache new (possibly modified) resource. The last point is crucial here. The resource will be updated only when the method #someResource changes. If you use some kind of indirection inside the block, you will loose this feature: the old cached value will not be forgotten if you change a method called inside the block. Hence my: "I admit that my usage was wrong". My ideal implementation of #once would: * Have the same syntax, because I think it's just awesome. * Impose no limits on the context of the block (self vs. no self and whatnot). * Forget the cached value whenever ANY of the involved methods changed (i.e. all methods called inside the block and recursively all methods called inside them). * Have to be easy to inspect the current value (no idea here). This would eliminate the need to use class ivars for caching and it would just work, i.e. no more time spent debugging some failed tests only to discover that I forgot to call one of my #flushSomething methods. But I digress :-) Ladislav Lenart On 20.3.2012 17:08, Reinout Heeck wrote: > On 3/20/2012 4:06 PM, Ladislav Lenart wrote: >> >> In retrospect, I admit that my usage was wrong, > > At quick glance I disagree with that conclusion: > > why should > > ^[OtherClass new] once > > behave differently from > > ^[self new] once > > ? > > > R > - > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
It doesn't sound feasible to me. For example, suppose a method sent in the once block did not change, but its class was reparented?
Or if that method sent #at:, or some other common messages, would you really tag hundreds or thousands of methods so you could clear the once block's cache if any of them changed? Dave Stevenson[hidden email] From: Ladislav Lenart <[hidden email]> To: Reinout Heeck <[hidden email]> Cc: [hidden email] Sent: Tue, March 20, 2012 12:20:58 PM Subject: Re: [vwnc] [vw7.7] Perhaps unknown limitation of BlockClosure>>once (in Assets) Well, that's why I wrote the post in the first place - to inform others about this minor but very cleverly hidden glitch :-) But perhaps I formulated my conclusion too roughly. Maybe I should write this instead: The EXPECTED albeit undocumented (and the only working) usage pattern is this: * You have a collection of assets implemented in Assets subclass. Let's call it AssetsSubclass. * AssetsSubclass implements generated class methods, each represents one resource. * Each such method has the form: someResource ^[SomeResource new] once * The purpose of #once is to cache the result of the block ONCE and use it for all subsequent calls to #someResource. * When you later recompile #someResource, the block will be evaluated ONCE again to cache new (possibly modified) resource. The last point is crucial here. The resource will be updated only when the method #someResource changes. If you use some kind of indirection inside the block, you will loose this feature: the old cached value will not be forgotten if you change a method called inside the block. Hence my: "I admit that my usage was wrong". My ideal implementation of #once would: * Have the same syntax, because I think it's just awesome. * Impose no limits on the context of the block (self vs. no self and whatnot). * Forget the cached value whenever ANY of the involved methods changed (i.e. all methods called inside the block and recursively all methods called inside them). * Have to be easy to inspect the current value (no idea here). This would eliminate the need to use class ivars for caching and it would just work, i.e. no more time spent debugging some failed tests only to discover that I forgot to call one of my #flushSomething methods. But I digress :-) Ladislav Lenart On 20.3.2012 17:08, Reinout Heeck wrote: > On 3/20/2012 4:06 PM, Ladislav Lenart wrote: >> >> In retrospect, I admit that my usage was wrong, > > At quick glance I disagree with that conclusion: > > why should > > ^[OtherClass new] once > > behave differently from > > ^[self new] once > > ? > > > R > - > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Of course you are right. It is not feasible. But
that's the usual relationship with ideals :-) Ladislav Lenart On 20.3.2012 18:35, Dave Stevenson wrote: > It doesn't sound feasible to me. For example, suppose a method sent in the once block did not change, but its class was reparented? > Or if that method sent #at:, or some other common messages, would you really tag hundreds or thousands of methods so you could clear the once block's cache if any of them changed? > Dave Stevenson > [hidden email] > > > -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > *From:* Ladislav Lenart <[hidden email]> > *To:* Reinout Heeck <[hidden email]> > *Cc:* [hidden email] > *Sent:* Tue, March 20, 2012 12:20:58 PM > *Subject:* Re: [vwnc] [vw7.7] Perhaps unknown limitation of BlockClosure>>once (in Assets) > > Well, that's why I wrote the post in the first place - to > inform others about this minor but very cleverly hidden > glitch :-) > > But perhaps I formulated my conclusion too roughly. > Maybe I should write this instead: > > The EXPECTED albeit undocumented (and the only working) > usage pattern is this: > * You have a collection of assets implemented in Assets > subclass. Let's call it AssetsSubclass. > * AssetsSubclass implements generated class methods, each > represents one resource. > * Each such method has the form: > > someResource > ^[SomeResource new] once > > * The purpose of #once is to cache the result of the block > ONCE and use it for all subsequent calls to #someResource. > * When you later recompile #someResource, the block will > be evaluated ONCE again to cache new (possibly modified) > resource. > > The last point is crucial here. The resource will be updated > only when the method #someResource changes. If you use some > kind of indirection inside the block, you will loose this > feature: the old cached value will not be forgotten if you > change a method called inside the block. > > Hence my: "I admit that my usage was wrong". > > My ideal implementation of #once would: > * Have the same syntax, because I think it's just awesome. > * Impose no limits on the context of the block (self vs. > no self and whatnot). > * Forget the cached value whenever ANY of the involved > methods changed (i.e. all methods called inside the > block and recursively all methods called inside them). > * Have to be easy to inspect the current value (no idea > here). > > This would eliminate the need to use class ivars for > caching and it would just work, i.e. no more time spent > debugging some failed tests only to discover that I > forgot to call one of my #flushSomething methods. > > But I digress :-) > > > Ladislav Lenart > > > On 20.3.2012 17:08, Reinout Heeck wrote: > > On 3/20/2012 4:06 PM, Ladislav Lenart wrote: > >> > >> In retrospect, I admit that my usage was wrong, > > > > At quick glance I disagree with that conclusion: > > > > why should > > > > ^[OtherClass new] once > > > > behave differently from > > > > ^[self new] once > > > > ? > > > > > > R > > - > > > > _______________________________________________ > > vwnc mailing list > > [hidden email] <mailto:[hidden email]> > > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > > > > _______________________________________________ > vwnc mailing list > [hidden email] <mailto:[hidden email]> > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Ladislav Lenart
Hi Ladislav, Hi Travis,
  the bug here is surely that once should check that the receiver is a clean block, not a copying or full block.  It can do that by scanning the home method or some such, looking for itself as a literal, and if not found, raise an error.  This in fact tripped me up embarrassingly when I tried to port once to Squeak since my closure compiler doesn't yet create clean blocks and so once fails.
HTH Eliot
On Tue, Mar 20, 2012 at 8:06 AM, Ladislav Lenart <[hidden email]> wrote: Hello all. best, Eliot _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Correct, but given the second property of #once (to "properly"
flush the cached value), such a fix will not help much, I think. Ladislav Lenart On 20.3.2012 19:15, Eliot Miranda wrote: > Hi Ladislav, Hi Travis, > > the bug here is surely that once should check that the receiver is a clean block, not a copying or full block. It can do that by scanning the home method or some such, looking for itself as a > literal, and if not found, raise an error. This in fact tripped me up embarrassingly when I tried to port once to Squeak since my closure compiler doesn't yet create clean blocks and so once fails. > > HTH > Eliot > > On Tue, Mar 20, 2012 at 8:06 AM, Ladislav Lenart <[hidden email] <mailto:[hidden email]>> wrote: > > Hello all. > > I've just spent a nontrivial amount of time digging into > BlockClosure>>once magic because the following code > snippet did not work as (I) expected: > > SomeClass class>>someResource > ^[self createSomeResource] once. > > SomeClass class>>createSomeResource > ^Object new. > > > The method #someResource returns new Object each time > it is called. It has the following byte code: > > 1 <44> push self > 2 <FA 00 01> make copying block (1) "<-- this is the cause" > 5 <CC 01> no-check send once > 7 <65> return > > > as opposed to the direct (and working) form: > > SomeClass class>>someResource > ^[Object new] once. > > > which has the following byte code: > > 1 <1C> push BlockClosure [] in SomeClass class>>someResource > 2 <CC 01> no-check send once > 4 <65> return > > > In retrospect, I admit that my usage was wrong, but it > would be nice if it was documented somewhere (preferably > in BlockClosure>>once method comment) because it was not > that easy to spot :-) > > > Anyway, happy coding and thank you for reading thus far, > > Ladislav Lenart > > > _______________________________________________ > vwnc mailing list > [hidden email] <mailto:[hidden email]> > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > > > > -- > best, > Eliot > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
On Tue, Mar 20, 2012 at 11:31 AM, Ladislav Lenart <[hidden email]> wrote: Correct, but given the second property of #once (to "properly" I don't understand. Â Can you explain more. Â
best, Eliot _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Sorry.
The code inside the cached block should be self-contained in the sense that all needed to compute the value is present directly in the block. When the block defining method changes, the cached value will be flushed and recomputed when desired. At least that's the current usage pattern of #once. If you introduce an indirection in the block, the automatic flushing will stop working. HTH, Ladislav Lenart On 20.3.2012 19:44, Eliot Miranda wrote: > > > On Tue, Mar 20, 2012 at 11:31 AM, Ladislav Lenart <[hidden email] <mailto:[hidden email]>> wrote: > > Correct, but given the second property of #once (to "properly" > flush the cached value), such a fix will not help much, I think. > > > I don't understand. Can you explain more. > > > Ladislav Lenart > > > > On 20.3.2012 19:15, Eliot Miranda wrote: > > Hi Ladislav, Hi Travis, > > the bug here is surely that once should check that the receiver is a clean block, not a copying or full block. It can do that by scanning the home method or some such, looking for itself > as a > literal, and if not found, raise an error. This in fact tripped me up embarrassingly when I tried to port once to Squeak since my closure compiler doesn't yet create clean blocks and so once > fails. > > HTH > Eliot > > On Tue, Mar 20, 2012 at 8:06 AM, Ladislav Lenart <[hidden email] <mailto:[hidden email]> <mailto:[hidden email] <mailto:[hidden email]>>> wrote: > > Hello all. > > I've just spent a nontrivial amount of time digging into > BlockClosure>>once magic because the following code > snippet did not work as (I) expected: > > SomeClass class>>someResource > ^[self createSomeResource] once. > > SomeClass class>>createSomeResource > ^Object new. > > > The method #someResource returns new Object each time > it is called. It has the following byte code: > > 1 <44> push self > 2 <FA 00 01> make copying block (1) "<-- this is the cause" > 5 <CC 01> no-check send once > 7 <65> return > > > as opposed to the direct (and working) form: > > SomeClass class>>someResource > ^[Object new] once. > > > which has the following byte code: > > 1 <1C> push BlockClosure [] in SomeClass class>>someResource > 2 <CC 01> no-check send once > 4 <65> return > > > In retrospect, I admit that my usage was wrong, but it > would be nice if it was documented somewhere (preferably > in BlockClosure>>once method comment) because it was not > that easy to spot :-) > > > Anyway, happy coding and thank you for reading thus far, > > Ladislav Lenart > > > _________________________________________________ > vwnc mailing list > [hidden email] <mailto:[hidden email]> <mailto:[hidden email] <mailto:[hidden email]>> > > http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc <http://lists.cs.uiuc.edu/mailman/listinfo/vwnc> > > > > > -- > best, > Eliot > > > > > > > -- > best, > Eliot > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
On Tue, Mar 20, 2012 at 11:56 AM, Ladislav Lenart <[hidden email]> wrote: Sorry. But that's in agreement with what I wrote. Â The property of blocks you're looking for (self-contained ness) is being "clean", as opposed to being "copying" or "full". Â A "clean" block is compiled as a literal, and so persists for at least as long as its containing method exists, and the exact closure is reused every time that method is run.
So once again, the bug here is surely that once should check that the receiver is a clean block, not a copying or full block.  It can do that by scanning the home method or some such, looking for itself as a literal, and if not found, raise an error.  This in fact tripped me up embarrassingly when I tried to port once to Squeak since my closure compiler doesn't yet create clean blocks and so once fails.
Or do you still disagree? HTH Eliot
best, Eliot _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
So, given the limitation that #once should only work for clean blocks,
is #once worth the complication as opposed to using an explicit cache? On 3/20/2012 12:02 PM, Eliot Miranda wrote: > > > On Tue, Mar 20, 2012 at 11:56 AM, Ladislav Lenart <[hidden email] > <mailto:[hidden email]>> wrote: > > Sorry. > > The code inside the cached block should be self-contained > in the sense that all needed to compute the value is present > directly in the block. When the block defining method changes, > the cached value will be flushed and recomputed when desired. > At least that's the current usage pattern of #once. If you > introduce an indirection in the block, the automatic flushing > will stop working. > > > But that's in agreement with what I wrote. The property of blocks > you're looking for (self-contained ness) is being "clean", as opposed to > being "copying" or "full". A "clean" block is compiled as a literal, > and so persists for at least as long as its containing method exists, > and the exact closure is reused every time that method is run. > > So once again, the bug here is surely that once should check that the > receiver is a clean block, not a copying or full block. It can do that > by scanning the home method or some such, looking for itself as > a literal, and if not found, raise an error. This in fact tripped me up > embarrassingly when I tried to port once to Squeak since my closure > compiler doesn't yet create clean blocks and so once fails. > > Or do you still disagree? > > HTH > Eliot > > > HTH, > > Ladislav Lenart > > > On 20.3.2012 19:44, Eliot Miranda wrote: > > > > On Tue, Mar 20, 2012 at 11:31 AM, Ladislav Lenart > <[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>> wrote: > > Correct, but given the second property of #once (to "properly" > flush the cached value), such a fix will not help much, I think. > > > I don't understand. Can you explain more. > > > Ladislav Lenart > > > > On 20.3.2012 19:15, Eliot Miranda wrote: > > Hi Ladislav, Hi Travis, > > the bug here is surely that once should check that > the receiver is a clean block, not a copying or full block. It > can do that by scanning the home method or some such, looking > for itself > as a > literal, and if not found, raise an error. This in fact > tripped me up embarrassingly when I tried to port once to Squeak > since my closure compiler doesn't yet create clean blocks and so > once > fails. > > HTH > Eliot > > On Tue, Mar 20, 2012 at 8:06 AM, Ladislav Lenart > <[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>>> wrote: > > Hello all. > > I've just spent a nontrivial amount of time digging into > BlockClosure>>once magic because the following code > snippet did not work as (I) expected: > > SomeClass class>>someResource > ^[self createSomeResource] once. > > SomeClass class>>createSomeResource > ^Object new. > > > The method #someResource returns new Object each time > it is called. It has the following byte code: > > 1 <44> push self > 2 <FA 00 01> make copying block (1) "<-- this is the > cause" > 5 <CC 01> no-check send once > 7 <65> return > > > as opposed to the direct (and working) form: > > SomeClass class>>someResource > ^[Object new] once. > > > which has the following byte code: > > 1 <1C> push BlockClosure [] in SomeClass > class>>someResource > 2 <CC 01> no-check send once > 4 <65> return > > > In retrospect, I admit that my usage was wrong, but it > would be nice if it was documented somewhere (preferably > in BlockClosure>>once method comment) because it was not > that easy to spot :-) > > > Anyway, happy coding and thank you for reading thus far, > > Ladislav Lenart > > > ___________________________________________________ > vwnc mailing list > [hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>> > > http://lists.cs.uiuc.edu/____mailman/listinfo/vwnc > <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc> > <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc > <http://lists.cs.uiuc.edu/mailman/listinfo/vwnc>> > > > > > > -- > best, > Eliot > > > > > > > -- > best, > Eliot > > > > > > > -- > best, > Eliot > > > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
On Tue, Mar 20, 2012 at 12:10 PM, Andres Valloud <[hidden email]> wrote: So, given the limitation that #once should only work for clean blocks, IMO, absolutely. Â It is /so/ elegant. Â Yes, it depends on an implementation detail, but I'm kicking myself that my Squeak closure implementation doesn't support clean blocks (yet).
Â
best, Eliot _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Ok, so long as I don't have to maintain it :).
On 3/20/2012 12:31 PM, Eliot Miranda wrote: > > > On Tue, Mar 20, 2012 at 12:10 PM, Andres Valloud <[hidden email] > <mailto:[hidden email]>> wrote: > > So, given the limitation that #once should only work for clean blocks, > is #once worth the complication as opposed to using an explicit cache? > > > IMO, absolutely. It is /so/ elegant. Yes, it depends on an > implementation detail, but I'm kicking myself that my Squeak closure > implementation doesn't support clean blocks (yet). > > > On 3/20/2012 12:02 PM, Eliot Miranda wrote: > > > > > > On Tue, Mar 20, 2012 at 11:56 AM, Ladislav Lenart > <[hidden email] <mailto:[hidden email]> > > <mailto:[hidden email] <mailto:[hidden email]>>> wrote: > > > > Sorry. > > > > The code inside the cached block should be self-contained > > in the sense that all needed to compute the value is present > > directly in the block. When the block defining method changes, > > the cached value will be flushed and recomputed when desired. > > At least that's the current usage pattern of #once. If you > > introduce an indirection in the block, the automatic flushing > > will stop working. > > > > > > But that's in agreement with what I wrote. The property of blocks > > you're looking for (self-contained ness) is being "clean", as > opposed to > > being "copying" or "full". A "clean" block is compiled as a literal, > > and so persists for at least as long as its containing method exists, > > and the exact closure is reused every time that method is run. > > > > So once again, the bug here is surely that once should check that the > > receiver is a clean block, not a copying or full block. It can > do that > > by scanning the home method or some such, looking for itself as > > a literal, and if not found, raise an error. This in fact > tripped me up > > embarrassingly when I tried to port once to Squeak since my closure > > compiler doesn't yet create clean blocks and so once fails. > > > > Or do you still disagree? > > > > HTH > > Eliot > > > > > > HTH, > > > > Ladislav Lenart > > > > > > On 20.3.2012 19:44, Eliot Miranda wrote: > > > > > > > > On Tue, Mar 20, 2012 at 11:31 AM, Ladislav Lenart > > <[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>>> wrote: > > > > Correct, but given the second property of #once (to > "properly" > > flush the cached value), such a fix will not help > much, I think. > > > > > > I don't understand. Can you explain more. > > > > > > Ladislav Lenart > > > > > > > > On 20.3.2012 19:15, Eliot Miranda wrote: > > > > Hi Ladislav, Hi Travis, > > > > the bug here is surely that once should > check that > > the receiver is a clean block, not a copying or full > block. It > > can do that by scanning the home method or some such, looking > > for itself > > as a > > literal, and if not found, raise an error. This > in fact > > tripped me up embarrassingly when I tried to port once to > Squeak > > since my closure compiler doesn't yet create clean blocks > and so > > once > > fails. > > > > HTH > > Eliot > > > > On Tue, Mar 20, 2012 at 8:06 AM, Ladislav Lenart > > <[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>> > > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>>>> wrote: > > > > Hello all. > > > > I've just spent a nontrivial amount of time > digging into > > BlockClosure>>once magic because the > following code > > snippet did not work as (I) expected: > > > > SomeClass class>>someResource > > ^[self createSomeResource] once. > > > > SomeClass class>>createSomeResource > > ^Object new. > > > > > > The method #someResource returns new Object > each time > > it is called. It has the following byte code: > > > > 1 <44> push self > > 2 <FA 00 01> make copying block (1) "<-- this > is the > > cause" > > 5 <CC 01> no-check send once > > 7 <65> return > > > > > > as opposed to the direct (and working) form: > > > > SomeClass class>>someResource > > ^[Object new] once. > > > > > > which has the following byte code: > > > > 1 <1C> push BlockClosure [] in SomeClass > > class>>someResource > > 2 <CC 01> no-check send once > > 4 <65> return > > > > > > In retrospect, I admit that my usage was > wrong, but it > > would be nice if it was documented somewhere > (preferably > > in BlockClosure>>once method comment) because > it was not > > that easy to spot :-) > > > > > > Anyway, happy coding and thank you for > reading thus far, > > > > Ladislav Lenart > > > > > > > ___________________________________________________ > > vwnc mailing list > > [hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>> > > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>>> > > > > http://lists.cs.uiuc.edu/____mailman/listinfo/vwnc > > <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc> > > <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc > > <http://lists.cs.uiuc.edu/mailman/listinfo/vwnc>> > > > > > > > > > > > > -- > > best, > > Eliot > > > > > > > > > > > > > > -- > > best, > > Eliot > > > > > > > > > > > > > > -- > > best, > > Eliot > > > > > > > > _______________________________________________ > > vwnc mailing list > > [hidden email] <mailto:[hidden email]> > > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > _______________________________________________ > vwnc mailing list > [hidden email] <mailto:[hidden email]> > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > > > > -- > best, > Eliot > vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Eliot Miranda-2
Ah, you are right of course :-) I misred your post completely.
All I can say is that it was at the end of my work day ;-) Sorry again! Ladislav Lenart On 20.3.2012 20:02, Eliot Miranda wrote: > > > On Tue, Mar 20, 2012 at 11:56 AM, Ladislav Lenart <[hidden email] <mailto:[hidden email]>> wrote: > > Sorry. > > The code inside the cached block should be self-contained > in the sense that all needed to compute the value is present > directly in the block. When the block defining method changes, > the cached value will be flushed and recomputed when desired. > At least that's the current usage pattern of #once. If you > introduce an indirection in the block, the automatic flushing > will stop working. > > > But that's in agreement with what I wrote. The property of blocks you're looking for (self-contained ness) is being "clean", as opposed to being "copying" or "full". A "clean" block is compiled as a > literal, and so persists for at least as long as its containing method exists, and the exact closure is reused every time that method is run. > > So once again, the bug here is surely that once should check that the receiver is a clean block, not a copying or full block. It can do that by scanning the home method or some such, looking for > itself as a literal, and if not found, raise an error. This in fact tripped me up embarrassingly when I tried to port once to Squeak since my closure compiler doesn't yet create clean blocks and so > once fails. > > Or do you still disagree? > > HTH > Eliot > > > HTH, > > Ladislav Lenart > > > On 20.3.2012 19:44, Eliot Miranda wrote: > > > > On Tue, Mar 20, 2012 at 11:31 AM, Ladislav Lenart <[hidden email] <mailto:[hidden email]> <mailto:[hidden email] <mailto:[hidden email]>>> wrote: > > Correct, but given the second property of #once (to "properly" > flush the cached value), such a fix will not help much, I think. > > > I don't understand. Can you explain more. > > > Ladislav Lenart > > > > On 20.3.2012 19:15, Eliot Miranda wrote: > > Hi Ladislav, Hi Travis, > > the bug here is surely that once should check that the receiver is a clean block, not a copying or full block. It can do that by scanning the home method or some such, looking > for itself > as a > literal, and if not found, raise an error. This in fact tripped me up embarrassingly when I tried to port once to Squeak since my closure compiler doesn't yet create clean blocks and > so once > fails. > > HTH > Eliot > > On Tue, Mar 20, 2012 at 8:06 AM, Ladislav Lenart <[hidden email] <mailto:[hidden email]> <mailto:[hidden email] <mailto:[hidden email]>> <mailto:[hidden email] > <mailto:[hidden email]> <mailto:[hidden email] <mailto:[hidden email]>>>> wrote: > > Hello all. > > I've just spent a nontrivial amount of time digging into > BlockClosure>>once magic because the following code > snippet did not work as (I) expected: > > SomeClass class>>someResource > ^[self createSomeResource] once. > > SomeClass class>>createSomeResource > ^Object new. > > > The method #someResource returns new Object each time > it is called. It has the following byte code: > > 1 <44> push self > 2 <FA 00 01> make copying block (1) "<-- this is the cause" > 5 <CC 01> no-check send once > 7 <65> return > > > as opposed to the direct (and working) form: > > SomeClass class>>someResource > ^[Object new] once. > > > which has the following byte code: > > 1 <1C> push BlockClosure [] in SomeClass class>>someResource > 2 <CC 01> no-check send once > 4 <65> return > > > In retrospect, I admit that my usage was wrong, but it > would be nice if it was documented somewhere (preferably > in BlockClosure>>once method comment) because it was not > that easy to spot :-) > > > Anyway, happy coding and thank you for reading thus far, > > Ladislav Lenart > > > ___________________________________________________ > vwnc mailing list > [hidden email] <mailto:[hidden email]> <mailto:[hidden email] <mailto:[hidden email]>> <mailto:[hidden email] <mailto:[hidden email]> <mailto:[hidden email] > <mailto:[hidden email]>>> > > http://lists.cs.uiuc.edu/____mailman/listinfo/vwnc <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc> <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc > <http://lists.cs.uiuc.edu/mailman/listinfo/vwnc>> > > > > > > -- > best, > Eliot > > > > > > > -- > best, > Eliot > > > > > > > -- > best, > Eliot > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Eliot Miranda-2
In VW it can be probably be simply fixed by testing for #isClean on the BlockClosure. The implementation could become something like this: once "cache myself and resend" self isClean ifFalse: [self error: ‘Only works with clean blocks’]. self becomeCached. ^self once but #isClean is currently part of “Debugger-support” so that one may have to move to “Kernel-Methods” or something like that. From: [hidden email] [mailto:[hidden email]]
On Behalf Of Eliot Miranda On Tue, Mar 20, 2012 at 12:10 PM, Andres Valloud <[hidden email]> wrote: So, given the limitation that #once should only work for clean blocks, IMO, absolutely. It is /so/ elegant. Yes, it depends on an implementation detail, but I'm kicking myself that my Squeak closure implementation doesn't support clean blocks (yet).
-- Eliot _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Andres Valloud-6
Wow! what an exquisite example of bright chaps blinding each other. Chatter about cleanness of blocks, 'self contained code' (an impossible concept until primitives can be put in blocks), and a framework (Assets) that already can generate code for you. Here goes: #once works just fine! When its source changes its cache will be flushed. Adding anything else to #once would yield unexpected behavior. So probably Assets is using it in a way that does not mesh well with everyones work flow, *that* however is something not to fix in #once but in Assets. :-) On 3/20/2012 8:10 PM, Andres Valloud wrote: > So, given the limitation that #once should only work for clean blocks, > is #once worth the complication as opposed to using an explicit cache? > > On 3/20/2012 12:02 PM, Eliot Miranda wrote: >> >> On Tue, Mar 20, 2012 at 11:56 AM, Ladislav Lenart<[hidden email] >> <mailto:[hidden email]>> wrote: >> >> Sorry. >> >> The code inside the cached block should be self-contained >> in the sense that all needed to compute the value is present >> directly in the block. When the block defining method changes, >> the cached value will be flushed and recomputed when desired. >> At least that's the current usage pattern of #once. If you >> introduce an indirection in the block, the automatic flushing >> will stop working. >> >> >> But that's in agreement with what I wrote. The property of blocks >> you're looking for (self-contained ness) is being "clean", as opposed to >> being "copying" or "full". A "clean" block is compiled as a literal, >> and so persists for at least as long as its containing method exists, >> and the exact closure is reused every time that method is run. >> >> So once again, the bug here is surely that once should check that the >> receiver is a clean block, not a copying or full block. It can do that >> by scanning the home method or some such, looking for itself as >> a literal, and if not found, raise an error. This in fact tripped me up >> embarrassingly when I tried to port once to Squeak since my closure >> compiler doesn't yet create clean blocks and so once fails. >> >> Or do you still disagree? >> >> HTH >> Eliot >> >> >> HTH, >> >> Ladislav Lenart >> >> >> On 20.3.2012 19:44, Eliot Miranda wrote: >> >> >> >> On Tue, Mar 20, 2012 at 11:31 AM, Ladislav Lenart >> <[hidden email]<mailto:[hidden email]> >> <mailto:[hidden email]<mailto:[hidden email]>>> wrote: >> >> Correct, but given the second property of #once (to "properly" >> flush the cached value), such a fix will not help much, I think. >> >> >> I don't understand. Can you explain more. >> >> >> Ladislav Lenart >> >> >> >> On 20.3.2012 19:15, Eliot Miranda wrote: >> >> Hi Ladislav, Hi Travis, >> >> the bug here is surely that once should check that >> the receiver is a clean block, not a copying or full block. It >> can do that by scanning the home method or some such, looking >> for itself >> as a >> literal, and if not found, raise an error. This in fact >> tripped me up embarrassingly when I tried to port once to Squeak >> since my closure compiler doesn't yet create clean blocks and so >> once >> fails. >> >> HTH >> Eliot >> >> On Tue, Mar 20, 2012 at 8:06 AM, Ladislav Lenart >> <[hidden email]<mailto:[hidden email]> >> <mailto:[hidden email]<mailto:[hidden email]>> >> <mailto:[hidden email]<mailto:[hidden email]> >> <mailto:[hidden email]<mailto:[hidden email]>>>> wrote: >> >> Hello all. >> >> I've just spent a nontrivial amount of time digging into >> BlockClosure>>once magic because the following code >> snippet did not work as (I) expected: >> >> SomeClass class>>someResource >> ^[self createSomeResource] once. >> >> SomeClass class>>createSomeResource >> ^Object new. >> >> >> The method #someResource returns new Object each time >> it is called. It has the following byte code: >> >> 1<44> push self >> 2<FA 00 01> make copying block (1) "<-- this is the >> cause" >> 5<CC 01> no-check send once >> 7<65> return >> >> >> as opposed to the direct (and working) form: >> >> SomeClass class>>someResource >> ^[Object new] once. >> >> >> which has the following byte code: >> >> 1<1C> push BlockClosure [] in SomeClass >> class>>someResource >> 2<CC 01> no-check send once >> 4<65> return >> >> >> In retrospect, I admit that my usage was wrong, but it >> would be nice if it was documented somewhere (preferably >> in BlockClosure>>once method comment) because it was not >> that easy to spot :-) >> >> >> Anyway, happy coding and thank you for reading thus far, >> >> Ladislav Lenart >> >> >> ___________________________________________________ >> vwnc mailing list >> [hidden email]<mailto:[hidden email]> >> <mailto:[hidden email]<mailto:[hidden email]>> >> <mailto:[hidden email]<mailto:[hidden email]> >> <mailto:[hidden email]<mailto:[hidden email]>>> >> >> http://lists.cs.uiuc.edu/____mailman/listinfo/vwnc >> <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc> >> <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc >> <http://lists.cs.uiuc.edu/mailman/listinfo/vwnc>> >> >> >> >> >> >> -- >> best, >> Eliot >> >> >> >> >> >> >> -- >> best, >> Eliot >> >> >> >> >> >> >> -- >> best, >> Eliot >> >> >> >> _______________________________________________ >> vwnc mailing list >> [hidden email] >> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
If I've understood correctly, the bright chaps are enlightening us.
#once fails to cache its value, unless the block is clean. That's surprising and undocumented, and no such restriction is found in similar classes like BlockValue. Assets is using #once correctly, but hand-written uses of #once quite quickly reveal that it doesn't actually do a great job of offering caching with little thought and effort. Object class>>onceClean "self onceClean == self onceClean" "true" ^[Object new] once Object class>>onceUnclean "self onceUnclean == self onceUnclean" "false" ^[self new] once Steve > -----Original Message----- > From: [hidden email] [mailto:[hidden email]] On > Behalf Of Reinout Heeck > Sent: 21. maaliskuuta 2012 12:25 > To: [hidden email] > Subject: Re: [vwnc] [vw7.7] Perhaps unknown limitation of > BlockClosure>>once (in Assets) > > > Wow! what an exquisite example of bright chaps blinding each other. > > Chatter about cleanness of blocks, 'self contained code' (an > concept until primitives can be put in blocks), and a framework > (Assets) > that already can generate code for you. > > > > Here goes: > > #once works just fine! > > When its source changes its cache will be flushed. > Adding anything else to #once would yield unexpected behavior. > > > So probably Assets is using it in a way that does not mesh well with > everyones work flow, *that* however is something not to fix in #once > but > in Assets. > > > > :-) > > > > > > > > > On 3/20/2012 8:10 PM, Andres Valloud wrote: > > So, given the limitation that #once should only work for clean > > is #once worth the complication as opposed to using an explicit > cache? > > > > On 3/20/2012 12:02 PM, Eliot Miranda wrote: > >> > >> On Tue, Mar 20, 2012 at 11:56 AM, Ladislav Lenart<[hidden email] > >> <mailto:[hidden email]>> wrote: > >> > >> Sorry. > >> > >> The code inside the cached block should be self-contained > >> in the sense that all needed to compute the value is present > >> directly in the block. When the block defining method changes, > >> the cached value will be flushed and recomputed when desired. > >> At least that's the current usage pattern of #once. If you > >> introduce an indirection in the block, the automatic flushing > >> will stop working. > >> > >> > >> But that's in agreement with what I wrote. The property of blocks > >> you're looking for (self-contained ness) is being "clean", as > opposed to > >> being "copying" or "full". A "clean" block is compiled as a > >> and so persists for at least as long as its containing method exists, > >> and the exact closure is reused every time that method is run. > >> > >> So once again, the bug here is surely that once should check that > the > >> receiver is a clean block, not a copying or full block. It can do > that > >> by scanning the home method or some such, looking for itself as > >> a literal, and if not found, raise an error. This in fact tripped > me up > >> embarrassingly when I tried to port once to Squeak since my closure > >> compiler doesn't yet create clean blocks and so once fails. > >> > >> Or do you still disagree? > >> > >> HTH > >> Eliot > >> > >> > >> HTH, > >> > >> Ladislav Lenart > >> > >> > >> On 20.3.2012 19:44, Eliot Miranda wrote: > >> > >> > >> > >> On Tue, Mar 20, 2012 at 11:31 AM, Ladislav Lenart > >> <[hidden email]<mailto:[hidden email]> > >> <mailto:[hidden email]<mailto:[hidden email]>>> > wrote: > >> > >> Correct, but given the second property of #once (to > "properly" > >> flush the cached value), such a fix will not help > I think. > >> > >> > >> I don't understand. Can you explain more. > >> > >> > >> Ladislav Lenart > >> > >> > >> > >> On 20.3.2012 19:15, Eliot Miranda wrote: > >> > >> Hi Ladislav, Hi Travis, > >> > >> the bug here is surely that once should check > that > >> the receiver is a clean block, not a copying or full > It > >> can do that by scanning the home method or some such, > looking > >> for itself > >> as a > >> literal, and if not found, raise an error. This in > fact > >> tripped me up embarrassingly when I tried to port once to > Squeak > >> since my closure compiler doesn't yet create clean blocks > and so > >> once > >> fails. > >> > >> HTH > >> Eliot > >> > >> On Tue, Mar 20, 2012 at 8:06 AM, Ladislav Lenart > >> <[hidden email]<mailto:[hidden email]> > >> <mailto:[hidden email]<mailto:[hidden email]>> > >> <mailto:[hidden email]<mailto:[hidden email]> > >> <mailto:[hidden email]<mailto:[hidden email]>>>> > wrote: > >> > >> Hello all. > >> > >> I've just spent a nontrivial amount of time > digging into > >> BlockClosure>>once magic because the following > code > >> snippet did not work as (I) expected: > >> > >> SomeClass class>>someResource > >> ^[self createSomeResource] once. > >> > >> SomeClass class>>createSomeResource > >> ^Object new. > >> > >> > >> The method #someResource returns new Object > each time > >> it is called. It has the following byte code: > >> > >> 1<44> push self > >> 2<FA 00 01> make copying block (1) "<-- this > is the > >> cause" > >> 5<CC 01> no-check send once > >> 7<65> return > >> > >> > >> as opposed to the direct (and working) form: > >> > >> SomeClass class>>someResource > >> ^[Object new] once. > >> > >> > >> which has the following byte code: > >> > >> 1<1C> push BlockClosure [] in SomeClass > >> class>>someResource > >> 2<CC 01> no-check send once > >> 4<65> return > >> > >> > >> In retrospect, I admit that my usage was > but it > >> would be nice if it was documented somewhere > (preferably > >> in BlockClosure>>once method comment) because > it was not > >> that easy to spot :-) > >> > >> > >> Anyway, happy coding and thank you for reading > thus far, > >> > >> Ladislav Lenart > >> > >> > >> > ___________________________________________________ > >> vwnc mailing list > >> [hidden email]<mailto:[hidden email]> > >> <mailto:[hidden email]<mailto:[hidden email]>> > >> <mailto:[hidden email]<mailto:[hidden email]> > >> <mailto:[hidden email]<mailto:[hidden email]>>> > >> > >> http://lists.cs.uiuc.edu/____mailman/listinfo/vwnc > >> <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc> > >> <http://lists.cs.uiuc.edu/__mailman/listinfo/vwnc > >> <http://lists.cs.uiuc.edu/mailman/listinfo/vwnc>> > >> > >> > >> > >> > >> > >> -- > >> best, > >> Eliot > >> > >> > >> > >> > >> > >> > >> -- > >> best, > >> Eliot > >> > >> > >> > >> > >> > >> > >> -- > >> best, > >> Eliot > >> > >> > >> > >> _______________________________________________ > >> vwnc mailing list > >> [hidden email] > >> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > _______________________________________________ > > vwnc mailing list > > [hidden email] > > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Dave Stevenson-3
As I see it there are other issues with this feature. First, as Dave noted, there are other conditions that may require the cache to be flushed and they are not or possibly cannot be detected automatically. Furthermore, there is no way for some other event to flush the cache. Because the cache flush is tied to the method compilation I would suggest that this is really another way of providing compile-time literal object construction without the required syntactical constructs. Because of the implicit constraints imposed on the use of #once, I would also suggest that it be HEAVILY commented, including its constraints. This leads to another point, compile-time literal construction. This could easily be accommodated by using a method pragma that dictates the method be evaluated at compile time and its result be cached. There would be less confusion that the feature is intended to be used only at compile time rather than run-time. Terry =========================================================== Terry Raymond Crafted Smalltalk 80 Lazywood Ln. Tiverton, RI 02878 (401) 624-4517 [hidden email] =========================================================== From: [hidden email] [mailto:[hidden email]] On Behalf Of Dave Stevenson It doesn't sound feasible to me. For example, suppose a method sent in the once block did not change, but its class was reparented? Or if that method sent #at:, or some other common messages, would you really tag hundreds or thousands of methods so you could clear the once block's cache if any of them changed? Dave Stevenson From: Ladislav Lenart <[hidden email]> _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Steven Kelly
On 3/21/2012 1:32 PM, Steven Kelly wrote:
> If I've understood correctly, the bright chaps are enlightening us. I stand corrected: I completely missed the failure of #oneUnclean below, instead I thought the conversation was about changes in methods called by the block not being picked up by #once :-/ Thank you Steve. > > Object class>>onceClean > "self onceClean == self onceClean" "true" > ^[Object new] once > > Object class>>onceUnclean > "self onceUnclean == self onceUnclean" "false" > ^[self new] once Stepping through the failing code reveals that the implementation is caching at the level of the closure (a BlockClosure), not at the level of the block (a CompiledBlock, the #method of the closure). It seems that both the closure and the block need to change class, and that the closure needs to delegate the actual caching to the block. If the byte code compiler did not do optimizations on clean blocks (storing a closure instead of a block) the whole implementaion of #once would naturally be just on CompiledBlock, not on both.... I tried to code a fix, but keep running into endless recursions (because the tools depend on #once?). _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Trying to atone for that foot in my mouth, I concocted a sketch for
fixing #once. Please find attached a workspace snippet that will alter the system without immediately crashing it. When evaluating the script it will complain about undeclared names, simply hit 'leave undeclared'. This implementation delegates the caching and becoming to the CompiledBlock instances instead of the BlockClosure instances that the original used. It should now work for both clean and copying blocks. The simple test Steven Kelly supplied below should now yield true in both cases. This code has hardly been tested, its just a sketch and needs some cleanup (and it is developed on 771 FTW). In both the original and new versions I miss the flushing of the VM (JIT) caches, could someone here with knowledge about the JIT review this apparent omission? > On 3/21/2012 1:32 PM, Steven Kelly wrote: >> Object class>>onceClean >> "self onceClean == self onceClean" "true" >> ^[Object new] once >> >> Object class>>onceUnclean >> "self onceUnclean == self onceUnclean" "false" >> ^[self new] once Enjoy, Reinout _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc FixOnce.ws (3K) Download Attachment |
Free forum by Nabble | Edit this page |