Trying to make this common swift pattern more functional.
for object in objects.allObjects {
guard let _object = object as? SomeTypeOfObject else { continue }
_object.subObject(subObject, objectStateChanged: changedState)
}
I'd love to use something like "any" (instead of map) to get rid of the for loop - like in Kotlin - but that dose not seem to be possible in Swift.
Trying to figure out a way to include the guard in the functional representation of this block.
Feels like I'm missing something. Am I?
Thanks
A common functional pattern is to compactMap and then call the method with side-effect in a forEach. This eliminates the guard entirely:
objects.allObjects // Add `.lazy` if you don’t want to build the intermediary array
.compactMap { $0 as? SomeTypeOfObject }
.forEach { $0.subObject(subObject, objectStateChanged: changedState) }
Related
I'm using NSRegularExpression in my Swift code because it needs to run on older platforms. The factory method throws, so we need to trap the error - which does indeed occur in my code (I feed in some crazy patterns). I call it using:
let regex: NSRegularExpression
do {
regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
} catch {
return false
}
For handling optionals, Swift offers the guard let pattern which makes this much more clear and self-documenting as it exposes the variable to the enclosing scope and one-lines the logic. guard case is also useful. Is there some similar syntactic sugar for throws?
You probably mean
guard let regex = try? NSRegularExpression(...) else { return false }
I am doing the weak strong dance in swift this way:
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), { [weak self] in
guard let `self` = self else {
return
}
self.doSomething(1)
})
Before this, I was using strongSelf instead of `self`. On a website I've seen that I can use this character ` .
But what does this character do in Swift? Without this I cannot assign to self. Why does this work? Is it a good practice to use it?
A bit of an update (I will not refer here when to use it but rather how).
From Swift 4.2 the use should be like:
guard let self = self else { return }
Using ` is basically based on the compiler bug thus not advised.
For more information there is no better source than this. Explaining all reasoning behind and other considerations.
In short the above is more consistent with other cases seen in the code like:
if let myVariable = myVariable
So does not create confusion/discrepancies.
Swift Programming Language
Presents a note that says the following:
If you need to give a constant or variable the same name as a reserved
Swift keyword, surround the keyword with backticks (`) when using it
as a name. However, avoid using keywords as names unless you have
absolutely no choice.
EDIT:
The way I do this is using any other name for example strongSelf like you previously did. Because in the end, both `self` and strongSelf will be some variable to act upon. So I suggest if we can use some other variable name that is fine.
I have encountered numerous situations where a coder have used the guard keyword. And then later, in a seemingly almost identical situation the same coder in the same code does not use the guard keyword. I am aware that this may be a stupid question, so please don't bash it. When should I use the guard keyword and where shouldn't I?
Here is an example (there are many more). This is part of a script that is requesting data form an API.
//Here I am using guard
guard let json = json else {
//Now I am not using guard
if let error = error {
completion(.Failure(error))
} else {
//Error handling
}
return
}
Why not use the:
if let var1 = var1 {
//Keep on going
} else {
//Don't crash
}
syntax all the time instead of the guard syntax? At first glance it even seems to have more functionality, but I am certain that does not have to be the case.
One great benefit of the guard statement is that you know that if the condition is not satisfied then the execution flow gets stopped.
This is important for several reasons
Unwrapping
You can define unwrapped values which don't need a new scope { ... } to be available
func next(num:Int?) -> Int? {
guard let num = num else { return nil }
return num + 1
}
Readability
When you read the code you know that if the guard condition is not satisfied then the following lines won't be executed.
Semantics
You know a guard statement is there to check conditions required for the following block of code.
But I can replace every guard with an if
Sure. We could also replace every while and for with a goto in some languages. And we could always replace recursion with iteration (and viceversa).
But this doesn't necessarily means it is always a good idea.
Despite we can implement some behaviours with more then one programming "tool", we should still use the one that better fits that specific scenario.
Can I merge a for-in and if-let in one statement?
for item in array {
if let f = item as? NSDictionary {
result.addObject(newFile(f))
}
}
array is made by a JSON, so I don't know if each item is a NSDictionary or not. I have to check.
I was looking for something like this:
for item as? NSDictionary in array {
// code
}
Like Python or Ruby.
#nickfalk is on the right track, but we can do better. His result unfortunately returns [AnyObject], which you can't then call newFile with (I assume). But that's ok, we can get the rest of the way pretty easily.
What you want is partial map. That is to say, you want to map some (but possibly not all) of the elements of one list to another list (from AnyObject to File, if we can). So there must be some rule for choosing, and some rule for mapping. Optional let's us combine those. Let's call the function that does that f. Then its type is:
f: T->U?
So there's some magic function that will possibly convert T to U. We want to map with that. Sounds easy:
extension Array {
func partialMap<U>(f: T->U?) -> [U] {
var result = [U]()
for x in self {
if let u = f(x) {
result.append(u)
}
}
return result
}
}
So now we've hidden all the nasty mutation and var and whatnot down deep where we don't have to look at it. We have a function that takes a mapping function from "something" to "maybe something else" and returns a list of "something elses that we could map."
Now everything is nice and immutable and reusable:
let result = array.partialMap { ($0 as? NSDictionary).map(newFile) }
Whoa there. What's that map in the middle? Well, as? returns NSDictionary?. When you map an optional, then if the optional is None, it returns None, otherwise it applies the function to the value and wraps it in Some. So this whole thing takes AnyObject and returns File? just like we wanted. One partialMap later we have our answer.
I would probably just go for something like:
let result = array.filter() { $0 is NSDictionary }
If you need result to be an NSDictionary array, you can just cast it:
let result = array.filter() { $0 is NSDictionary } as [NSDictionary]
If your goal is to reduce an NSArray to an array only containing NSDictionary filter is a very powerful tool. Create the appropriate filtering function:
func filterForNSDictionary(object: AnyObject) -> Bool{
return object.isKindOfClass(NSDictionary)
}
Then simply pass in you array and function to the filter function
let result = filter(array, filterForNSDictionary)
As #RobNapier points out my solution above will end up with a result array being of the type [AnyObject] this can of course easily be remedied:
let result = filter(array, filterForNSDictionary) as [NSDictionary]
This could be considered risky, if you force the array to be of the wrong type. as [NSString] (for instance9 would most likely blow up in your face down the line...
Rob's solution being pure awesome cleverness of course and #MattGibson delivering the perfect shorthand, while exposing me as an absolute beginner in this field.
It's a very common idiom to continue a loop if some condition fails on an element.
Say we want to do something to all subviews of a certain type (and, for some reason, don't want to duck type things). Ideally, we would write:
for view in self.subviews as [NSView] { // cast required in beta 6
if (let specificView = view as? SpecificView) == nil { // <- Error here
continue
}
// Do things at a sensible indentation level
}
The above code fails with 'Pattern variable binding cannot appear in an expression', as in this question.
However, this seems like such a common pattern that there has to be a way to do it in Swift. Am I missing something?
EDIT: Now that I think about it, this appears to fall afoul of the scoping rules for if let statements, which only scope the variable to the inner block.
With that in mind, I'd like to broaden the question a little: how do people apply this pattern generally in Swift?
This is a somewhat common pattern, but it is not a good pattern. I've seen it inject bugs into ObjC projects. It assumes too much about the view hierarchy, and winds up being fragile when that changes (such as when someone injects an extra view you weren't expecting in order to manage rotations; true story). The better pattern is to maintain a property that points to your SpecificView (or views) that you want to track. Downcasting in general is something to be avoided, not optimized.
That said, it is not a terrible pattern, and sometimes it is a very useful pattern. So how might you handle it?
let specifics = self.subviews
.filter { $0 is SpecificView }
.map { $0 as SpecificView }
for view in specifics { ... }
That's kind of a common pattern, so maybe we can genericize it?
extension Array {
func filterByClass<T>(c: T.Type) -> [T] {
return self.filter { $0 is T }.map { $0 as T }
}
}
for view in self.subviews.filterByClass(SpecificView) { ... }
That said, I think this approach should be avoided wherever possible rather than excessively simplified.