-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Poor terminology around reference ownership #11
Comments
Could you elaborate? |
The caller always outlives the callee, so it can lend a reference to the callee. However, the callee cannot lend anything to the caller as it cannot own anything once it no longer exists. |
Yup. For example, if you call |
IIUC "borrowed" is only used for return values, e.g. " These concepts, by whatever name, are occasionally useful, when an API is intended to transfer ownership (stealing) or not (borrowing). If we picked a neutral term that applies to both cases, we'd end up stating that most calls that return an object return a new reference, which is then owned by the caller, whereas most calls that take an object as argument don't change the ownership from the caller's POV. Given the intentional asymmetry in the defaults here I'm not sure that picking a neutral term is actually better. And given that we probably should strive to make all public APIs use the default behavior (i.e., neither borrowing nor stealing) I'm not sure that we need to find replacement terminology. For internal APIs (e.g. |
That's a good rule of thumb, but IMO there are many legitimate exceptions. |
We still need a name for the default behavior. "default" doesn't convey any information to the reader. We also need to decide whether to describe the behavior from the point of view of the caller or the callee. |
We will probably be able to keep the term "borrowing", since that's now widely used in other languages (esp. Rust, but I predict other languages will also be talking about "borrow checking"). Agreed that "stealing" is pejorative; "takes a reference" might work? |
"transfers ownership" could be a good way to describe the semantics |
So the default behavior would be
|
“Transfers ownership” is good in general! I'd like to keep using “borrow”, but if you use it you should always explicitly say what is being borrowed from. So
For transferring ownership of an argument, perhaps give? It's not perfect, but short: |
Rust uses the term "move" to describe transfer of ownership. This might also be familiar to C++ readers. |
Honestly I've always wondered what C++ "move" semantics are for. So I think it's not a great term. It's mostly convenient there because it has the same number of letters as "copy" and contrasts nicely -- buy we don't talk about copying references either in CPython. |
I was always very confused about such code pattern:
Who owns startkey strong reference? Is it PyObject_RichCompareBool()? Is it the callee? Why is startkey treated differently that key which is also a I proposed adding a If I understood correctly the code, the problem is that startkey is a borrowed reference, whereas key should be a strong reference. Is key really a strong reference? Well, I didn't copy/paste the full code to show how much confusing it is if you cannot check the "context" of the code: where references come from, how object reference count is handled, etc. |
What is your point about not copy/pasting the full code? The answer to your question "who owns startkey" in dictobject.c is literally on the line before (where it is taken out of the container data structure). In setobject.c it is a bit farther up, because there are a bunch of guards that check whether startkey is usable. |
My point is that when I just look at the My concern is that to me, it's unclear if PyObject_RichCompareBool() must be called with strong references or if passing borrowed references is safe. Well, apparently it's unsafe. Is there a guideline saying when it's safe or not? Is it on a case by case basis? Can a case change if a function implement changes (if it didn't call arbitrary Python code, and then it does)? I mean that I don't understand what "borrowed reference" means when passing a Python object to a function. In general, it looks unsafe. But sometimes, if you are lucky, it's safe :-) |
(I suspect I'm falling into a trap you've carefully designed to show some logical fallacy. So be it.) I think the only safe guideline is that the caller should always have a strong reference to each object passed as an argument into an API function. In most cases this isn't a problem -- I don't think this is something specific to The problem occurs when you aren't sure you have a strong reference -- e.g. if you received an object from In the examples you quote, Note that I subtly distinguish between owning and having a strong reference. If you own it, you must eventually give up ownership (decref) or transfer it (e.g. by returning it, or inserting it into a mutable data structure that "borrows" the reference, like |
Proposed guideline issue: capi-workgroup/api-evolution#25 tldr of the current proposal, as it applies to the discussion here:
|
That's a misleading term. IMO it's closer to C++ |
I don't think we should use terms with negative connotations for legitimate operations. IMO, the wording should reflect what's being done (move/transfer). |
So function that "steal" arguments we can name For functions that return a "borrowed" argument I'm less sure. I don't think of "borrow" as a pejorative word. The concepts do not feel symmetric (the caller does not "steal" a reference -- it's the callee that does something unusual). |
Concrete example: I propose to make Do |
It does to me, but let’s leave this up to the whole WG, if it gets established. |
It's a legitimate operation, but it does go against the usual convention. Frankly, I don't see how
|
Example of documentation currently using "steal" term:
For me, it's even more surprising when the negative form is used. Example:
|
Sorry, I thought this issue was about the terminology we use [in the docs], not about C API naming. |
Oh dear. My miscommunication-spider-sense didn't catch that! :-) Yeah, let's use the less loaded terms in definitions and discussions, but I'm fine with using the (traditional) "steal" in API names. Still not sure what to use for API names that return a borrowed reference; I don't believe we have that word in any API name currently. |
But, IMO,
True, but we practically don't have In capi-workgroup/api-evolution#25, I propose to use |
The evolution names are discussed over at capi-workgroup/api-evolution#23 and capi-workgroup/api-evolution#21. Perhaps the C API naming should continue over there? The revolution naming does not have an issue yet; perhaps the closest would be capi-workgroup/api-revolution#9? |
IMO, the we're deciding on the desired “target” ; the terms should be the same regardless of whether we approach it gradually or do grand rename (modulo some API-wide prefix for the latter case). |
Going through this again, I see that it's possible clear wording with something like But, I would still like to use “steal” in docs of existing API that doesn't have it in the name. |
Currently we use the terms "borrowed" and "stolen" to describe references, both passed those passed as arguments, and those returned.
Returning a "borrowed" reference is fundamentally different to passing a "borrowed" reference as an argument. Using the same term is confusing.
The term "stolen" is needlessly pejorative, which distracts from the semantics.
The text was updated successfully, but these errors were encountered: