From: Bruce S. <Bru...@nc...> - 2004-08-22 20:38:48
|
I ran Jonathan's test routine in pre-Boost and Boost versions of VPython. In the pre-Boost version the behavior is NOT what Gary and Jonathan describe. In the pre-Boost version the two forms of the update statement work exactly the same in Jonathan's test routine. The original Visual deliberately did something like this: sphere(pos=a) was treated as though it were written as sphere(pos=vector(a)) The intent was to avoid many of the problems that caught Gary, using the trick that Jonathan describes. I can't pretend to be able to see through all aspects of this issue, but my first instinct is to make the latest Visual do what the original one did, both because it avoids some subtle problems for users and because the change has presumably broken some working programs somewhere. Comments? Bruce Sherwood gp...@ri... wrote: > All, > > I have a visual python program whose behavior changes > when I alternately comment and uncomment these two lines: > > s.v += (force / s.mass) * dt > s.v = s.v + (force / s.mass) * dt > > where s is a sphere instance and... well, see below. > > I thought this was odd, so I asked Jonathan to take a look. > He did, and: > > Gotme! (as in Gotcha!) > > Jonathan's reply to me is reproduced below. There are some > good lessons here. I think there are three: 1.) the reference > vs. value feature, 2.) a += b is not entirely equivalent to a = a+b, > 3.) defualt arguments in function defs are built into the function > object when the function is defined, not when it is called. > > The refernce to MakeMass() is a reference to my program. I *think* > Jonathan's explanation is clear enough on its own without having to know > exactly what's inside MakeMass. > > regards, with thanks to J.B., > -gary > > ---------------------------- Original Message ---------------------------- > Subject: Re: incrementing vectors "problem" > From: "Jonathan Brandmeyer" <jbr...@ea...> > Date: Wed, August 18, 2004 5:09 pm > To: gp...@ri... > -------------------------------------------------------------------------- > > >>On Wed, 2004-08-18 at 09:28, gp...@ri... wrote: > > >>This is a work in progress. There must be a coding problem somewhere >>(there are a number of changes in the works) but I'm stuck at this > > spot. >If you can just run it and let me know if they are the same or > different >for you, I'll have some idea about what I should do next. > (I'm not asking >you to debug my code!) > > I was sufficiently perplexed that I did debug your code. You have been > burned by reference vs. value semantics. > > Consider the following code: > from visual import * > spheres = [] > velocity = vector(0,0,0) > spheres.append( sphere( v=velocity)) > spheres.append( sphere( v=velocity)) > spheres.append( sphere( v=velocity)) > spheres.append( sphere( v=velocity)) > > twice = 2 > while twice: > print "before iteration:" > for i in spheres: > print i.v > > ctr = 0 > for i in spheres: > print ctr > ctr += 1 > print "before:", i.v > i.v += vector(.01, .01, .01) > # i.v = i.v + vector(.01, .01, .01) > print "after", i.v > > twice -= 1 > > Run it, and be surprised. The problem is that when each sphere is > created, its 'v' attribute is a reference to the single vector pointed to > by 'velocity'. So, when the loop runs with += expressions, each of them > is changing the single global vector 'velocity', but when it is run with > 'x = x + y' expressions, on the first iteration, each 'v' attribute is > reassigned to a new, unique vector: the returned result of the > addition. > > What is the fix? Whenever you want a true copy, you can invoke the "copy > constructor" for a vector to break the reference cycle: > velocity = vector(0,0,0) > v = vector(velocity) > > Note that all of the visual objects' vector attributes underlying "set > functions" do essentially the same thing. > > Actually, there is one additional piece of information that is specific to > your code. In your case, the common vector was the default value for the > 'velocity' argument in the MakeMass() function. When the > interpreter passes the closing line of the function definition, it creates > a callable object, named "MakeMass", and that object has a single copy of > any default arguments within it. Every time MakeMass's __call__() member > function is invoked without one of the arguments for which there is a > default, that parameter is replaced with a reference to the single > instance of the default value that was created when MakeMass was created. > > I know its a damned subtle problem, but those are Python's semantics. > > HTH, > -Jonathan > > > > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Visualpython-users mailing list > Vis...@li... > https://lists.sourceforge.net/lists/listinfo/visualpython-users |