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() } }








