if let
statement. As far as I can tell, it exists pretty
much exclusively
to check that an optional variable actually does contain a value and if it does, work with a no-longer-optional version
of that variable.
Swift packages this functionality in a combination if
statement and let
declaration:
if let value = value {
print("value is \(value)")
}
This has a bunch of problems that are explained nicely in a Swift Evolution thread (via Michael Tsai) together with some proposals to fix it. One of the issues is the idiomatic repitition of the variable name, because typically you do want the same variable, just with less optionality. Alas, code-completion apparently doesn't handle this well, so the temptation is to pick a non-descriptive variable name.
In my previous post (Asynchronous Sequences and Polymorphic Streams) I noted how the fact that iteration in Smalltalk and Objecive-S is done via messages and blocks means that there is no separate concept of a "loop-variable", that is just an argument to the block.
Conditionals are handled the same way, with blocks and messages, but normally don't pass arguments to their
argument blocks, because in normal conditionals those arguments would always be just the constants
true
or false
. Not very interesting.
When I added ifNotNil:
some time ago, I used the same logic, but it turns out the object
is now actually potentially interesting. So ifNotNil:
now passes the now-known-to-be-non-nil
value to the block and can be used as follows:
value ifNotNil:{ :value |
stdout println:value.
}
This doesn't eliminate the duplication, but does avoid the issue of having the newly introduced variable name precede the original variable. Well, that and the whole weird
if let
in the first place.With anonymous block arguments, we actually don't have to name the parameter at all:
value ifNotNil:{ stdout println:$0. }
Alternatively, we can just take advantage of some conveniensces and use a HOM instead:
value ifNotNil printOn:stdout.
Of course, Objective-S currently doesn't care about optionality, and with the current nil-eating behavior, the
ifNotNil
is
not strictly necessary, you could just write it as follow:
value printOn:stdout.
I haven't really done much thinking about it, but the whole idea of optionality shouldn't really be handled in the space of values, but in the space of references. Which are first class objects in Objective-S.
So you don't ask a value if it is nil or not, you ask the variable if it contains a value:
ref:value ifBound:{ :value | ... }
To me that makes a lot more sense than having every type be accompanied by an optional type.
So if we were to care about optionality so in the future, we have the
tools to create a sensible solution. And we can let if let
just be.
The problem with duplicated names is less of a problem if you consider that #ifNotNil: doesn't care if the receiver is stored in a variable in first place. You could call a method and then send #ifNotNil: to the result. In such a case it's more useful to have the block with a named variable, as it documents what kind of thing you'll get there.
ReplyDeleteOn the other hand i prefer ifNil: because not having a value is typically the exception to the rule and you'd just early return in case of a nil value or you choose a default-value in case of nil using #ifNil:.
Except in Objective-C, the messenger swallows messages to nil...
ReplyDelete