Hi all,
I'd like to propose a syntax addition that acts to ease some things that I
believe should fall under the umbrella of 'optional chaining'. Optional
chaining allows us to access the properties of an optional value and return nil
if any link in that chain breaks. I propose we introduce syntax to allow
similar chaining when passing optional valued parameters to functions that
expect that parameter to be non-optional.
The example below is taken from a project I'm working on at the moment:
// Current
let readme: Markdown?
if let rawMarkdown = String(contentsOfFile: "README.md") {
readme = Markdown(string: rawMarkdown)
} else {
readme = nil
}
In this example we want to perform an operation, the initialisation of a
'Markdown' type, with our raw text if it exists and get nil otherwise. This is
rather verbose
I propose the following syntax for an alternative:
// Proposed alternative
let readme = Markdown(string: String(contentsOfFile: "README.md")?)
The ? is familiar in its use for optional chaining.
This would act like syntactic sugar for the flatMap method on Optional. For
example:
(where `john` is of a `Person` type with a property `address: Address?`)
// func getZipCode(fromAddress address: Address) -> ZipCode
getZipCode(fromAddress: john.address?)
// Would be equivalent to…
john.address.flatMap {
getZipCode($0)
}
An example with multiple parameters:
// func getPostageEstimate(source: Address, destination: Address, weight:
Double) -> Int
getPostageEstimate(source: john.address?, destination: alice.address?, weight:
2.0)
// Equivalent to
john.address.flatMap { freshVar1 in
alice.address.flatMap { freshVar2 in
getPostageEstimate(source: freshVar1, destination: freshVar2,
weight: 2.0)
}
}
// Or equally:
{
guard let freshVar1 = john.address,
let freshVar2 = alice.address else {
return nil
}
return getPostageEstimate(source: freshVar1, destination: freshVar2,
weight: 2.0)
}()
This would only be allowed when the parameter doesn’t already accept Optionals
and when the chained value is in fact an optional. We’d want to consider
emitting at least the following errors/warnings in the given scenarios:
let result = myFunc(3?)
// error: cannot use optional chaining on non-optional value of type 'Int'
// func myFunc2(x: String?) -> String
let result = myFunc2(x: john.address?)
// error: cannot use optional argument chaining on argument of optional type
let result = myFunc(nil?)
// warning: optional argument chaining with nil literal always results in nil
Seeking your thoughts on this idea, the specific syntax, and more use case
examples.
Best,
Jared
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution