4 ms·
Here's a situation I ran into recently: * ClassA conforms to a protocol that allows it to return its description as a string * The protocol includes a regular
by archagon 4y ago
Here's a situation I ran into recently:
* ClassA conforms to a protocol that allows it to return its description as a string
* The protocol includes a regular `description` function as well as an optional `debugDescription` function
* An object conforming to this protocol can be passed to a global logging function, which then calls `description` or `debugDescription` depending on whether the debugger is attached or not
* ClassA's state is protected by a lock
* ClassA's description implementation goes through its state and converts it to a string representation
* Accordingly, ClassA's description implementation needs to also be locked
* The global logging function can be called from within ClassA's state lock, and can take the current instance of ClassA as a parameter
The recommended approach of making `description` call `description_underLock` doesn't work, because the logging function decides whether to invoke `description` or `debugDescription` depending on the context. In other words, if the logging function is called from inside the state lock with `self` as an argument, then we'll get a deadlock if we don't manually invoke `description_underLock`; but if we directly give the logging function the string from `description_underLock` or `debugDescription_underLock` instead of `self`, we now have to replicate the internal logic of the logging function in our layer. Alternatively, we can impose conditions such as "never log `self` from within the state lock," but that feels arbitrary and restrictive.
I think recursive locks make sense in this case, and probably other cases where protocols and/or indirection is involved. We just have to make sure that our description implementation is dead simple (mostly a "leaf node" function) and doesn't have side effects.