Pass-by-reference : Could a C#-like approach work in Python?

S

Stephen Horne

I have in the past suggested that Python functions could use some kind
of modifier token for parameters to indicate pass-by-reference, so
that immutable items in particular could be modified (or more
accurately replaced) by the function, with that modification affecting
what the caller sees. In case I'm explaining this badly, here is how
Python currently works...
.... p += 1
....1

.... and here is (roughly) what I'd like to be able to do...
.... p += 1
....2


There are good reasons why this is not supported in Python at present,
which have been explained to me in the past. However, I've been
learning C# just recently, and I've just been struck by a blinding
flash of the obvious. C# has a rather similar issue - some types are
'value types' (as opposed to 'reference types') and comparable to
immutables in Python in many ways, yet there is still a need (on
occasion) to pass them by reference. While C# has static typing and
could have done exactly the same thing as Pascal or as C++, it
actually did something different.

The C# solution uses a modifier keyword, but that keyword must be
specified in both the function definition *and* the call. For
instance...

....
public static void Inc (ref int p)
{
p++;
}
....
int i = 1;

Inc (ref i);
....

The rationale for this in C#, I assume, is mostly about clarity and
maintainability - the caller can't be surprised when value type
parameters are changed in a function as he had to explicitly allow it.
It also allows both a by-reference and a by-value version of the same
function to be defined using overloading (though that seems much less
useful to me).

However, it occurred to me that this approach could also be used to
solve the main implementation problem with adding a call-by-reference
scheme to Python.

In Python, the compiler cannot adapt the calling convention to
different types of functions because it cannot refer back to the
declaration of the function at compile time - the function being
called is not always knowable until run-time (e.g. using a variable
can be assigned a function object, lambda can create anonymous
functions, etc). At first sight, it appears that supporting
call-by-reference would require a big run-time overhead as the
run-time engine queried the function object to determine which
parameters to pass by reference and to adapt the call appropriately.

Because the C# approach indicates which parameters are by reference in
the call, however, this overhead can be avoided - the compiler doesn't
need to refer to information in the declaration to determine which
parameters to pass by reference.

Basically, when a function or method is declared with 'ref' modifiers
on some parameters, Python could use a variant of the function type
which supports a new call mechanism and knows which parameters need to
be passed by reference. Similarly, when a call uses 'ref' modifiers,
Python can do a consistency check with the function type being called
and use the new call mechanism.

Performance with functions that don't use call-by-reference would be
unaffected...

1. If a call with ref-modifiers is attempted on a non-ref function,
this would be rejected in the same way as any attempted call
on a non-callable object - the required behaviour wouldn't exist
for conventional function objects.

2. If a call without ref-modifiers is attempted on a function with
ref modifiers, it would again be rejected as the new function
type wouldn't support the required behaviour for conventional
calls.

3. A conventional call to a conventional function would operate
exactly as it does now.

In short, only calls using call-by-reference would incur any overhead
(to validate that the correct parameters are by-reference or not, and
to implement the new calling convention).

Even that validation in the call overhead could probably be avoided
(by having a large number of function-class variants), leaving only
the implementation of the calling convention as a problem.

I would then be able to write...
.... p += 1
....2

Obviously the implementation would not be trivial, but i think this
would be a very useful feature.

Any thoughts?
 
T

Tim Hoffman

Hi Stephen

The bit I can't fathom is why you would want to do this ?
At least in the case of the simple example you give.

In your example aren't you really asking for a reference to a reference
to be passed, because in Python you always just pass a reference to an
object, in the sense that x = 1 is variable x pointing to the integer
object 1.

When you call inc function you are taking an immutable object 1 and
creating a new object which is the result of adding 1 to 1. And what you
are then asking it to rebind the variable x to point to the new int
object 2 inside the function.

Why you would want to do this is unclear. Secondly if it where a more
abstract object it would have an increment method which you could call
on the object which was passed to the function.

So again I just can't see why you want to do it.

Maybe I am missing something here

Tim


Stephen said:
I have in the past suggested that Python functions could use some kind
of modifier token for parameters to indicate pass-by-reference, so
that immutable items in particular could be modified (or more
accurately replaced) by the function, with that modification affecting
what the caller sees. In case I'm explaining this badly, here is how
Python currently works...



... p += 1
...


1

... and here is (roughly) what I'd like to be able to do...



... p += 1
...


stuff removed.
 
P

Peter Otten

Stephen said:
... and here is (roughly) what I'd like to be able to do...

