Hi
I would to currify some blocks that I want to use as methods in a simple object model. The currification will allows to capture the class in which the block/ methods is defined in the same way literals hold this information for compiled methods, and my programmer will not see it. Now I'm stuck. When I evaluate in a workspace ([:each | [ :objself | | class | class := each. class = 2 ifTrue: [ ^ 'zak']. ^ 'zork']] value: 3) value: 4 "in my small oo model class will play the role of the class literal and I plan to use it to perform super sends" I get what is expected 'zak' Now I want to have a kind of macro system that given a string generate blocks that will act as method bodies for my oo model. methodFrom: aString myClass: aClass "(self new methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. ^ ''zork''' myClass: 2) value: 4" | block string resBlock | string := '[ :each | [ :objself | | class | class := each. ', aString ,']]'. block := Compiler new evaluate: string in: nil receiver: nil notifying: nil ifFail: [nil]. resBlock := block value: aClass. ^ resBlock When I execute self new methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. ^ ''zork''' myClass: 2) value: 4 I get a context cannot return. I understand approximately that since I create my blocks on the fly they do not have a homeContext. Now I would like to know how I can get the behavior of the block that I manually typed for the generated ones. Any nice suggestion? Should I create and how a BlockContext and pass it as the in: parameter Stef |
Le Jeudi 23 Février 2006 21:04, stéphane ducasse a écrit :
> Hi > > I would to currify some blocks that I want to use as methods in a > simple object model. > The currification will allows to capture the class in which the block/ > methods is defined in the same way literals hold > this information for compiled methods, and my programmer will not see > it. > > Now I'm stuck. > > When I evaluate in a workspace > ([:each | > [ :objself | > > | class | > > class := each. > class = 2 ifTrue: [ ^ 'zak']. > ^ 'zork']] value: 3) > value: 4 > > "in my small oo model class will play the role of the class literal > and I plan to use it to perform super sends" > I get what is expected > 'zak' > > > Now I want to have a kind of macro system that given a string > generate blocks > that will act as method bodies for my oo model. > > methodFrom: aString myClass: aClass > "(self new > methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. > ^ ''zork''' > myClass: 2) value: 4" > > | block string resBlock | > > string := '[ :each | > [ :objself | > > | class | > > class := each. ', aString ,']]'. > block := Compiler new > evaluate: string > in: nil > receiver: nil > notifying: nil > ifFail: [nil]. > resBlock := block value: aClass. > ^ resBlock > > > When I execute > > self new > methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. > ^ ''zork''' > myClass: 2) value: 4 > > I get a context cannot return. > I understand approximately that since I create my blocks on the fly > they do not have a homeContext. More exactly, your block had a homeContext until #methodFrom:myClass: did return. Once returned from, the context is no more active, and aClass has been removed from the execution stack. The inside block created still want to access aClass as first argument on the stack... And the copy into inside block temporary does not fix it. Block still keep the link to the stack... > Now I would like to know how I can get the behavior of the block that > I manually typed > for the generated ones. > Any nice suggestion? Should I create and how a BlockContext and pass > it as the in: parameter > > > Stef I suggest you use a dedicated class that will have both a pointer to the class and a pointer to the block method as inst vars. Object subclass: ValuableThing instanceVariables: 'targetClass blockMethod'. This thing will simply implement value: aClass ^(block value: targetClass) value: aClass Did not browse the system, but such things might already exist in one of ValueModel subclasses. Then your #methodFrom:myClass: will compile the outside block and create an instance of ValuableThing that will be value:-able. methodFrom: aString myClass: aClass "(self new methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. ^ ''zork''' myClass: 2) value: 4" | block string resThing | string := '[ :each | [ :objself | | class | class := each. ', aString ,']]'. block := Compiler new evaluate: string in: nil receiver: nil notifying: nil ifFail: [nil]. resThing := ValuableThing new targetClass: aClass blockMethod: block. ^ resThing When you will evaluate resThing, the block context should be OK. Nicolas ------------------------------------------------------- |
In reply to this post by stéphane ducasse-2
Hi
In fact I started with this kind of idea but (I haven't currified the block so I could not access the class as I wanted). Thanks for the suggestion. But I would really like to know why my expression in my workspace worked while the expression generated on the fly did not. Any idea? > Object subclass: ObjMethod > instanceVariables: 'definingClass blockMethod'. > > This thing will simply implement > value: aClass > ^(block value: definingClass) value: aClass > > Did not browse the system, but such things might already exist in > one of > ValueModel subclasses. > > Then your #methodFrom:myClass: will compile the outside block and > create an > instance of ValuableThing that will be value:-able. > > methodFrom: aString myClass: aClass > "(self new > methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. > ^ ''zork''' > myClass: 2) value: 4" > > | block string resThing | > > string := '[ :each | > [ :objself | > | class | > class := each. ', aString ,']]'. > block := Compiler evaluate: string. > resThing := ValuableThing new targetClass: aClass blockMethod: > block. > ^ resThing > > When you will evaluate resThing, the block context should be OK. Does not work.... Sniff. Stef |
Le Jeudi 23 Février 2006 22:29, stéphane ducasse a écrit :
> Hi > > In fact I started with this kind of idea but (I haven't currified the > block so I could not access the class as I wanted). > Thanks for the suggestion. But I would really like to know why my > expression in my workspace worked while the > expression generated on the fly did not. > Any idea? The inside block refer to its homeContext, that is the Context of method in which it is compiled. When you have a DoIt, the insideBlock is evaluated while the homeContext (the DoIt) is still active. This is why it works. > > > > > When you will evaluate resThing, the block context should be OK. > > Does not work.... > Sniff. > > Stef Sorry, i had not any VW image opened when i answered, should have checked... As i stated above, the homeContext of the insideBlock in my solution is also a DoIt (Compiler evaluate: etc...). This is why my solution were also bad. The homeContext is not valid once #evaluate: will return. If you compile your block on the fly with Compiler evaluate: ..., it's home context is always dead when you evaluate the block. You must arrange to have the inside block not refer to its homeContext. So where is this reference to the homeContext ? Because the example you use has a return sign ^. That means that the homeContext should return... Still your block refer to its homeContext and won't work... (self new methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. ^ ''zork''' myClass: 2) value: 4 If you try this one: (self new methodFrom: 'class = 2 ifTrue: [ ''zak''] ifFalse: [ ''zork''' ] myClass: 2) value: 4 It should work (Sorry, I still did not open the image). Maybe your first implementation will work too. But maybe you need these return signs... in which case, i have no easy solution with blocks. |
Yes I need these returns else I cannot represent control flow
escaping in my model. >> In fact I started with this kind of idea but (I haven't currified the >> block so I could not access the class as I wanted). >> Thanks for the suggestion. But I would really like to know why my >> expression in my workspace worked while the >> expression generated on the fly did not. >> Any idea? > > The inside block refer to its homeContext, that is the Context of > method in > which it is compiled. > When you have a DoIt, the insideBlock is evaluated while the > homeContext (the > DoIt) is still active. This is why it works. > >> >>> >>> When you will evaluate resThing, the block context should be OK. >> >> Does not work.... >> Sniff. >> >> Stef > > Sorry, i had not any VW image opened when i answered, should have > checked... > As i stated above, the homeContext of the insideBlock in my > solution is also a > DoIt (Compiler evaluate: etc...). This is why my solution were also > bad. The > homeContext is not valid once #evaluate: will return. > > If you compile your block on the fly with Compiler evaluate: ..., > it's home > context is always dead when you evaluate the block. > You must arrange to have the inside block not refer to its > homeContext. > > So where is this reference to the homeContext ? > Because the example you use has a return sign ^. That means that the > homeContext should return... > Still your block refer to its homeContext and won't work... > > (self new > methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. > ^ ''zork''' > myClass: 2) value: 4 > > If you try this one: > > (self new > methodFrom: 'class = 2 > ifTrue: [ ''zak''] > ifFalse: [ ''zork''' ] > myClass: 2) value: 4 > > It should work (Sorry, I still did not open the image). > Maybe your first implementation will work too. > But maybe you need these return signs... in which case, i have no easy > solution with blocks. > > > |
In fact thinking about it I'm not sure that these returns have sense
in my model. This is interesting to see how an implementation can make you thinking. > Yes I need these returns else I cannot represent control flow > escaping in my model. > >>> In fact I started with this kind of idea but (I haven't currified >>> the >>> block so I could not access the class as I wanted). >>> Thanks for the suggestion. But I would really like to know why my >>> expression in my workspace worked while the >>> expression generated on the fly did not. >>> Any idea? >> >> The inside block refer to its homeContext, that is the Context of >> method in >> which it is compiled. >> When you have a DoIt, the insideBlock is evaluated while the >> homeContext (the >> DoIt) is still active. This is why it works. >> >>> >>>> >>>> When you will evaluate resThing, the block context should be OK. >>> >>> Does not work.... >>> Sniff. >>> >>> Stef >> >> Sorry, i had not any VW image opened when i answered, should have >> checked... >> As i stated above, the homeContext of the insideBlock in my >> solution is also a >> DoIt (Compiler evaluate: etc...). This is why my solution were >> also bad. The >> homeContext is not valid once #evaluate: will return. >> >> If you compile your block on the fly with Compiler evaluate: ..., >> it's home >> context is always dead when you evaluate the block. >> You must arrange to have the inside block not refer to its >> homeContext. >> >> So where is this reference to the homeContext ? >> Because the example you use has a return sign ^. That means that the >> homeContext should return... >> Still your block refer to its homeContext and won't work... >> >> (self new >> methodFrom: 'class = 2 ifTrue: [ ^ ''zak'']. >> ^ ''zork''' >> myClass: 2) value: 4 >> >> If you try this one: >> >> (self new >> methodFrom: 'class = 2 >> ifTrue: [ ''zak''] >> ifFalse: [ ''zork''' ] >> myClass: 2) value: 4 >> >> It should work (Sorry, I still did not open the image). >> Maybe your first implementation will work too. >> But maybe you need these return signs... in which case, i have no >> easy >> solution with blocks. >> >> >> > |
Free forum by Nabble | Edit this page |