lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

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,
	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
ph: (847) 448-0386

Attachment: PGP.sig
Description: This is a digitally signed message part