Agh, that subject header was a mouthful. The code examples should make this proposal pretty clear, though. Basically: Swift's system of getting rid of NSError ** parameters and turning them into something easier to deal with is great. I'd like to propose doing something similar with reference parameters; if a reference parameter is marked "out" in the header, thus guaranteeing that it is only for returning a value and that its initial value doesn't matter, we can eliminate the parameter and move it to the actual return value. If the Obj-C method already has a return value, we can make it a tuple. So, something like this (assuming nonnull):
- (NSString *)foo:(out NSString **)bar;
becomes something like this:
func foo() -> (String, String)
The Obj-C return value, if there is one, would always be the first element in the tuple, accessible via .0. For methods using the common Obj-C naming conventions for methods that return values by reference, the other elements in the tuple could be named. In this case, "get<name>" would remain the name of the method, but additional by-reference parameters and their names could be removed from the method name completely and moved to the return tuple. In both cases the argument label could be used to determine the name, like so:
- (void)getFoo:(out NSString **)foo bar:(out NSString **)bar;
- (NSString *)fooWithBar:(NSString *)bar baz:(out NSString **)baz;
- (NSString *)fooAndReturnBar:(out NSString **)bar;
become:
func getFoo() -> (foo: String, bar: String)
func fooWithBar(bar: String) -> (String, baz: String)
func foo() -> (String, bar: String)
Methods that have void returns (or which have Boolean returns and an error parameter, which Swift will turn into a void return) don't even need a tuple:
- (void)foo:(out NSString **)bar;
becomes
func foo() -> String
Furthermore, something like -[NSURL getResourceValue:forKey:error:], once the "out" keyword is added to its declaration, becomes this:
func getResourceValueForKey() throws -> AnyObject?
so that instead of this rather Byzantine-looking construction:
var sizeObj: AnyObject? = nil
try url.getResourceValue(&sizeObj, forKey: NSURLFileSizeKey)
if size = sizeObj as? NSNumber {
// do something with size
}
you could just do this:
if let size = try url.getResourceValueForKey(NSURLFileSizeKey) as? NSNumber {
// do something with size
}
So much cleaner, and generally more "swifty"!
The beauty of it all is that we don't even have to invent a new keyword for this, since Obj-C already has an "out" keyword (which was originally there for use with Distributed Objects, but I see no reason we couldn't repurpose it here). We could even wrap the call in an autoreleasepool to get rid of the autorelease on the returned-by-reference values, if the performance trade-off is deemed to be worth it.
You may say, what about methods that can take NULL as the reference parameter, and skip doing the work to generate that value if they get NULL as a parameter? Won't this proposed change make such methods inefficient in cases where you don't want one of the values? Well, assuming the pointer is declared as nullable, you could just do this:
let (foo, bar: _) = someMethod()
or:
let (foo, _) = someMethod()
and, seeing that a particular return value is not needed, Swift would pass NULL to the Objective-C method. (If the pointer were non-nullable, Swift would send it an actual pointer and simply ignore the result).
What think you?