[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Extending Lua-RPC: questions about handling index and call events
- From: James Snyder <jbsnyder@...>
- Date: Thu, 4 Jun 2009 09:39:14 -0500
On Jun 3, 2009, at 8:20 PM, Geoff Leyland wrote:
On 4/06/2009, at 12:25 PM, James Snyder wrote:
Would lazy evaluation work? You could not do anything until the
object is used by a __call, __tostring, __add or some other
metamethod. There would be the usual problem with comparison
operators, but it would work some of the time I think.
That works for a fair number of things so long as there's a
metamethod that can be hooked prior to an operation.
It does get weird with something like:
value_from_server = handle.some_value
value_from_server + local_value
or even things like:
value_from_server + handle.some_other_value
These would both work wouldn't they? Your helper's __add would get
its (and the other operand's, if it was also a helper) value from
the server and do the job locally. (Which is what I think you wrote
next). I don't see a problem with that - am I missing something?
You *could* build a syntax tree and serialise that and send it to
the server, but that'd be probably more complication than is
necessary.
Right, they would with the implementation of an __add.
To me it would make the most sense to, when possible, pull both to
the local environment, and then perform the local operation as it
would with that type. I wonder if that could be cleanly
generalized somehow? It would be nice to be able to do things like
call math.cos(handle.some_remote_value) without having to
explicitly copy it from the remote to the local state. For things
like this,
That should be possible, right? You're serialising the call anyway,
so if you can just serialise the helper too, it should be possible
to handle it on the remote machine?
Hmm.. So, executing the line above gives you the following bytecode:
main <test.lua:0,0> (6 instructions, 24 bytes at 0x1dd5530)
0+ params, 2 slots, 0 upvalues, 0 locals, 4 constants, 0 functions
1 [1] GETGLOBAL 0 -1 ; math
2 [1] GETTABLE 0 0 -2 ; "cos"
3 [1] GETGLOBAL 1 -3 ; handle
4 [1] GETTABLE 1 1 -4 ; "some_remote_value"
5 [1] CALL 0 2 1
6 [1] RETURN 0 1
This is tougher than the other metatable stuff because after getting
the cos function onto the stack, locally, I'm putting a
some_remote_value userdata for it to operate on locally.
Unfortunately, it's not a lua number however, it's a userdata.
Looking at how this is implemented in lua, I don't see how I can hook
this in such a way that I can have that userdata behave like a number.
This, I suppose, is the crux of this issue: how do I know whether to
push userdata onto the local stack, or to serialize the remote value
and put that actual value on the stack instead?
handle.math.cos(handle.some_remote_value) wouldn't be as much of a
problem, since I could push over the index events to get
some_remote_value onto the remote stack for the remote cos.
I guess one way to deal with this would be to handle things this way
for remote indexes:
if type is number, string, boolean, or nil:
serialize it and put it on the local stack,
otherwise:
provide lazy evaluation helper
There are probably a bunch of disadvantages I'm not thinking of here,
but I think, for sure, I have to point the index to some sort of
proxying function that actually gets the remote value, otherwise I'll
end up with a local cached value on the local table (which would be
undesirable if the value changed on the remote side and I wanted to
poll it).
It doesn't have to perfectly handle every situation. My main goals
are to make it easy to execute functions on a remote session, and
to make it pretty easy to get data from the remote environment for
further local processing.
I think a combination of laziness and offering a "get" as you
mention below would work fine. There'd be some odd corners when you
weren't sure if you needed a get or forgot one, but that wouldn't be
too bad would it?
No, this might be a good way to make intentions explicit without
making a huge hairy implementation that might require a fair amount of
work whenever Lua gets updated. It certainly has no downsides to
inclusion even if the default behavior were extended to try and do
something clever.
Perhaps the easiest approach is to do lazy evaluation, where the
helper can handle __call (to call a remote function), __index (to
index deeper into multiple layers of tables), and a method like
"get" or "copy" that would take anything it knows how to serialize
and copy it to the local stack.
Thanks for your comments and thoughts :-)
Any other suggestions? (doing it all from a module without
modifying Lua itself would be best)
Although the goal is completely different, this has a lot in common
with rima's late bound symbolic math stuff - which is far from
elegant or finished at the moment - so I'll look forward to seeing
what you come up with. Rima does have an eval, and it includes the
"connection" (called a scope), so, in your context you'd have
something like:
local a, b = rpc.helper"a, b"
local e = a + b.some_value
local res1 = rpc.eval(e, connection1)
and then you could ask another server/scope the same question
local res2 = rpc.eval(e, connection2)
I doubt that there's any use for that kind of functionality in what
you're doing, but I'm pleasantly surprised that some of the insides
are so similar.
Interesting, is Rima available somewhere? I might be interested in
taking a look just to see if I might learn a bit from the
implementation.
I could see some advantage to doing something like what you describe
above where you might have a client talking to multiple lua instances
to either poll them for state information, or to do work on them. If
you wrap things with some sort of map function and use it to work on
large chunks of data over a series of connections registered on a
table or something.
I'm mainly working on this for use with eLua (hence the serial link
protocol being supported (which is giving me some headaches) ), so
that I can have a link to an embedded device and do development and
testing while having the benefit of being able to get large quantities
of data back to a desktop machine. There might be benefit to being
able to use this sort of thing to poll a bunch of embedded devices in
succession over a network or wireless link.
Side note for those who might use this:
I make no claims about how well this code will deal with anything
malicious. Since it's fairly simple, it likely is possible to lock it
down a little more tightly and deal with potential exploitation.
Because of the way it is abstracted, you should be able to wrap the
low level buffer writing code to add any layers one might want around
the actual messages that are transmitted. I'm working to make this as
easy as possible to use on any sort of communication medium that one
can read and write bytes to, since the embedded devices it will be
used on could use a variety of different types of links :-)
Also, it does NOT deal with correcting endianness for the data
transmitted, at this point, but I will likely deal with this in the
future (hopefully automatically :-).
--
James Snyder
Biomedical Engineering
Northwestern University
jbsnyder@fanplastic.org
http://fanplastic.org/key.txt
ph: (847) 448-0386
Attachment:
PGP.sig
Description: This is a digitally signed message part