473,394 Members | 1,746 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

a question regarding call-by-reference

I am working on a school project, trying to build a simple RPC stub
generator. The idea is that the generator takes a normal python file
with functions defined in it and produces a client and server stub. The
client stub has the same functions defined, but they just connect to
the server and ask it to call the desired functions. The server stub is
a server listening for incoming requests and dispatching them to the
appropriate functions and sending back the results. Extremely simple
and I've gotten it to mostly work, but I have one problem:
call-by-reference parameters. An example:

A function like this:
def sum(a, b):
return a + b

would yield a client stub like this (simplified):
def sum(a, b):
send_message({'funcname': 'sum', 'args': (a, b)})
result = receive_message()
return result

Now, this works just fine. I get problems when I try to do something
like this:
def add_elm(list):
list.append('elm')
return

Imported normally this would work fine. The list given as a parameter
would be one element larger. But when the stubs are generated, the
function doesn't return anything and the list is appended in the server
and the client-side list is left untouched. At first I thought the
solution was easy, just return the changed parameters and place them in
the parameter variables in the client stub:
def add_elm(list):
send_message({'funcname': 'add_elm', 'args': (list)})
response = receive_message()
(list) = response.get('args')
return response.get('result')

The problem is, this doesn't work. The original list doesn't point to
the changed list. I have been trying to figure this out and it seems
that if I just assign to the list variable it just modifies the local
(to the function) name space, and that those changes aren't reflected
in the list in the original name space.

I believe there are some ways around this, but I haven't found one that
would not require any special handling in either the code calling the
client stub or the original functions. I want to maintain transparency.

etv

Feb 6 '06 #1
6 1459
"enjoying the view" <pp******@gmail.com> wrote in message
news:11**********************@o13g2000cwo.googlegr oups.com...
I am working on a school project, trying to build a simple RPC stub
generator. The idea is that the generator takes a normal python file
with functions defined in it and produces a client and server stub. The
client stub has the same functions defined, but they just connect to
the server and ask it to call the desired functions. The server stub is
a server listening for incoming requests and dispatching them to the
appropriate functions and sending back the results.

<snip>

One thing you might try is iterating over the arguments and doing special
handling for lists and dicts, which can be updated within the called module.
Using your example (changing 'list' to 'listarg' to avoid confusion):

def add_elm(listarg):
listarg.append('elm')
return

Generate code like:

def add_elm(listarg):
send_message({'funcname': 'add_elm', 'args': (listarg)})
response = receive_message()
listarg[:] = response.get('args')[0][:]
return response.get('result')

If the listargs get long/complicated, you might be doing a lot of data
copying at the cost of performance (especially since this is a defensive
copy - you don't *know* that the list was updated in the server in the first
place - I guess you could test first with "if response.get('args')[0] !=
listarg:" or something).

For dicts, do:

dictarg.update(response.get('args')[n])

This will be a little cheaper than just total replacement of the contents,
which is what the list [:] slice will do.

But this special-case handling only works for lists and dicts (don't know
how you would handle tuples or scalar variables), you quickly run into other
problems with passing objects. I'm taking you at your word that you are
creating a *simple* RPC stub generator. At this point, you can generate
stubs for methods that do not update their arguments, or for methods that
pass lists or dicts. I've used CORBA in the past, and this is similar to
using a subset of the full parameter functionality, such as using only "in"
parameters (as opposed to "out" or "inout"). That is, instead of defining a
method that modifies its parameter value, have the new value returned by the
function. Python actually helps you here, since it is so easy to pass back
a tuple of values from a function.

This kind of parameter marshalling/unmarshalling gets complicated quickly.
You are already very near the edge of non-intrusiveness on the client and
server sides - to get more features, you'll need to start adding some
aspects of parameter passing mechanisms (such as CORBA's in/out/inout
keywords), and object marshalling conventions (such as requiring objects
that are passed to implement compare() and update() or copy() methods).

-- Paul
Feb 6 '06 #2
enjoying the view wrote:
I am working on a school project, trying to build a simple RPC stub
generator. The idea is that the generator takes a normal python file
with functions defined in it and produces a client and server stub. The
client stub has the same functions defined, but they just connect to
the server and ask it to call the desired functions. The server stub is
a server listening for incoming requests and dispatching them to the
appropriate functions and sending back the results. Extremely simple
and I've gotten it to mostly work, but I have one problem:
call-by-reference parameters. An example:

A function like this:
def sum(a, b):
return a + b

would yield a client stub like this (simplified):
def sum(a, b):
send_message({'funcname': 'sum', 'args': (a, b)})
result = receive_message()
return result

Now, this works just fine. I get problems when I try to do something
like this:
def add_elm(list):
list.append('elm')
return

Imported normally this would work fine. The list given as a parameter
would be one element larger. But when the stubs are generated, the
function doesn't return anything and the list is appended in the server
and the client-side list is left untouched. At first I thought the
solution was easy, just return the changed parameters and place them in
the parameter variables in the client stub:
def add_elm(list):
send_message({'funcname': 'add_elm', 'args': (list)})
response = receive_message()
(list) = response.get('args')
return response.get('result')

The problem is, this doesn't work. The original list doesn't point to
the changed list. I have been trying to figure this out and it seems
that if I just assign to the list variable it just modifies the local
(to the function) name space, and that those changes aren't reflected
in the list in the original name space.

I believe there are some ways around this, but I haven't found one that
would not require any special handling in either the code calling the
client stub or the original functions. I want to maintain transparency.

etv

I am not an expert, so maybe someone else can provide here a nice tricky
solution, but I am quite sure, that there is no simple way around the
described problem.
The only strategy which comes to my mind in this context is to use for
all function arguments and return values only pickled objects which need
to be unpickled on the other side. Probably some compression algorithm
can help to keep the network traffic down in case large amount of data
must be exchanged.

Claudio
Feb 7 '06 #3
enjoying the view wrote:
Imported normally this would work fine. The list given as a parameter
would be one element larger. But when the stubs are generated, the
function doesn't return anything and the list is appended in the server
and the client-side list is left untouched. At first I thought the
solution was easy, just return the changed parameters and place them in
the parameter variables in the client stub:
def add_elm(list):
send_message({'funcname': 'add_elm', 'args': (list)})
response = receive_message()
(list) = response.get('args')
return response.get('result')

The problem is, this doesn't work. The original list doesn't point to
the changed list. I have been trying to figure this out and it seems
that if I just assign to the list variable it just modifies the local
(to the function) name space, and that those changes aren't reflected
in the list in the original name space.


Try
list[:] = response.get('args')
this will change the value of the list passed in.

Kent
Feb 7 '06 #4
On 6 Feb 2006 10:21:45 -0800, "enjoying the view" <pp******@gmail.com> wrote:
I am working on a school project, trying to build a simple RPC stub
generator. The idea is that the generator takes a normal python file
with functions defined in it and produces a client and server stub. The
client stub has the same functions defined, but they just connect to
the server and ask it to call the desired functions. The server stub is
a server listening for incoming requests and dispatching them to the
appropriate functions and sending back the results. Extremely simple
and I've gotten it to mostly work, but I have one problem:
call-by-reference parameters. An example:

A function like this:
def sum(a, b):
return a + b

would yield a client stub like this (simplified):
def sum(a, b):
send_message({'funcname': 'sum', 'args': (a, b)})
result = receive_message()
return result

Now, this works just fine. I get problems when I try to do something
like this:
def add_elm(list):
list.append('elm')
return

Imported normally this would work fine. The list given as a parameter
would be one element larger. But when the stubs are generated, the
function doesn't return anything and the list is appended in the server
and the client-side list is left untouched. At first I thought the
solution was easy, just return the changed parameters and place them in
the parameter variables in the client stub:
def add_elm(list):
send_message({'funcname': 'add_elm', 'args': (list)})
response = receive_message() if the response contains an updated list, you can update the content
of the add_elm caller's list by slice assignment, e.g.,
list[:] = response.get(<however you get the updated list>')

But you are in really tricky territory here I think. There is any number
of ways to mutate objects via function argument reference. Not just
if they're lists. And lists can be deeply nested, so you could be sending
deep copies of lists across a network, which could involve most of your memory
even if the first level has only a few elements. And if there are side effects besides
the direct mutations, you have additional problems. What if a function accesses
arg.prop and that's a property that keeps count or otherwise tracks instances of something?

The totally general solution is probably impossible. So if I were you I would go back to
the specifier of this problem and negotiate some severe restrictions on assumptions
about arguments (maybe just outlaw direct mutation and access side effects ;-)
(list) = response.get('args')
return response.get('result')

The problem is, this doesn't work. The original list doesn't point to
the changed list. I have been trying to figure this out and it seems
that if I just assign to the list variable it just modifies the local
(to the function) name space, and that those changes aren't reflected
in the list in the original name space.

I believe there are some ways around this, but I haven't found one that
would not require any special handling in either the code calling the
client stub or the original functions. I want to maintain transparency.

etv

Good luck ;-)

Regards,
Bengt Richter
Feb 7 '06 #5
Thank you everyone for your helpful replies!

I think the problems that arise with nested and overly large lists and
dictionaries, and difficulties of handling other mutable datatypes will
make my little assignment just too difficult. I'll just specify that
call-by-reference isn't supported and leave it at that.

Between floors. Going down.
Enjoying the view.

Feb 8 '06 #6
Don't send the whole list or parts of the list to the server unless
actually needed!

If the server has to do an append, have the server send back the new
elements to be appended and then do the appending on the client side!

Or

Does the homework specify that the entire mutable type be sent to the
server?
"enjoying the view" <pp******@gmail.com> wrote:
I am working on a school project, trying to build a simple RPC stub
generator. The idea is that the generator takes a normal python file
with functions defined in it and produces a client and server stub. The
client stub has the same functions defined, but they just connect to
the server and ask it to call the desired functions. The server stub is
a server listening for incoming requests and dispatching them to the
appropriate functions and sending back the results. Extremely simple
and I've gotten it to mostly work, but I have one problem:
call-by-reference parameters. An example:

A function like this:
def sum(a, b):
return a + b

would yield a client stub like this (simplified):
def sum(a, b):
send_message({'funcname': 'sum', 'args': (a, b)})
result = receive_message()
return result

Now, this works just fine. I get problems when I try to do something
like this:
def add_elm(list):
list.append('elm')
return

Imported normally this would work fine. The list given as a parameter
would be one element larger. But when the stubs are generated, the
function doesn't return anything and the list is appended in the server
and the client-side list is left untouched. At first I thought the
solution was easy, just return the changed parameters and place them in
the parameter variables in the client stub:
def add_elm(list):
send_message({'funcname': 'add_elm', 'args': (list)})
response = receive_message()
(list) = response.get('args')
return response.get('result')

The problem is, this doesn't work. The original list doesn't point to
the changed list. I have been trying to figure this out and it seems
that if I just assign to the list variable it just modifies the local
(to the function) name space, and that those changes aren't reflected
in the list in the original name space.

I believe there are some ways around this, but I haven't found one that
would not require any special handling in either the code calling the
client stub or the original functions. I want to maintain transparency.

etv

--
Regards,
Casey
Feb 8 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Karl M | last post by:
Hi everyone, I just notice some strange behaviors on the MS C++ compiler regarding struct default constructor, see the example bellow: struct MyStruct { int a; }; class MyClass { public:
3
by: Sarika | last post by:
I have some questions regarding Modal forms and would appreciate if someone could clarify my understanding. (a) I observed that the modal form's Form_Closing event is generated if I set the...
77
by: M.B | last post by:
Guys, Need some of your opinion on an oft beaten track We have an option of using "goto" in C language, but most testbooks (even K&R) advice against use of it. My personal experience was that...
3
by: trialproduct2004 | last post by:
Hi all, Can someone tell me how virtual functions works. Like how memory is getting allocated to virtual function. And how to call base class function through derived class pointer. And why...
5
by: annhere | last post by:
Hi we have a certain SQL script. From that script we have calls like: DROP FUNCTION A@ call sqlj.remove_jar( 'AXML')@ CALL SQLJ.REFRESH_CLASSES()@ call sqlj.install_jar( 'file:C:\AXML.jar',...
20
by: sam_cit | last post by:
Hi Everyone, I have the following code, int main() { int p = {10,20,30,40,50}; int *i = &p; printf("before : %p\n",(void*)i); printf("1 %d %d\n",*++i,*i++);
4
by: Benny Van | last post by:
Hi all! I have a question regarding a windows operating system function: I was asked to write a small program for a homework to display the user name and computer name and the system time out to a...
1
by: Jim Flanagan | last post by:
Hello - I am in need of more help regarding an approach to accomplishing the following: We have a need to change the Volume serial numbers of a bunch of preprogrammed IDE Solid State Drive...
5
by: Philip Potter | last post by:
I have a somewhat flippant question regarding undefined behaviour. Does an operation which invokes undefined behaviour affect the whole program, or are earlier statements guaranteed to execute...
4
by: Pranav | last post by:
Hello All, I have a simple question regarding the definition of abstract class, IIRC , Abstract class is one which contains virtual function declaration and other variables and no object of this...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.