Imagine we have some method
MyClass>>#method: arg
Transcript crShow: 'executed'
So when you do MyClass new method: 1
the transcript is filled with "executed" lines.
Now I want to skip this method if arg
is 0. I've tried to install an instead metalink with a condition:
link := MetaLink new
condition: [ :arguments |
arguments first = 0 ]
arguments: #(arguments);
control: #instead.
(MyClass >> #method:) ast link: link
But then the method does not run anymore and I want to run it if the arg is not 0.
I've also tried to do the condition in the metaobject in this way:
link := MetaLink new
metaObject: [ :ast :arguments :receiver |
arguments first = 0
ifFalse: [
ast compiledMethod
valueWithReceiver: receiver
arguments: arguments ] ];
selector: #value:value:value:;
arguments: #(node arguments receiver);
control: #instead.
(MyClass >> #method:) ast link: link
But in this case you end up in a infinite recursion, as the metalink is called over and over again although I thought that ast compiledMethod
should return a compiled method and not the reflective counterpart
yes, it looks like "instead hooks" are always executed "instead" of the original method, even if the link condition does not hold, the difference is just whether we return the value of the instead link evaluation or just nil.
Maybe this should be changed for instead links.
As solution for your usecase, you can use a before link that just returns the receiver if the condition holds:
| ml |
ml := MetaLink new.
ml control: #before.
ml condition:[:args | args first = 0] arguments:#(arguments).
ml selector:#value:.
ml metaObject:[:context | context return].
ml arguments:{#context}.
(MyObject>>#method:) ast link:ml.
the #context is the key for the thisContext refication (RFThisContextReification)