Out parameters are a useful language feature for multiple results, particularly when the language in question doesn't have tuples as a first-class feature. Even though Java omitted pass-by-reference (meaning both
out in Delphi parlance), C# did not follow its lead and includes both parameter-passing semantics. And so it follows that the .NET method System.Int32.TryParse(String,Int32&) is possible in C#, but not in Java.
The API works well enough when you want to put the extra return value(s) into local variables or visible fields. What about times when you want to put the return value into a property, though? Since you can't (generally) take a reference to a property, you have to manually create a local variable, pass the local variable by reference, and then, in a separate statement, assign the variable to the property.
Anonymous methods can provide an "out" here, if you'll pardon the pun. By passing a setter instead of a mutable reference, you can escape from this constraint. Here's are two overloaded
ReadLine functions, one using the
out mechanism, the other using the setter pattern:
function ReadLine(const Prompt: string; out Dest: string): Boolean; overload; var line: string; begin Write(Prompt, '> '); Flush(Output); Readln(line); Result := line <> ''; if Result then Dest := line; end; function ReadLine(const Prompt: string; const Setter: TProc<string>): Boolean; overload; var line: string; begin Write(Prompt, '> '); Flush(Output); Readln(line); Result := line <> ''; if Result then Setter(line); end;
As can be seen, the code that uses setters versus out parameters is little different. (It would be more different in a language that requires definite assignment, like C#, as otherwise we would have to set Dest to some value in the case of no entry.)
The real difference is in the usage point of this idiom. (And don't forget, this is an idiom; it might look odd the first time you see it, but when you understand anonymous methods, or even just the idiom, it's a trivial pattern and easy to understand.) Here's the definition of a class with a couple of properties, and a couple of functions. The first uses the
out idiom, and the second uses the setter idiom:
type TFrob = class private FFoo: string; FBar: string; public property Foo: string read FFoo write FFoo; property Bar: string read FBar write FBar; end; // Using 'out' idiom - requires separate assignment statement function WorkWithFrob: Boolean; var frob: TFrob; temp: string; begin frob := TFrob.Create; try if not ReadLine('Give me Foo', temp) then Exit(False); frob.Foo := temp; if not ReadLine('Give me Bar', temp) then Exit(False); frob.Bar := temp; Writeln(Format('Your foo is %s and bar is %s', [frob.Foo, frob.Bar])); Result := True; finally frob.Free; end; end; // Using 'setter' idiom - can be done inline function WorkWithFrob2: Boolean; var frob: TFrob; begin frob := TFrob.Create; try if not ReadLine('Give me Foo', procedure(x: string) begin frob.Foo := x; end) or not ReadLine('Give me Bar', procedure(x: string) begin frob.Bar := x; end) then Exit(False); Writeln(Format('Your foo is %s and bar is %s', [frob.Foo, frob.Bar])); Result := True; finally frob.Free; end; end;
This idiom isn't useful very often, but when the right situation comes up, it's really quite nice to have, especially when you need persistent references to properties - e.g. when you need to store the reference in some structure somewhere, and update it with different values over time.
Viewed more generally, anonymous methods / method references can act as kinds of pipes that join up producers and consumers of data, with getters (TFunc<TResult>) for consumer-pull and setters (TProc<TArg>) for producer-push.