Nice idea... I'm wondering how this would impact on implementation. As a side note I suspect that most non-die-hard fans of Eiffel will find the syntax "agent is do std_output.put_line(i.out) end.call([])" quite obscure, expecially for the dot-call alone in the line... BTW how should a closure like the following behave? foo is local i: INTEGER do i:=0 10.times(do i:=i+1 if i>8 then print("Ok%N") end end) print(i.out) end
Shall it print: Ok Ok 10 or nothing because i is reset at the value it had at agent invocation (0)?
Currently a class like this:
class AGTE -- Agent test creation make
feature make is local i: INTEGER do i:=5 print("i="+i.out+"%N") 10.times(agent is do i:=i+1 end) print("i="+i.out+"%N") end -- i: INTEGER end -- class AGTE
crashes SmartEiffel, while class AGTE -- Agent test creation make feature make is do i:=5 print("i="+i.out+"%N") 10.times(agent is do i:=i+1 end) print("i="+i.out+"%N") end i: INTEGER end -- class AGTE outputs:
i=5 i=15
I see that what we currently have are not "real" closures but I don't see the gain, at least explainable with a simplicistic example. Perhaps I'm missing something
mmh. Without digging into theory now, I think it is good to have access to the variables defined in the lexical environment of the agent. First of all, because it improves readability.
Thinking about inline agents, it may be a good idea to think about improving the .call([]). I'm definitely not a fan of introducing useless syntactic sugar, but an inline agent call just does not look nice. I have not settled an opinion here.
Another question that arises when thinking about anonymous inner "functions" is whether anonymous inner classes are of any good. - I used them in Java often for the visitor pattern and here there are cool. Anyhow, I do not remember any other nice use cases.
Closures mean access to the local variables. If they are not separate then they will be cloned as per Liberty's idea of SCOOP. Needless to say, i := i + 1 would not work as expected.
But the variables are only cloned, if the agent is executed on another processor, wouldn't it? I'd suggest to bind inline agents always to the same processor, as the "outlining" feature defining and using the inline agent. So by definition local variables would not need to be imported...
Nice idea... I'm wondering how this would impact on implementation.
ReplyDeleteAs a side note I suspect that most non-die-hard fans of Eiffel will find the syntax "agent is do std_output.put_line(i.out) end.call([])" quite obscure, expecially for the dot-call alone in the line...
BTW how should a closure like the following behave?
foo is
local i: INTEGER
do
i:=0
10.times(do
i:=i+1
if i>8 then print("Ok%N") end
end)
print(i.out)
end
Shall it print:
Ok
Ok
10
or nothing because i is reset at the value it had at agent invocation (0)?
Currently a class like this:
class AGTE
-- Agent test
creation make
feature
make is
local i: INTEGER
do
i:=5
print("i="+i.out+"%N")
10.times(agent is do i:=i+1 end)
print("i="+i.out+"%N")
end
-- i: INTEGER
end -- class AGTE
crashes SmartEiffel, while
class AGTE
-- Agent test
creation make
feature
make is
do
i:=5
print("i="+i.out+"%N")
10.times(agent is do i:=i+1 end)
print("i="+i.out+"%N")
end
i: INTEGER
end -- class AGTE
outputs:
i=5
i=15
I see that what we currently have are not "real" closures but I don't see the gain, at least explainable with a simplicistic example. Perhaps I'm missing something
Men, we miss an online Eiffel code formatter/colorer.... reading code like this is abysimal.
ReplyDeletemmh. Without digging into theory now, I think it is good to have access to the variables defined in the lexical environment of the agent. First of all, because it improves readability.
ReplyDeleteThinking about inline agents, it may be a good idea to think about improving the .call([]). I'm definitely not a fan of introducing useless syntactic sugar, but an inline agent call just does not look nice. I have not settled an opinion here.
Another question that arises when thinking about anonymous inner "functions" is whether anonymous inner classes are of any good. - I used them in Java often for the visitor pattern and here there are cool. Anyhow, I do not remember any other nice use cases.
Paolo, thanks for your remarks.
ReplyDeleteWriteable entities are indeed something to think of but I think they should behave as you fell they should.
I mean,
i=5
i=15
SmartEiffel crashes because there is some test missing somewhere. In SmartEiffel i is out of the agent scope.
I'll have to test other languages that have closures to know how they behave.
Now, how do closures integrate with SCOOP :-)
closures in SCOOP? Is there anything special? - They are executes synchronously on the same processor as the calling code.
ReplyDeleteClosures mean access to the local variables. If they are not separate then they will be cloned as per Liberty's idea of SCOOP. Needless to say, i := i + 1 would not work as expected.
ReplyDeleteBut the variables are only cloned, if the agent is executed on another processor, wouldn't it? I'd suggest to bind inline agents always to the same processor, as the "outlining" feature defining and using the inline agent. So by definition local variables would not need to be imported...
ReplyDeleteagent {MY_SEPARATE}.do_something
ReplyDeleteMaybe this should be forgotten because there is a rule that a separate target must be an argument of the calling method... Well I don't know
Reading my last message... of course I meant "forbidden", not "forgotten"!!
ReplyDelete