Is there a name for this software principle?
August 29, 2018 7:44 PM   Subscribe

Is there a name for the software principle that paired actions should occur at the same level/module?

Allocating and deallocating memory, opening and closing a file, or acquiring and releasing a lock should happen in the same module or layer of a system. For example, if I write a library that returns widgets with a function like create_widget and the memory for said widget is malloced, there should be a destroy_widget that calls free rather than have the consumer call free directly.

This seems to be a widely-agreed upon good practice. RAII is a related concept, but it's not the principle itself. I can't seem to find a name for the principle. Is there one?
posted by Cogito to Computers & Internet (16 answers total) 2 users marked this as a favorite
Your examples reminded me of the anti-pattern action at a distance, which led me to the Law of Demeter, single responsibility principle, and the familiar principle of least astonishment.
posted by Wobbuffet at 8:07 PM on August 29, 2018 [2 favorites]

"Symmetry" might be the best description, if you are going to allocate the resource, have a single place to deallocate it as well. And make sure all control paths lead back to that same closure.
posted by nickggully at 8:56 PM on August 29, 2018

Reminds me of "A Programming Idiom You've Never Heard Of"
posted by Phssthpok at 9:45 PM on August 29, 2018 [1 favorite]

In the examples you gave, it is related to lifetime management or object ownership. Occurring in the same level is not strictly necessary, so long as ownership of objects and their lifetimes is properly handed over throughout the software stack.
posted by RobotNinja at 10:13 PM on August 29, 2018

The principle I'm asking about is occurring on the same level. You could certainly have the contract of create_widget be that users call free for themselves, and it would 100% work. I'm just looking for the name of the principle that says that's a bad idea generally.
posted by Cogito at 10:26 PM on August 29, 2018

I think information hiding is probably the closest thing to a name for this. If other code doesn't need to know how the "widget" module works, these workings ought to be hidden behind the widget interface.
posted by panic at 12:50 AM on August 30, 2018

This technique of pairing enter and exit, or open and close, at the same level, is known as nesting.
posted by cyanistes at 1:15 AM on August 30, 2018 [1 favorite]

You could certainly have the contract of create_widget be that users call free for themselves, and it would 100% work. I'm just looking for the name of the principle that says that's a bad idea generally.

Bitter experience?
posted by flabdablet at 3:56 AM on August 30, 2018 [7 favorites]

I'd frame it as locality rather than symmetry. Do as much related stuff together at nearby location, scope, and time to avoid confusion.
posted by b1tr0t at 6:58 AM on August 30, 2018

If we were inventing a term ‘locality’ would definitely be high on my list. I’m still trying to come up with an existing name other than Principle Of Least Surprise.
posted by Tell Me No Lies at 7:15 AM on August 30, 2018

In my mind this is a memory ownership pattern. When building C libraries you have to decide which memory ownership pattern to stick to: caller ownership of memory, or callee ownership of memory/resources. Alternatively, you could distinguish between managed and unmanaged resources. If having the caller manage the underlying resource is considered dangerous or a mistake, then a managed resource pattern is used. If the point is to give the callee direct access to the memory/resource, then a callee-ownership/unmanaged resources pattern is used.
posted by dis_integration at 8:48 AM on August 30, 2018

So perhaps the reason there's no widely used term (never heard of nesting used in this context) is that it's sort of the combination of locality and consistent ownership semantics. Even if you weren't risking a leak, a function to modify the object should be located as close to the function to create it as possible. Conversely, no matter where something is created, the deletion should be consistent with the creation. So both principles apply, but they're orthogonal in this case.
posted by wnissen at 9:33 AM on August 30, 2018

This bumps up against the notion of Connascence, but isn't quite there. Still, that might provide some guidance.
posted by dws at 10:22 AM on August 30, 2018

Looking at Python, there is the with statement:
In that document the term "Reliable Acquisition/Release Pairs" is used.
posted by bdc34 at 11:02 AM on August 30, 2018

Perhaps related bits of taxonomy: friction or asymmetry of interaction.

The first one would probably be most useful when describing why an API like that is bad "it's a high friction API". The second is the best I can come up with for describing the phenomenon itself: your API in question is very asymmetrical in terms of its usage.

A good API should be low friction (i.e. difficulty of interaction scales linearly or better with complexity of task being performed) and symmetrical in usage (caller allocates, or lib allocates, but whoever allocs handles freeing as well.)
posted by -1 at 3:29 PM on August 30, 2018

I think on reflection I'd suggest it's covered by several principles at once:
  1. Modules should be loosely coupled. If one module creates widgets but another module destroys them, those modules seem pretty interdependent--particularly if a widget has some complicated teardown, requiring the destroyer to know implementation details. This may actually cover all the examples.
  2. Modules should be cohesive. Their methods should have some kind of obvious functional relationship to each other akin to creating/destroying widgets. In the examples given, destroying widgets is unlikely to resemble the other functions of the calling module.
  3. Modules should have one responsibility with respect to which other modules generally defer without needing to know the details. If that's widget management, maybe the whole analysis stops there, though I can imagine the weird and aberrant case of a module that creates all the things and a module that destroys them--loose coupling excludes that more clearly.
  4. Modules should be unsurprising.
That said, I'm not sure there is a principle saying paired actions should happen at the same level, because I think people do sometimes put a teardown action directly on objects instantiated by a factory. No idea who has opinions about that, but it doesn't strike me as forbidden by any of the principles above.
posted by Wobbuffet at 6:08 PM on August 30, 2018 [1 favorite]

« Older Can I somehow see the math behind a web game in...   |   So I opened the attachment, now what? Newer »
This thread is closed to new comments.