... p += 1
...

Any thoughts?

Obviously, your example could easily be rewritten to

def inc(p):
return p + 1

x = inc(x)

and a similar function with two by-ref parameters would still be readable:

x, y = inc2(x, y)

So here's my question. How many functions are there in your *real* code that
could benefit from, say three or more by-ref parameters?
Hint: for me it comes close to 0 :)

By the way, this is strictly from a user perspective, I trust the Python
developers to overcome the implementation issuses, *if* there is a
significant usability improvement.


Peter
 
J

JCM

....
... p += 1
...
2

While I'd not be against some sort of reference-passing mechanism in
Python, I think this is the wrong way to go--modifiability should be
evident to the caller. Currently, if you see a call to f(x) you know
that x cannot be rebound. I'd be more in favor of something like:
... p += 1
... 2
 
S

Stephen Horne

Hi Stephen

The bit I can't fathom is why you would want to do this ?
At least in the case of the simple example you give.

It wasn't intended as a real world example - it was only intended to
illustrate what I want to be able to do.
When you call inc function you are taking an immutable object 1 and
creating a new object which is the result of adding 1 to 1. And what you
are then asking it to rebind the variable x to point to the new int
object 2 inside the function.

Yes - that is exactly it. To rebind the callers variable/whatever that
supplied the parameter from within the function.
Why you would want to do this is unclear. Secondly if it where a more
abstract object it would have an increment method which you could call
on the object which was passed to the function.

No, you are taking the noddy example too literally.

For a more realistic (but still simplified) example, see my reply to
Peter Ottens post.
 
S

Stephen Horne

...


While I'd not be against some sort of reference-passing mechanism in
Python, I think this is the wrong way to go--modifiability should be
evident to the caller.

1. I pointed out that this is an advantage of the C# system, which I
was proposing to imitate.

: The C# solution uses a modifier keyword, but that keyword must be
: specified in both the function definition *and* the call. For
: instance...

....

: The rationale for this in C#, I assume, is mostly about clarity and
: maintainability - the caller can't be surprised when value type
: parameters are changed in a function as he had to explicitly allow it.


2. You quoted the example I labelled as "(roughly) what I'd like to
be able to do" and ignored the one where I adopted the C#
approach...

: >>> def Inc(ref p) :
: ... p += 1
: ...
: >>> x = 1
: >>> Inc(ref x)
: >>> x
: 2

So your criticism is invalid simply because the whole point of my post
was to suggest a scheme where "modifiability should be evident to the
caller".
Currently, if you see a call to f(x) you know
that x cannot be rebound.

And if in some future version of Python the suggestion I made was
implemented, when you see f(x) you will still know that x cannot be
rebound - but when you see f(ref x) you will know that x may well be
rebound.
I'd be more in favor of something like:

... p += 1
...
2

I wouldn't want this. To implement it, either a single compiled
version of a function would need to figure out at run time whether the
parameters where by reference or not, or several versions of each
function would have to be compiled into the .pyc file.

Also, I don't really see the benefit. If a function has by-reference
parameters then rebinding those parameters is likely a big part of the
purpose of the function. Supplying a parameter which cannot be rebound
is likely an error caused by someone forgetting to type the 'ref', in
which case they'd equally likely appreciate an error message as
opposed to wierd, hard-to-trace logic errors.
 
S

Stephen Horne

Obviously, your example could easily be rewritten to

def inc(p):
return p + 1

x = inc(x)

and a similar function with two by-ref parameters would still be readable:

x, y = inc2(x, y)

So here's my question. How many functions are there in your *real* code that
could benefit from, say three or more by-ref parameters?
Hint: for me it comes close to 0 :)

Its not an issue of whether the same effect can be achieved in Python.
It's more an issue of whether the method used expresses the
programmers intentions properly.

If a function is defined as...

def Inc (p) :
return p + 1

then that to me expresses an intention which is different to that
expressed by...

def Inc (ref p) :
p += 1

The latter case expresses the intention to in-place rebinding of the
parameter. In doing so, it better expresses the purpose of some kinds
of functions (though not this noddy example, obviously).

This is all very fuzzy, so let's examine an example which is based on
an issue in some real Python code (though this is simplified to make
the point). The problem is to insert an object into some container -
appending to a list will do here. However, the object being inserted
will typically be quite large, so we want to avoid copying it if
possible.

No problem there, it seems...

class c_Container :
f_List = []

def Add (self, p_Object) :
f_List.append (p_Object)

