Used to encapsulate the results from a complex computation. See ResultObjectPattern
for the long description; the discussion follows.
Kent- I'm trying to figure out if I have a pattern here. Sometimes when you send a message to an object, the resulting computation is complex or important enough that you'd like to keep track of it, either to examine the computation or to archive/log it.
>gtrun returns a TestResult
, which records when the run started and stopped and which TestCase
s failed to run correctly.
I can imagine a complex database query doing similar work, or a compiler optimizer.
Anyway, if you have another example, or a refutation, or if you want to take a crack at writing the whole pattern, feel free to do it here.
From Patrick Logan: Ok, I'll try this experiment...
The only thing I can add at this point is to make explicit the apparent relationship between ResultObject
and Kent's earlier ParametersObject?
(was that the name?) from the PatternsMailList?
(is there a page by a different name for this already?)
I think this is pattern (but then I liked ParametersObject?
too). I think there are a bunch of uses for ResultObjects?
- FutureObject? --- packing up the result of a parallel computation (used in DistributedSmalltalk)
- LazyObject --- packing up the result of a CoRoutine
- MultipleValueObject? --- packing up multiple return values. This is mentioned in the SelfLanguage programmers reference manual. I'm not sure whether these should be separate patterns, whether they are just uses of ResultObject, or whether both ResultObject and ParametersObject? should really be instances of a more general DynamicObject? pattern. But I think there is a relationship there.
When I think about a ResultObject
I think about results in terms of persistence. When an object is a part of a system as a persistent value, it can be self optimizing. It stays up to date with the overall state of the system and when you ask for its result it can yield it with the least amount of effort. Bandaged together systems often have certain results that are costly to get because they were not designed to be persistent.
I think that if there is a pattern, ResultObject
, then it is really a question of whether you can generalize the notion of a persistent system object that is self optimizing. What kind of system do you need to architect that would allow you to easily incorporate many ResultObject
values with each being integrated into the system and self optimizing.
An application I'm currently working on uses the ResultObject
pattern for the specification of error information. When an action cannot be completed somewhere deep in the system rather than displaying an error to the user at that point an ErrorObject?
(possibly using FlyweightPattern
, see DesignPatterns
p. 195) is generated which represents the error that occurred. These error objects are saved in a queue so that they can be presented to the user at a later time. The main benefit of using the object rather than simply queuing error strings is that we can defer reading error message strings from disk (or possibly never retrieve them from disk in that case that other parts of the system automatically recover from the error and the error messages need never be displayed to the user).
The current implementation of ErrorObject?
in our system supports a GetErrorString?
method, as well as a DisplayHelp?
method for conveying a more in-depth explanation of the error for the user. One can envision additional helpful methods to support various forms of error recovery processes.
The discussion of ResultObject
so far seems to conceive of it as an entity that gets generated at the termination of the computation. It seems to me that it would be useful for the ResultObject
to come into existence immediately. It could then be used to examine intermediate results or perhaps provide a convenient means of cancelling the computation (so there needs to be a linkage between the ResultObject
and the ComputationObject?
whose results it is capturing).
I implemented a similar scheme about two years ago inside an expert system. The system included a rule-based engine; when called, it would examine a node inside a network and determine whether the node was close to capacity and needed to be resized. We used a ResultObject
to hold all the decision logic for the particular node, and the folks who used the system would read this decision logic to verify that decisions were being made appropriately.
I've finally taken Kent's bait, and tried my hand at writing up ResultObject
as a pattern. Have a look at the ResultObjectPattern
and let me know what you think!
Here are some thoughts that might relate to the result object:
Sometimes when a ClientObject?
requests a service from a DomainObject
, the request might be denied for some reason known only to the domain. There might be a variety of reasons, some of which the user could overrule and some of which are absolutely prohibited. One approach to handling this in a decoupled way would be to return something that might be called a "ReturnObject?
" which would convey (1) the success or failure of the request, (2) an action to be performed if the requestor chooses to overrule (if appropriate) along with the performer of that action, (3) an indicator (symbol etc) of the problem that occurred if any, and (4) the requested object if applicable.
So, what do you think? Does this have relevance to the ResultObjectPattern
I think the above has relevance, so let me go ahead and raise the question. What's the difference between a ReturnObject?
and a ResultObject
? Is one just a special case of the other?
As soon as I read the comments about Persistence, this also began to smell a little like VersionedObjects?
. Does it make sense that snapshots of the state of a long computation could be isomorphic to a version tree for an object? Or am I really
barking up a wrong tree? :-)
Potentially an AntiPattern
. Don't use a ResultObject
to return OutOfBand
data. Throw an appropriate exception.