The CL condition system (and similar stuff in Smalltalk) demonstrates how CL is a programming system and not just a programming language. Conditions in a single program tend to have limited usefulness, but in the scope of a larger environment (read: many programs interacting) they can be remarkably useful.
Whenever I see CL’s condition system it seems to me that we could achieve the same effect by passing handlers as lambdas to a computation. Or, in the case of an OO language, creating an object for the computation and parameterizing its construction with strategy objects as the handlers.
Then, I wonder why people don’t do either of those that often.
Then, I wonder why people don’t do either of those that often.
Because it’s a frigging lot of work. And also because eventually a user will want a hook that you didn’t provide, or a hook with a different shape from the one you provided, and then refactoring your code to accomodate their use case will cause you a world of pain.
The solution as a library author is to say no to inversion of control, and write first-order procedures that do one simple thing at a time. Whenever you would normally use a higher-order procedure (aka “higher-order functions” or “methods taking strategy arguments”), do the following instead:
Identify the points at which the higher-order procedure calls a procedure argument.
Reify the state of at those points as custom data structures.
Instead of calling a procedure argument, return the current state immediately.
Write another procedure that resumes the continuation with the result of the procedure argument.
This gives your users the freedom to handle the continuation however they want, without force-fitting square pegs into round holes. I am firmly convinced now that the only legitimate use case for first-class procedures is implementing custom control flow, e.g., laziness and concurrency.
The CL condition system (and similar stuff in Smalltalk) demonstrates how CL is a programming system and not just a programming language. Conditions in a single program tend to have limited usefulness, but in the scope of a larger environment (read: many programs interacting) they can be remarkably useful.
Whenever I see CL’s condition system it seems to me that we could achieve the same effect by passing handlers as lambdas to a computation. Or, in the case of an OO language, creating an object for the computation and parameterizing its construction with strategy objects as the handlers.
Then, I wonder why people don’t do either of those that often.
Because it’s a frigging lot of work. And also because eventually a user will want a hook that you didn’t provide, or a hook with a different shape from the one you provided, and then refactoring your code to accomodate their use case will cause you a world of pain.
The solution as a library author is to say no to inversion of control, and write first-order procedures that do one simple thing at a time. Whenever you would normally use a higher-order procedure (aka “higher-order functions” or “methods taking strategy arguments”), do the following instead:
This gives your users the freedom to handle the continuation however they want, without force-fitting square pegs into round holes. I am firmly convinced now that the only legitimate use case for first-class procedures is implementing custom control flow, e.g., laziness and concurrency.