Still Thinking About Swift
After some more time playing with Swift, Iâve added a few more items to my list of things that bugged me at some point or another. Iâm not saying these are perfect ideas, but they seemed good at the time!
If you want to omit the parameter names in a function, then only include the types in the declaration and refer to them using numeric names in the function body and donât mess around with the underscore placeholder:
func someFunction(Object, Object) { $0.callMethod($1) }
Then you could call it like this without using the labels (since there are none, of course):
someFunction(foo, bar)
Any unnamed parameter would always be replaced with the $ variables and the counting for them would start at 0 at the first unnamed parameter with no named parameters allowed after:
func someFunction(with: Object, Object) { with.callMethod($0) } someFunction(with: foo, bar)
And if you want to name them in the function body but not for callers, then you could do it the same way that you do for closures:
func someFunction(Object, Object) { (let with, and) in with.callMethod(and) }
Going along with this, I think it might be better if all labeled parameters were required to be labeled at the call - even the first one on methods. The existing exceptions to this are awkward and clearly exist as a side effect of Objective-Câs conventions. To maintain some Objective-C compatibility, if the class/function/whatever is marked as @objc, then it could work as it does today - but I donât think new pure Swift code should necessarily inherit that legacy.
Swift should be able to infer that this is perfectly valid and safe, but it doesnât seem willing to do so:
func doSomething() -> Int { var something: Int? = nil if something == nil { something = 42 } return something * 2 }
This is a contrived example because itâd be relatively easily worked around with the ?? operator, or using let, or some other construction, but Iâve run into this scenario a few times now and it seems like the âstandardâ Swift constructions are awkward if thereâs a handful of rules being checked, validated, reset, etc before you get down to where you want to use some of the values that may have been optional earlier in the function but not by the end. In this situation, guard doesnât seem useful because it forces you to leave your current scope and thatâs not quite what I want sometimes. Often the code inside the guard might be several lines and involve an expensive or slow computation that isnât always necessary.
Sure, I could force unwrap it with ! but then Iâve essentially circumvented the compilerâs checking and moved a bug from something that could be caught at compile time to something thatâd only be caught at runtime if I happened to rearrange the code and break the assumption that a particular variable beyond a certain point must always be non-nil.
I know that technically the types donât match (one is optional, one isnât), but considering how often Iâve done this and expected it to work I really feel like this should be a thing somehow - some kind of automatic unwrapping if all cases can be proven to be unwrapped?
It may be nice to have a keyword that tells the compiler to try to statically prove certain conditions are true after some point without needing to leave the scope or wrap it in an if-let or something else that happens at runtime. This way the compiler could still check the validity of the assertion and it would do so at compile time.
For example, imagine using something like this to unwrap an optional beyond a certain point in the function body:
func doSomething() -> Int { var something: Int? = nil if something == nil { something = 42 } require something: Int return something * 2 }
The compiler would be expected to prove that at the ârequireâ line, âsomethingâ could be an âIntâ (non-optional). If the compiler cannot prove that, it is an error. If it can prove it, the type of the variable is effectively changed from that point on (the compiler effectively changes all instances of âsomethingâ to âsomething!â - but it knows it should never fail which might mean it could avoid doing certain checks and it eliminates a piece of state from the mind of the programmer).
This idea could be extended in other ways, potentially, if you could specify rules in a flexible enough way. For example, imagine being able to constrain the ranges of basic value types:
require x in 0âŚ1 let result = someValue * x
Ideally, the compiler would then attempt to prove that x must always be in the range of 0âŚ1. If it cannot prove this to be true, then it would be a compiler error.
Going farther, you could use the same thing on type declarations themselves so you could have a Float that could only contain 0âŚ1:
var scaler: Float in 0âŚ1
Or build a function that has constrained input ranges:
func scale(x: Float in 0âŚ1) -> Float { return someValue * x }
I like the idea of this always being a compile-time check when possible, but it could also be useful to force the requirement to be evaluated at runtime by adding a force operator to it:
func scale(x: Float in! 0âŚ1) -> Float { return someValue * x }
In this scenario the compiler would probably still try to prove it statically - and if it could, itâd skip runtime checks - but if it cannot, it would then insert runtime guards that catch requirement failures and crash as necessary - similar to a forced unwrap - instead of being a compile time error.
The cases in a switch statement donât need a âbreakâ like most other languages do - this is good. The weird thing is that the âbreakâ keyword still behaves like a traditional break in a switch even though it isnât necessary. I imagine thereâs decent reasons for this, but I spent a good 20 minutes confused as to why this didnât break out of the loop like I initially thought it would:
while isTrue { switch something { case .SpecialCase: break case .NormalCase: stuff() } }









