MetaLink to conditionally skip a method execution based on an arg

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

MetaLink to conditionally skip a method execution based on an arg

Uko2
Hi.

Imagine I have method a: and I want to skip the execution (return self or nil or whatever) when a: is evaluated with parameter 0. I have tried to add a meta link which will run instead of the method with a condition, but the condition did not work… I have tried to implement the metallic method to do nothing if the arg is 0 otherwise to perform the method, but I end up with an infinite loop…

Did anybody do something like that already? Any suggestions?

Uko
Reply | Threaded
Open this post in threaded view
|

Re: MetaLink to conditionally skip a method execution based on an arg

Uko2

On 22 Oct 2016, at 23:13, Yuriy Tymchuk <[hidden email]> wrote:

Hi.

Imagine I have method a: and I want to skip the execution (return self or nil or whatever) when a: is evaluated with parameter 0. I have tried to add a meta link which will run instead of the method with a condition, but the condition did not work… I have tried to implement the metallic method to do nothing if the arg is 0 otherwise to perform the method, but I end up with an infinite loop…

Did anybody do something like that already? Any suggestions?

Uko

Reply | Threaded
Open this post in threaded view
|

Re: MetaLink to conditionally skip a method execution based on an arg

Peter Uhnak
I was looking at this and ran into some very odd behavior:

imagine we have some method:

```
Object subclass: #MyClass.
MyClass compile: 'method: arg
    Transcript crShow: ''executed '', arg asString'.
```

and a simple metalink

```
link := MetaLink new
metaObject: Halt;
selector: #now;
control: #instead.

(MyClass >> #method:) ast link: link.
```

Now I can do the following to execute the code:

```
c := MyClass new.
(MyClass>>#method:) valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) reflectiveMethod valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) compiledMethod valueWithReceiver: c arguments: #(1).
MyClass rFwithArgs: #(1) executeMethod: (MyClass>>#method:) compiledMethod.
```

All of the statements above will call the method WITHOUT triggering the metalink, which is odd.

Now what's even stranger, if I instead do this

```
c := MyClass new.
c method: 1.
(MyClass>>#method:) valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) reflectiveMethod valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) compiledMethod valueWithReceiver: c arguments: #(1).
MyClass rFwithArgs: #(1) executeMethod: (MyClass>>#method:) compiledMethod.
```

Then ALL the statements (starting with `c method: 1`) will be suddenly halting (triggering the metalinks).


So my questions are:

1) why in the first case the following two methods didn't trigger the metalink?

(MyClass>>#method:) valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) reflectiveMethod valueWithReceiver: c arguments: #(1).

2) why in the second case these two methods did trigger the metalink?

(MyClass>>#method:) compiledMethod valueWithReceiver: c arguments: #(1).
MyClass rFwithArgs: #(1) executeMethod: (MyClass>>#method:) compiledMethod.

#rFwithArgs:executeMethod: even has comment "This method is used by reflectivity internally. All meta-links are ignored".

3) why the class of (MyClass>>#method:) changed after calling `method:`?

```
(MyClass >> #method:) ast link: link.

c := MyClass new.
(MyClass>>#method:) class. "ReflectiveMethod"
(MyClass>>#method:) valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) class. "ReflectiveMethod"
c method: 1.
(MyClass>>#method:) class. "CompiledMethod"
```

4) (unrelated to the above) I tried calling `link disable` from within the #metaObject, but it was ignored, but maybe I don't understand its purpose.


Thanks,
Peter

On Sun, Oct 23, 2016 at 09:21:59AM +0200, Yuriy Tymchuk wrote:

> I’ve also described the question with examples on SO: https://stackoverflow.com/questions/40200546/conditionally-skip-a-method-with-matalinks
>
> > On 22 Oct 2016, at 23:13, Yuriy Tymchuk <[hidden email]> wrote:
> >
> > Hi.
> >
> > Imagine I have method a: and I want to skip the execution (return self or nil or whatever) when a: is evaluated with parameter 0. I have tried to add a meta link which will run instead of the method with a condition, but the condition did not work… I have tried to implement the metallic method to do nothing if the arg is 0 otherwise to perform the method, but I end up with an infinite loop…
> >
> > Did anybody do something like that already? Any suggestions?
> >
> > Uko
>

Reply | Threaded
Open this post in threaded view
|

Re: MetaLink to conditionally skip a method execution based on an arg

wernerk
In reply to this post by Uko2
Hi,
i would be also interested in answer to this interesting MetaLink-question.
werner

p.s. Yuriy, i guess this could also be done with ghost

On 10/23/2016 09:21 AM, Yuriy Tymchuk wrote:

On 22 Oct 2016, at 23:13, Yuriy Tymchuk <[hidden email]> wrote:

Hi.

Imagine I have method a: and I want to skip the execution (return self or nil or whatever) when a: is evaluated with parameter 0. I have tried to add a meta link which will run instead of the method with a condition, but the condition did not work… I have tried to implement the metallic method to do nothing if the arg is 0 otherwise to perform the method, but I end up with an infinite loop…

Did anybody do something like that already? Any suggestions?

Uko


Reply | Threaded
Open this post in threaded view
|

Re: MetaLink to conditionally skip a method execution based on an arg

Nicolai Hess-3-2
In reply to this post by Peter Uhnak


