Pharo/Smalltalk中带块参数键值消息及Promise类then:catch:实现问询
then:catch: in Pharo/Smalltalk Let's walk through building this custom Promise implementation that accepts blocks as arguments via the then:catch: message. We'll cover everything from defining the class to testing your example code.
Step 1: Define the Promise Class
First, create a new class in the Pharo System Browser with the two mutually exclusive instance variables we need—only one will hold a value at any given time:
Object subclass: #Promise instanceVariableNames: 'promiseValue promiseError' classVariableNames: '' package: 'Your-Custom-Package'
Step 2: Add the promiseValue Method to BlockClosure
We need to extend BlockClosure so any block can spawn a Promise instance when sending the promiseValue message. This method runs the block, captures its result (or any thrown exception), and sets the appropriate Promise instance variable:
BlockClosure >> promiseValue | promise | promise := Promise new. [ promise promiseValue: self value ] on: Exception do: [ :ex | promise promiseError: ex ]. ^ promise
We also need setter methods for the Promise's instance variables to enforce mutual exclusivity:
Promise >> promiseValue: anObject promiseValue := anObject. "Clear error to maintain mutual exclusivity" promiseError := nil Promise >> promiseError: anException promiseError := anException. "Clear value to maintain mutual exclusivity" promiseValue := nil
Step 3: Implement the then:catch: Method
This is the core method that handles success and failure blocks. It checks which instance variable is populated and executes the corresponding block:
Promise >> then: successBlock catch: failureBlock promiseValue ifNotNil: [ ^ successBlock value: promiseValue ]. promiseError ifNotNil: [ ^ failureBlock value: promiseError ]. "Optional: Handle pending state if you plan to support async execution later" ^ self error: 'Promise is in pending state'
Step 4: Test Your Example Code
Now let's run the example you provided to verify it works:
promiseObject := [10/0] promiseValue. promiseObject then: [:result | Transcript crShow: result] catch: [:failure | Transcript crShow: failure]
When you execute this, the block [10/0] will throw a ZeroDivide exception. The Promise will catch this exception, set promiseError, and the catch: block will print the exception details to the Transcript.
Key Details to Note
- Mutual Exclusivity: Our setter methods ensure that setting either
promiseValueorpromiseErrorclears the other—this enforces the "only one initialized at a time" rule. - Error Handling: The
promiseValuemethod wraps the block execution in an exception handler to catch any errors that occur. - Pending State: The current implementation throws an error for uninitialized (pending) promises. You could extend this later to support asynchronous operations by storing blocks to execute once the promise resolves.
内容的提问来源于stack exchange,提问作者Gakuo

