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

Carl Waldbieser waldbie at attglobal.net
Thu Sep 11 06:45:38 CEST 2003


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


> 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 ;-)
>






More information about the Python-list mailing list