Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the practical use of nested functions in swift? [duplicate]

Tags:

What is the practical use of nested functions? It only makes the code harder to read and doesn't make a particular case easy.

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {     func stepForward(input: Int) -> Int { return input + 1 }     func stepBackward(input: Int) -> Int { return input - 1 }     return backwards ? stepBackward : stepForward } 

Source

like image 241
Esqarrouth Avatar asked Oct 06 '15 10:10

Esqarrouth


People also ask

What is the use of nested functions in Swift?

In Swift, when a function exists inside another function then such types of functions are known as nested functions. The nested function is hidden inside the outer function or enclosed and cannot be accessed by the outside functions if we try to access them we will error.

Why we use nested functions?

A nested function can access other local functions, variables, constants, types, classes, etc. that are in the same scope, or in any enclosing scope, without explicit parameter passing, which greatly simplifies passing data into and out of the nested function. This is typically allowed for both reading and writing.

How many types of functions are there in Swift?

Swift has two compound Types: functions and tuples. Now I know what you might be thinking: “Functions have names!” Indeed many do.


2 Answers

I think the core of your question is: Why not use private function instead of an ugly nested function?

Simply put, nested functions can ease readability and encapsulation.

Similarly one can ask, what's the practical use of local variables (of a function) vs instance variables? To me it's really the same question. Only that nested functions are less common.

Readability

A private function can still be accessed from other functions in your class. The same isn't true for nested functions. You're telling your developers, this only belongs to this function (contrary to private functions where they belong to the entire class). Back off and don't mess with it, if you need similar capability, go write your own!

The moment you see a private function you have to think, which function will call it. Is it the first function or the last? Let me search for it. Yet with a nested function you don't have to look up and down. It's already known which function will call it.

Also if you have 5 private functions, where 3 of them are called in a single public function then by nesting them all under the same public function you're communicating to other developers that these private functions are related.

In short, just as you don't want to pollute your public namespace, you don't want to pollute your private namespace.

Encapsulation

Another convenience is that it can access all the local parameters to its parent function. You no longer need to pass them around. This would eventually mean one less function to test, because you've wrapped one function inside another. Additionally if you're calling that function in a block of the non-nested function, then you don't have to wrap it into self or think about creating leaks. It's because the lifecycle of the nested function is tied to the lifecycle of its containing function.

Another use case would be when you have very similar functions in your class, say like you have:

extractAllHebrewNames() // right to left language extractAllAmericanNames() // left to right language extractAllJapaneseNames() // top to bottom language 

Now if you have a private func named printName (that prints names), it would work if you switch the case based on language, but what if just you don't/can't do that. Instead you can write your own nested functions (They could all now have the exact same name. because each is in a different namespace.) inside each separate extract function and print the names.

Your question is somewhat similar, to why not use 'if else' instead of a 'Switch case.

I think it's just a convenience provided (for something that can be dealt without using nested functions).

NOTE: A nested function should be written before it's callsite within the function.

Error: use of local variable 'nested' before its declaration

func doSomething(){     nested()          func nested(){              } } 

No Error:

func doSomething(){     func nested(){              }          nested() } 

Similarly a local variable used in a nested function must be declared before the nested function


BE AWARE:

If you're using nested functions, then the compiler won't enforce self checks.

The compiler is not smart enough. It will NOT throw error of:

Call to method 'doZ' in closure requires explicit 'self.' to make capture semantics explicit  

This could result in hard to find memory leaks. e.g.

class P {     var name: String          init(name: String) {         print("p was allocated")         self.name = name     }          func weaklyNested() {         weak var _self = self         func doX() {             print("nested:", _self?.name as Any)         }                  DispatchQueue.main.asyncAfter(deadline: .now() + 1) {             doX()         }     }          func stronglyNested() {         func doZ() {             print("nested:", name)         }                  DispatchQueue.main.asyncAfter(deadline: .now() + 2) {             doZ() // will NOT throw error of: `Call to method 'doZ' in closure requires explicit 'self.' to make capture semantics explicit`         }     }          deinit {         print("class P was deinitialized")     } }  class H {     var p: P          init(p: P) {         self.p = p     } }  var h1: H? = H(p: P(name: "john")) h1?.p.weaklyNested() h1 = nil // will deallocate immediately, then print nil after 2 seconds  var h2: H? = H(p: P(name: "john")) h2?.p.stronglyNested() h2 = nil // will NOT deallocate immediately, will print "john" after 2 seconds, then deallocates 

tl;dr solution:

  • use weak var _self = self and inside the nested function reference to self with the weak reference.
  • don't use nested functions at all :( Or don't use instance variables inside your nested functions.

This part was written thanks to this original post from Is self captured within a nested function?

like image 105
mfaani Avatar answered Oct 21 '22 19:10

mfaani


One use case is operations on recursive data structures.

Consider, for instance, this code for searching in binary search trees:

func get(_ key: Key) -> Value? {     func recursiveGet(cur: Node) -> Value? {         if cur.key == key {             return cur.val         } else if key < cur.key {             return cur.left != nil ? recursiveGet(cur: cur.left!) : nil         } else {             return cur.right != nil ? recursiveGet(cur: cur.right!) : nil         }     }      if let root = self.root {         return recursiveGet(cur: root)     } else {         return nil     } } 

Of course, you can transform the recursion into a loop, doing away with the nested function. I find recursive code often clearer than iterative variants, though. (Trade off vs. runtime cost!)

You could also define recursiveGet as (private) member outside of get but that would be bad design (unless recursiveGet is used in multiple methods).

like image 22
Raphael Avatar answered Oct 21 '22 18:10

Raphael