The problem with this, however, is the risk of accidental
side-effects. If the caller goes on to modify the object that he
passed as a parameter, that will change the content of the container.

So how can rebindable parameters help with this?

One approach would be to make the function rebind the parameter to
either None or some kind of read-only proxy object. If the caller
tried to modify the object after passing it in, he'd very quickly get
error messages. They may seem cryptic, but they'd be better than the
strange hard-to-trace errors you get with accidental side-effects.

Having figured out what the problem is, the caller simply has to make
a copy of the object himself (or use a variant of the function that
does the copying itself).

class c_Container :
f_List = []

def Add (self, ref p_Object) :
f_List.append (p_Object)
p_Object = None
# p_Object = Read_Only_Proxy (p_Object)

def Add_Copy (self, p_Object) :
f_List.append (copy.deepcopy (p_Object))


The point of the ref parameter here is not just to allow information
to be passed to the caller from the function - it is to ensure that
the source of the specific parameter passed in gets rebound. The
intention to 'give away' that object would be expressed by the 'ref'
in the call...

l_Container = c_Container ()
l_Object = Get_The_Object ()

l_Container.Add (ref l_Object)

Actually, an 'in' or 'give' modifier might make even more sense here
(very different to C# - I can't imagine a reason for an 'out' modifier
in Python).

Where such problems occur, this is by no means foolproof of course.
For example...

l_Container = c_Container ()
l_Object_Ref1 = Get_The_Object ()
l_Object_Ref2 = l_Object_Ref2

l_Container.Add (ref l_Object_Ref1)

l_Object_Ref2.Mutate_Somehow ()

However, it would probably catch a very substantial portion of real
accidental side-effect errors.
By the way, this is strictly from a user perspective, I trust the Python
developers to overcome the implementation issuses, *if* there is a
significant usability improvement.

And that is the big question.

C# 'needs' ref parameters because it has no convenient way to return
multiple values from a function. Python does not. The question is
really whether this argument about expressing intentions and evading
errors is compelling or not.
 
J

JCM

Stephen Horne said:
1. I pointed out that this is an advantage of the C# system, which I
was proposing to imitate.

: The C# solution uses a modifier keyword, but that keyword must be
: specified in both the function definition *and* the call. For
: instance...

...

: The rationale for this in C#, I assume, is mostly about clarity and
: maintainability - the caller can't be surprised when value type
: parameters are changed in a function as he had to explicitly allow it.


2. You quoted the example I labelled as "(roughly) what I'd like to
be able to do" and ignored the one where I adopted the C#
approach...

I enitirely missed the second half of your original post. Oops.
 
J

JCM

I enitirely missed the second half of your original post. Oops.

And given that I wrote the same pseudo-Python as you without seeing it
or the C# code tells me I agree with your proposal :)
 
E

Erik Max Francis

Stephen said:
Its not an issue of whether the same effect can be achieved in Python.
It's more an issue of whether the method used expresses the
programmers intentions properly.

I agree. And with your suggestion, now every single function call can
potentially change meaning. Given Python's dynamicism, you may not even
know if this particular function call exhibits the behavior. Now
Python's nice, predictable behavior is up for grabs.

If you want to rebinding outside the function, a far better way of
"expressing the programmer's intentions properly," in my opinion, is to
make the behavior as explicit as possible:

class Container:
def __init__(self, x=None): self.x = x
def get(self): return self.x
def set(self, x): self.x = x
def increment(self): self.x += 1 # for example

def Inc(c):
container.increment()

container = Container(1)
Inc(container)
print container.get()
 
P

Peter Otten

Stephen said:
However, it would probably catch a very substantial portion of real
accidental side-effect errors.

It may be a matter of taste, but I think it will cause a *very* substantial
portion of side effect errors. A simple example:

def nested(ref o):
o = ReadOnly(o)

def fun(o):
nested(ref o)
# so glad we can do no harm to o...riginal

x = C()
fun(x)
x.attr = newValue # oops

Note that even in today's Python you can do weird stuff:
.... def __setattr__(self, n, v): raise Exception, "read-only"
....Traceback (most recent call last):
File "<stdin>", line 1, in ?
1

This would at least propagate over the entire calling hierarchy.

To go back to your container example, if copying is costly and only
sometimes necessary, wrap the item into a copy-on-write proxy for every
logically distinct but physically identical instance. That decision should
be explicit rather than hidden as a side effect of a container class.

Peter
 
S

Stephen Horne

