Generator
A friend of mine mentioned about generator's in java.
I took a look at the infomancers-collections which claims to implement this for java.
Neat package - would love to play with it for passtime, not sure if I will ever touch it for production code.
The basic essential idea is simple :
a) use the bytecode instrumentation hooks in vm to modify the class loaded at runtime so as to inject code into subclasses of com.infomancers.collections.yield.Yielder.
b) Modify bytecode such that any call to 'yieldReturn' in yieldNextCore() is succeeded by:
b.1) record state.
b.2) return.
b.3) inject a label after this return.
c) Inject code in begining of yieldNextCode to essentially convert it into a large switch case - based on 'state', decide where to jump next.
So a simple pseudo example would be :
-- developer code start --
yieldNextCore() {
if (1 == count) {
// return some_a() if cond is satisfied.
yieldReturn(some_a());
}
// return some_b() as the generated value
return yieldReturn(some_b());
}
-- developer code end --
would be converted to -
-- generated code start --
int state = 0;
yieldNextCore() {
switch (state) {
case 0: goto label_0;
case 1: goto label_1;
}
label_0:
if (1 == count) {
yieldReturn(some_a());
state = 1;
return ;
}
label_1:
yieldReturn(some_b());
state = 2;
return ;
label_2:
}
-- generated code end --
To make sure that this will actually work, all the local variables within the method are pulled out as instance variables in the class.
Cute trick !
PS: I have not tried the code, or the package. So I cant answer questions of what happens if yieldReturn is called from outside yieldNextCore (might not work ?), conflicting names within different scopes in the yieldNextCore method (load error ?), etc.
As I said, I considered this as a nice solution to an interesting side problem ...
I took a look at the infomancers-collections which claims to implement this for java.
Neat package - would love to play with it for passtime, not sure if I will ever touch it for production code.
The basic essential idea is simple :
a) use the bytecode instrumentation hooks in vm to modify the class loaded at runtime so as to inject code into subclasses of com.infomancers.collections.yield.Yielder.
b) Modify bytecode such that any call to 'yieldReturn' in yieldNextCore() is succeeded by:
b.1) record state.
b.2) return.
b.3) inject a label after this return.
c) Inject code in begining of yieldNextCode to essentially convert it into a large switch case - based on 'state', decide where to jump next.
So a simple pseudo example would be :
-- developer code start --
yieldNextCore() {
if (1 == count) {
// return some_a() if cond is satisfied.
yieldReturn(some_a());
}
// return some_b() as the generated value
return yieldReturn(some_b());
}
-- developer code end --
would be converted to -
-- generated code start --
int state = 0;
yieldNextCore() {
switch (state) {
case 0: goto label_0;
case 1: goto label_1;
}
label_0:
if (1 == count) {
yieldReturn(some_a());
state = 1;
return ;
}
label_1:
yieldReturn(some_b());
state = 2;
return ;
label_2:
}
-- generated code end --
To make sure that this will actually work, all the local variables within the method are pulled out as instance variables in the class.
Cute trick !
PS: I have not tried the code, or the package. So I cant answer questions of what happens if yieldReturn is called from outside yieldNextCore (might not work ?), conflicting names within different scopes in the yieldNextCore method (load error ?), etc.
As I said, I considered this as a nice solution to an interesting side problem ...
2 Comments:
This thing is quite useful and used very often in python actually. I don't think you can write a non trivial program in Python and not use them.
Initially, they kept this as an optimisation for iterable objects but now I think it's pretty much standard.
Interesting...nice post
Post a Comment
<< Home