2016-10-23 12:15 GMT+02:00 Peter Uhnak <[hidden email]>:
I was looking at this and ran into some very odd behavior:

imagine we have some method:

```
Object subclass: #MyClass.
MyClass compile: 'method: arg
    Transcript crShow: ''executed '', arg asString'.
```

and a simple metalink

```
link := MetaLink new
metaObject: Halt;
selector: #now;
control: #instead.

(MyClass >> #method:) ast link: link.
```

Now I can do the following to execute the code:

```
c := MyClass new.
(MyClass>>#method:) valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) reflectiveMethod valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) compiledMethod valueWithReceiver: c arguments: #(1).
MyClass rFwithArgs: #(1) executeMethod: (MyClass>>#method:) compiledMethod.
```


There is only one way to "compile and install" the modified method and unless this is done, all the above messages are
received on the ReflectiveMethod and delegated to the CompiledMethod (see ReflectiveMethod>>##doesNotUnderstand:

 
All of the statements above will call the method WITHOUT triggering the metalink, which is odd.

Now what's even stranger, if I instead do this

```
c := MyClass new.
c method: 1.
(MyClass>>#method:) valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) reflectiveMethod valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) compiledMethod valueWithReceiver: c arguments: #(1).
MyClass rFwithArgs: #(1) executeMethod: (MyClass>>#method:) compiledMethod.
```


by the first call "c method:1" this is the place where the ReflectiveMethod actually compiles and installs a modified compiled method.

the magic happens with "objects as methods" and the method run:with:in:
(if the vm looks up a message send, and the object in the method dictionary is *not* a CompiledMethod, it calls the object with the method
run: aSelector with: anArray in: aReceiver

This is implemented in ReflectiveMethod and will actually compile and install the new CompiledMethod.
 
Then ALL the statements (starting with `c method: 1`) will be suddenly halting (triggering the metalinks).

Yes because the compiled method to be called is now the new one.

(MyClass>>#method:) class -> " this is now a compiled method again, but the new, modified one".

 


So my questions are:

1) why in the first case the following two methods didn't trigger the metalink?

(MyClass>>#method:) valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) reflectiveMethod valueWithReceiver: c arguments: #(1).

2) why in the second case these two methods did trigger the metalink?

(MyClass>>#method:) compiledMethod valueWithReceiver: c arguments: #(1).
MyClass rFwithArgs: #(1) executeMethod: (MyClass>>#method:) compiledMethod.

#rFwithArgs:executeMethod: even has comment "This method is used by reflectivity internally. All meta-links are ignored".

3) why the class of (MyClass>>#method:) changed after calling `method:`?

```
(MyClass >> #method:) ast link: link.

c := MyClass new.
(MyClass>>#method:) class. "ReflectiveMethod"
(MyClass>>#method:) valueWithReceiver: c arguments: #(1).
(MyClass>>#method:) class. "ReflectiveMethod"
c method: 1.
(MyClass>>#method:) class. "CompiledMethod"
```

4) (unrelated to the above) I tried calling `link disable` from within the #metaObject, but it was ignored, but maybe I don't understand its purpose.


You can enable / disable the condition without actually changing / reinstalling the link

link condition:[:args | args first isNumber] arguments:#(arguments).

c method:1.   "<- will trigger halt"
c method:'s'.  "<- wont trigger halt"

link disable. "<- disable the condition, like condition never holds"

c method:1.   "<- wont trigger halt"
c method:'s'.  "<- wont trigger halt"

 


Thanks,
Peter

On Sun, Oct 23, 2016 at 09:21:59AM +0200, Yuriy Tymchuk wrote:
> I’ve also described the question with examples on SO: https://stackoverflow.com/questions/40200546/conditionally-skip-a-method-with-matalinks
>
> > On 22 Oct 2016, at 23:13, Yuriy Tymchuk <[hidden email]> wrote:
> >
> > Hi.
> >
> > Imagine I have method a: and I want to skip the execution (return self or nil or whatever) when a: is evaluated with parameter 0. I have tried to add a meta link which will run instead of the method with a condition, but the condition did not work… I have tried to implement the metallic method to do nothing if the arg is 0 otherwise to perform the method, but I end up with an infinite loop…
> >
> > Did anybody do something like that already? Any suggestions?
> >
> > Uko
>


Reply | Threaded
Open this post in threaded view
|

Re: MetaLink to conditionally skip a method execution based on an arg

Nicolai Hess-3-2
In reply to this post by Uko2

Am 23.10.2016 9:22 vorm. schrieb "Yuriy Tymchuk" <[hidden email]>:
>
> I’ve also described the question with examples on SO: https://stackoverflow.com/questions/40200546/conditionally-skip-a-method-with-matalinks
>

Answered on SO.
@marcus: Maybe instead links should continue with the original code, if their condition does not hold?

>> On 22 Oct 2016, at 23:13, Yuriy Tymchuk <[hidden email]> wrote:
>>
>> Hi.
>>
>> Imagine I have method a: and I want to skip the execution (return self or nil or whatever) when a: is evaluated with parameter 0. I have tried to add a meta link which will run instead of the method with a condition, but the condition did not work… I have tried to implement the metallic method to do nothing if the arg is 0 otherwise to perform the method, but I end up with an infinite loop…
>>
>> Did anybody do something like that already? Any suggestions?
>>
>> Uko
>
>