Many times I use self-executing closure to assign a value, such as:
let user = {
guard let region = region, let group = group else { return User() }
return User(region: region, group: group)
}()
let suiteName = {
switch Environment.mode {
case .development: return "group.com.example.dev"
case .staging: return "group.com.example.staging"
case .production: return "group.com.example.live"
}
}()
let realm: Realm
do { realm = try Realm() }
catch { return completion(.failure(.databaseFailure(error))) }
A shorthand assignment of these would be very convenient:
let user = let region = region, let group = group
? User(region: region, group: group)
: User()
let suiteName = switch Environment.mode {
case .development: return "group.com.example.dev"
case .staging: return "group.com.example.staging"
case .production: return "group.com.example.live"
}
do let realm = try Realm() catch {
return completion(.failure(.databaseFailure(error)))
}
What do you think.. Swifty or nay?
UPDATE: Disregard guard/do/try from discussion since proposed before.
1 Like
Avi
2
I'm not sure whether I like the first two, but what about changing the last to be an alternative to guard-else? That is:
guard let realm = try Realm() catch {
return completion(.failure(.databaseFailure(error)))
}
guard would keep the same requirement that the body must return, or otherwise exit the enclosing scope.
3 Likes
karim
(Karim Nassar)
3
Fairly sure this was proposed before. Can't remember where it wound up.
Edit:
Here are a couple:
I think one complication that needed straightening out was what happens when the throwing operation returns an optional?
Does the guard-let unwrap it? Do you then need to support guard-let-try-catch-else ??
Thanks @karim for recalling that and finding it! I've updated the title and post to only discuss the first 2 examples.
Letan
(Letanyan Arumugam)
5
The first two examples seem to only be held back by the current capabilities of the type checker. There is, however, a want to make control statements (including loops) return values.
So the things you're proposing would be very close to that, though your first option might look a bit different:
let user = if let region, let group = group {
return User(region, group)
} else {
return User()
}
There's probably still design needed for this, like possibly changing return to yield or something, but I think this feature is not exactly a top priority right now :(
ahti
(Lukas Stabe 🙃)
6
I'd be very happy to see control flow statements work as expressions. I'm referring to if/else and switch mostly, I think loops should rather be handled by generators/coroutines, and haven't thought about other types of statement.
I don't know anything about the type checker internals, but I tried around a bit to find the current limitations:
func if_f<T>(_ cond: Bool, then: () -> T, else e: () -> T) -> T {
if cond { return then() } else { return e() }
}
// this works fine
let v = if_f(1 == 2, then: { "lol" }, else: { "lel" })
// this works as well, bc the contextual type from print is Any
print(if_f(1 == 1, then: { "lol" }, else: { 1 }))
// however, this doesn't
let v2 = if_f(1 == 1, then: { "lol" }, else: { 1 })
// unless we give the type checker a little help:
let v3 = if_f(1 == 1, then: { "lol" }, else: { 1 }) as Any
So it might be possible to do at least the simple case, where all branches have the same static type, without type checker improvements?
Wrt syntax, I think using return here would unnecessarily overload the meaning of the keyword. yield should probably be left for coroutines/generators. I'd rather just have no special syntax, the way Rust, Ruby, F# and I'm sure other languages work:
let user = if let region, let group = group {
User(region, group)
} else {
User()
}
let suiteName = switch Environment.mode {
case .development: "group.com.example.dev"
case .staging: "group.com.example.staging"
case .production: "group.com.example.live"
}
1 Like
No, it takes an Any... which isn't exactly the same as [Any] although it would be nice if one could convert from the latter to the former.
Avi
9
func f(x: Any...) {
print(type(of: x))
}
f(x: 1)
The output is Array<Any>.
Sash
(Sash)
10
Any news on this feature? It would be very handy to have it