I get to the reason I'm rapidly changing my mind on this idea at the
end of this post, so you may want to read the last few paragraphs
first, but...


I agree. And with your suggestion, now every single function call can
potentially change meaning. Given Python's dynamicism, you may not even
know if this particular function call exhibits the behavior. Now
Python's nice, predictable behavior is up for grabs.

I don't agree with this.

If the caller has to specify the behaviour in the syntax they use for
the call AS WELL AS the definition (in both cases using the 'ref'
modifiers) then the call mechanism is 100% explicit and predictable.
If, given Pythons dynamism, you have an function object of the wrong
type (and therefore one which does not support the call mechanism you
are trying to use) then it will fail - just as attempting to do a
conventional function call on a non-function will fail.

That is, suppose I define a function...

def Call_This (p_Function) :
x = 1
p_Function (ref x)

This function doesn't know what type of object it will be called with
- it *should* be a function with a reference argument but it might be
a conventional function, it might be a function with the wrong number
of arguments, or it might not be a function at all.

But it doesn't really matter because I have explicitly specified how I
want to call that object - if the object doesn't support that call
mechanism it simply fails.

So if i write...

def Example_Fn_1 (p) :
None

Call_This (Example_Fn_1)

then an exception will be raised because I provided the wrong type of
function as a parameter. But this is not really any different to what
we should already expect if I write...

Call_This ("oops, this isn't a function")
If you want to rebinding outside the function, a far better way of
"expressing the programmer's intentions properly," in my opinion, is to
make the behavior as explicit as possible:

class Container:
def __init__(self, x=None): self.x = x
def get(self): return self.x
def set(self, x): self.x = x
def increment(self): self.x += 1 # for example

def Inc(c):
container.increment()

container = Container(1)
Inc(container)
print container.get()

Of course this handles the increment example and it handles most cases
quite well, but there are many cases where this is inappropriate.
Putting an object into a mutable wrapper *purely* as a way to allow a
function to rebind the object it needs to rebind is a bad idea - it
means creating extra housekeeping code that (1) obscures the real
application logic, and (2) creates extra opportunities for bugs.

But of course my putting it that way is bogus - in reality, most data
would be in mutable objects (class instances) anyway in real world
programs, and the use of return values (including returning a tuple)
can handle returning any number of output values.

In other words, the following *is* bad...

variable = Wrapper (variable)
Call_Function (variable)
variable = Wrapper.Unwrap ()

But realistically, that wouldn't happen. Rather, you'd have...

variable = Call_Function (variable)

And so we get back to Peter Ottens point - Python doesn't need
call-by-reference (or rather call-by-reference-to-reference) because
it has another way of providing output values - and significantly, one
which allows multiple values to be conveniently returned.

As a fan of many functional techniques and as someone who
instinctively distrusts side-effects, I actually like this. But a
little voice keeps whispering to me "yes, but not always".

Part of it is of course that I still feel it is a wart that, when
passing a mutable object as a parameter, I can rebind any internal
component of that object and it will be visible to the caller - but if
I rebind the object as a whole the change doesn't affect the caller.
Of course we've been through this before, though, and I doubt you want
to revisit the arguments any more than I do.

The most compelling example I have is essentially the side-effect
thing from my reply to Peter Ottens post. As an attempt to express it
more clearly, there are times when you set up an object purely so that
you can store it into a container...

obj = Obj_Type ()

obj.Do_Setup_Stuff_1 ()
obj.Do_Setup_Stuff_2 ()
obj.Do_Setup_Stuff_3 ()

container.Add (obj)

In many cases, the Add function will not take a copy because it seems
pointless. The caller set up the object purely to store it in the
container, and in most cases is going to discard its reference to the
object immediately afterwards. But then there's always the possibility
that the caller might carry on using that object. For instance...

obj = Obj_Type ()

obj.Do_Setup_Stuff_1 ()
obj.Do_Setup_Stuff_2 ()
obj.Do_Setup_Stuff_3 ()

container.Add (obj)

obj.Do_Setup_Stuff_3_Slightly_Differently ()

container.Add (obj)

This probably wouldn't do what was expected - the 'slightly
differently' call changed an object that is also being referenced from
inside the container - an accidental side-effect.

If a 'ref' parameter is used and the 'Add' function rebinds it to
'None', however, we get...

obj = Obj_Type ()

obj.Do_Setup_Stuff_1 ()
obj.Do_Setup_Stuff_2 ()
obj.Do_Setup_Stuff_3 ()

container.Add (ref obj)

