Author ncoghlan
Recipients jcon, kermode, mark.dickinson, ncoghlan, petri.lehtinen, pitrou, pv, rupole, skrah, teoliphant
Date 2011-06-28.00:58:23
SpamBayes Score 2.77556e-16
Marked as misclassified No
Message-id <1309222705.19.0.199391578033.issue10181@psf.upfronthosting.co.za>
In-reply-to
Content
memoryview.release() will raise an exception if you call it when the underlying PyManagedBuffer instance has a refcount > 1. So the explicit memory management still works, and if you mess it up by leaving dangling references around you'll run the risk of getting an exception (CPython will mostly cleanly things up for you due to the refcounting, but we're well used to CPython users getting away with that kind of bug and being surprised when they port to a fully garbage collected implementation like PyPy, IronPython or Jython).

It isn't pretty, but it's the most practical way to cope with the lifecycle issues. The other alternative is to obediently force release of the buffer and then throw exceptions on subsequent *access*, the way we do with files. I'm less in favour of that approach, since it results in additional runtime overhead as you have to keep checking the state validity and I think it generates the exception in the wrong place - the exception should be triggered where the implicit assertion that "all other references are gone and this object should be released right now" has been violated, not at some later random location where the object happens to be used. (I'm also swayed by the backwards compatibility argument: we can easily move from "refcount must be 1" enforcement to the laissez-faire approach used by files. You can't go in the other direction without the potential to break working code)

The reason redirecting all requests to the underlying object doesn't work is because repeated calls to getbuffer on mutable objects are allowed to return *different* answers. Assume we have a mutable array type that allows changes while memory is exported by keeping the old buffer around until all references are released. Then we want the following behaviour:

  a = mutable_byte_array(100) # 100 byte array
  m1 = memoryview(a) # View of original 100 byte array
  a.resize(0) # Array is now zero length, but old buffer is still valid
  m2 = m1[:]
  m3 = memoryview(m1)
  # Both m2 and m3 should provide access to the *original* 100 byte
  # array, not to the now empty *current* array
  # Having len(m2) and len(m3) differ from len(m1) because the
  # original source array had changed would be incredibly confusing
  # When m1, m2 and m3 all go away then the original array will be
  # released

The builtin bytearray avoids this issue by simply disallowing mutation while a buffer is exported, but memoryview needs to cope with arbitrary third party objects which may behave like the hypothetical mutable_byte_array().
History
Date User Action Args
2011-06-28 00:58:25ncoghlansetrecipients: + ncoghlan, teoliphant, mark.dickinson, rupole, kermode, pitrou, pv, skrah, jcon, petri.lehtinen
2011-06-28 00:58:25ncoghlansetmessageid: <1309222705.19.0.199391578033.issue10181@psf.upfronthosting.co.za>
2011-06-28 00:58:24ncoghlanlinkissue10181 messages
2011-06-28 00:58:23ncoghlancreate