[swift-evolution] [Idea] Use optionals for non-optional parameters
Pyry Jahkola
pyry.jahkola at iki.fi
Tue Aug 16 13:40:05 CDT 2016
> On 16 Aug 2016, at 20:24, Justin Jia via swift-evolution <swift-evolution at swift.org> wrote:
>
> Thank you for the sharing how you solve this problem! It seems like the best workaround so far.
>
> I wish $0 can be replaced by the actual name. (Maybe tuples?)
>
> let a = (x: x, y: y)
> let result = a.my_map { foo(x: $0.x, y: $0.y }
>
> In my_map unwrap all variables inside tuple?
>
> I agree that short-circuiting is an issue. But personally I still think the imperfect solution is good enough. But I'll try to find other possible solutions.
One technique around this is to introduce a set of generic library functions that try to unwrap all of their arguments and construct a tuple thereof if every argument evaluated to `.some(_)`. The evaluation of expressions can also be delayed with @autoclosure:
func unwrap<A, B>(_ a: A?, _ b: @autoclosure () throws -> B?) rethrows -> (A, B)? {
guard let a = a, let b = try b() else { return nil }
return (a, b)
}
func unwrap<A, B, C>(_ a: A?,
_ b: @autoclosure () throws -> B?,
_ c: @autoclosure () throws -> C?) rethrows -> (A, B, C)?
{
guard let a = a, let b = try b(), let c = try c() else { return nil }
return (a, b, c)
}
// ...etc, for higher arities than 3.
Repetitive library code? Yes. But can be easily generated with a code generator such as swift.gyb, and you hardly need it for arities higher than a few.
You can use `unwrap()` together with `if let` or `guard let`:
if let (a, b, c) = unwrap(Int("1"), Double("12"), Bool("true")) {
print(a, b, c) //=> 1 12.0 true
}
Or even `.map()` if you like. This use is similar to Dave Sweeris' suggestion of `optionally()`:
struct User { var username, language: String }
let data = ["u": "chris", "l": "swift"]
let user = unwrap(data["u"], data["l"]).map {u, l in
User(username: u, language: l)
}
print(user) //=> Optional(User(username: "chris", language: "swift"))
I guess that reads better than this equivalent with `.flatMap()` and `.map()`:
let user = data["u"].flatMap { u in
data["l"].map { l in
User(username: u, language: l)
}
}
OTOH, it isn't much better than either delayed `let` initialisation:
let user: User?
if let u = data["u"], let l = data["l"] {
user = User(username: u, language: l)
} else {
user = nil
}
Or the use of a one-off closure like so:
let user: User? = {
guard let u = data["u"], let l = data["l"] else { return nil }
return User(username: u, language: l)
}()
— Pyry
(Sorry for the sparing use of newlines in the examples above. Tried to keep it tight.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160816/a72e1a19/attachment.html>
More information about the swift-evolution
mailing list