obj.Do_Setup_Stuff_3_Slightly_Differently ()
# exception here tells that something has gone wrong

container.Add (ref obj)

Which quickly gets bugfixed to...

obj = Obj_Type ()

obj.Do_Setup_Stuff_1 ()
obj.Do_Setup_Stuff_2 ()
obj.Do_Setup_Stuff_3 ()

container.Add_Copy (obj)

obj.Do_Setup_Stuff_3_Slightly_Differently ()
# no exception as Add_Copy doesn't rebind the parameter

container.Add (ref obj)


Then again, even in this case there are other ways. For instance...

builder = Builder ()

builder.Do_Setup_Stuff_1 ()
builder.Do_Setup_Stuff_2 ()
builder.Do_Setup_Stuff_3 ()

container.Add (builder.Build ())

builder.Do_Setup_Stuff_3_Slightly_Differently ()

container.Add (builder.Build ())

In this case, the builder class can set a 'used' flag after the
'Build' call which tells it that it needs to make a copy before
applying further changes. In that way, both unnecessary copies and
accidental side-effects are avoided while keeping the intention clear
(especially as this is basically one of the classic design patterns
from Gamma et al - though I may be confusing Builder with Factory
Method) and with no changes to Python.

So my 'most compelling example' isn't compelling at all. Damn.

I've been thinking on this for some hours now and still not come up
with a more compelling example (or at least not one which can't be
better handled a different way) so I guess the idea is a dud.

Bet you never expected me to admit that so easy ;-)
 
S

Stephen Horne

It may be a matter of taste, but I think it will cause a *very* substantial
portion of side effect errors. A simple example:

def nested(ref o):
o = ReadOnly(o)

def fun(o):
nested(ref o)
# so glad we can do no harm to o...riginal

x = C()
fun(x)
x.attr = newValue # oops

I think theres a little error here (or you're interpreting the ref
differently to me). Basically...
def fun(o):
nested(ref o)
# so glad we can do no harm to o...riginal

At this point, the parameter 'o' has been rebound to the read only
proxy so no changes can be made to it after this point in the
function, but...
x = C()
fun(x)

'fun' isn't using a 'ref' parameter, so 'x' is not being rebound to
the read only proxy. Therefore...
x.attr = newValue

this will still run, and will still have the accidental side-effect.

To go back to your container example, if copying is costly and only
sometimes necessary, wrap the item into a copy-on-write proxy for every
logically distinct but physically identical instance. That decision should
be explicit rather than hidden as a side effect of a container class.

Maybe, though as you may notice in my reply to Erik Max Francis I'm
rethinking that decision. It can be handled a different way by making
a class responsible for deciding whether to copy or not - e.g. the
Builder class I used in that reply.

Looking at your example above, I see further evidence that the
rationale is false. Basically, it would be too easy to forget to
ensure the 'ref' was used in every method where it was needed - having
the rebinding to a proxy in a private internal method called by the
public methods would give a false sense of security.
 
E

Erik Max Francis

Stephen said:
I don't agree with this.

If the caller has to specify the behaviour in the syntax they use for
the call AS WELL AS the definition (in both cases using the 'ref'
modifiers) then the call mechanism is 100% explicit and predictable.
If, given Pythons dynamism, you have an function object of the wrong
type (and therefore one which does not support the call mechanism you
are trying to use) then it will fail - just as attempting to do a
conventional function call on a non-function will fail.

That isn't what I meant. Look at the following code:

someFunction(thisArgument, thatArgument)

With Python as it stands right now, I know that this call can never
rebind the names thisArgument and thatArgument. It doesn't matter what
someFunction is, it doesn't matter what thisArgument or thatArgument
are. I know it can never happen.

With your proposed change, now whenever I see a function call in code I
don't know whether it's going to rebind names from the caller's side.
It might, it might not. Furthermore, with Python's dynamicism, it might
be hard to tell without running the code (since functions are first
class objects, inspecting the function name may not help).
 
C

Carl Waldbieser

I think you could still run into a problem here with aliasing. For example:

obj = Obj_Type ()
x = obj

obj.Do_Setup_Stuff_1 ()
obj.Do_Setup_Stuff_2 ()
obj.Do_Setup_Stuff_3 ()
container.Add (ref obj) #rebinds obj to None
#later...
x.alter() #alters containers copy anyway

This kind o problem exists in other languages like C++, too. The containers
in the C++ standard library copy elements to side-step these problems. When
copying becomes expensive, pointers to elements are used instead, but since
you can have multiple pointers to the same object, you run the risk of
clobbering data in the container if you are not careful.

In practice, though, this type of behavior has rarely been a problem for me.

Carl Waldbieser
 
P

Peter Otten

Stephen said:
I think theres a little error here (or you're interpreting the ref
differently to me). Basically...


At this point, the parameter 'o' has been rebound to the read only
proxy so no changes can be made to it after this point in the
function, but...


'fun' isn't using a 'ref' parameter, so 'x' is not being rebound to
the read only proxy. Therefore...


this will still run, and will still have the accidental side-effect.

.... and that is the whole point of my example: You can easily bypass the
rebinding in a manner that is hard to find (if fun() and nested() contained
some real code)

Peter
 
T

Thomas Bellman

Erik Max Francis said:
That isn't what I meant. Look at the following code:
someFunction(thisArgument, thatArgument)
With Python as it stands right now, I know that this call can never
rebind the names thisArgument and thatArgument. It doesn't matter what
someFunction is, it doesn't matter what thisArgument or thatArgument
are. I know it can never happen.
With your proposed change, now whenever I see a function call in code I
don't know whether it's going to rebind names from the caller's side.
It might, it might not. Furthermore, with Python's dynamicism, it might
be hard to tell without running the code (since functions are first
class objects, inspecting the function name may not help).

No, you *would* know. The above call would *not* be able to
rebind any of thisArgument or thatArgument. In fact, if
someFunction() is defined with a ref parameter, the call would
*fail*, raising an exception. Just like calling it with the
wrong number of parameters would.

For someFunction() to be able to rebind, e.g, thisArgument, there
are *two* prerequisites:
1. someFunction() must be defined as 'def someFunction(ref a, b)'.
2. the *call* must be 'someFunction(ref x, y)'.
*Both* these must be met. If only one of them is met, the call
will fail.

Here's a sample session of what would happen under Stephen's
model:
... x = 17
... ... x = 23
... Traceback (most recent call last):
Traceback (most recent call last):
17

(For the record, I do not support Stephen's proposal, nor any
other kinds of call-by-reference in Python. For one, I don't
think it meshes well with the rest of Python, and moreover, I
have yet to encounter a real-world example where this would
actually make code more readable - and I have been using Python
for eight years now, and Lisp (which has similar call semantics)
for a few years before that.)
 
S

Stephen Horne

That isn't what I meant. Look at the following code:

someFunction(thisArgument, thatArgument)

With Python as it stands right now, I know that this call can never
rebind the names thisArgument and thatArgument. It doesn't matter what
someFunction is, it doesn't matter what thisArgument or thatArgument
are. I know it can never happen.

With your proposed change, now whenever I see a function call in code I
don't know whether it's going to rebind names from the caller's side.
It might, it might not. Furthermore, with Python's dynamicism, it might
be hard to tell without running the code (since functions are first
class objects, inspecting the function name may not help).

Wrong.

That statement will behave exactly as it always did, and CANNOT rebind
thisArgument or thatArgument even if my suggestion were implemented.
The CALLER has to EXPLICITLY allow the rebinding by using the ref
flags IN ADDITION TO specifying it in the function definition, as is
done in C# - that was the whole point.

With this call, the first argument may be rebound but not the second
(assuming the function was written to accept the arguments specified
that way).

someFunction(ref thisArgument, thatArgument)
^
|
Note this explicit
modifier in the call

However, I am still retracting the suggestion for reasons I have
already covered.
 
S

Stephen Horne

I think you could still run into a problem here with aliasing. For example:

obj = Obj_Type ()
x = obj

obj.Do_Setup_Stuff_1 ()
obj.Do_Setup_Stuff_2 ()
obj.Do_Setup_Stuff_3 ()
container.Add (ref obj) #rebinds obj to None
#later...
x.alter() #alters containers copy anyway

Yes - that's what I meant by "this is by no means foolproof of course"
in my post with message ID (e-mail address removed).
This kind o problem exists in other languages like C++, too. The containers
in the C++ standard library copy elements to side-step these problems. When
copying becomes expensive, pointers to elements are used instead, but since
you can have multiple pointers to the same object, you run the risk of
clobbering data in the container if you are not careful.

Its not unusual to use a reference counting scheme to restore the
apparant copy semantics while avoiding unnecessary copying, but of
course you are correct.
In practice, though, this type of behavior has rarely been a problem for me.

Yes - if I trim down your tail quoting somewhat...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top