Programming in Swift · Closures and Collections | Ray Wenderlich

Hi!

First, you’re definitely not alone with your opinion on bracing: Swift bracing — Erica Sadun. However, the Swift community settled on 1TBS pretty early on, so you’ll want to use your own linting rules if you’ll be converting others’ work for your own projects.

Have you held the command key while mousing over braces or parentheses yet in Xcode? That highlights the matching symbol. You may find it helpful for visualizing scope; I certainly do when there’s enough nesting going on.

We don’t get into generics in this course, but Catie and I use something like Allman style when generic functions get complex enough, and the opening brace no longer seems to have a most-meaningful connection to what precedes it. I’d be interested to know how you’d format this (an example we use in our own style guide):

/*:
### Multipline `where` clauses
When there is more than one `where` clause, each requires its own line, and is indented below the `where` keyword. The following opening `{` will appear at the beginning of the line after the last requirement.
*/

protocol PAT {
  associatedtype Associatedtype
}

func function<
  Parameter0: PAT,
  Parameter1: PAT
>(
  parameter0: Parameter0,
  parameter1: Parameter1
)
where
  Parameter0.Associatedtype: Protocol,
  Parameter1.Associatedtype: Protocol
{
  // 🦁
  // 🐯
  // 🐻
}

As for shorthand syntax in closures, I think your example is a great illustration for a case where positional shorthand names are preferable. Within the closure, you’re quickly giving meaning to the parameters, so they can be given meaningful names. But considering all the closure knows about its parameters, to start, is that they’re integers, and their positions, $0 and $1 are clearer to me than a and b, or any alternative. I wish we had the option to use positional syntax in functions too, for cases like this!

It will be interesting to see if you come to a similar opinion after getting over the initial pain of learning Swift closure syntax – I’d love to hear back from you about it (in maybe a year’s time or so?) after you’ve had ample time to experiment and come to find your own standards.

let multiply: (Int, Int) -> Int = {
  let (min, max) =
    $0 < $1
    ? ($0, $1)
    : ($1, $0)
  print(
    min, max,
    "Arrghh!!! Swift!!!",
    getNewString()
  )

  let product = $0 * $1
  print("Result of \($0) * \($1) = \(product)")
  return product
}

Hi Catie & Jessie

Thanks for taking the time to read and reply with such useful info to my previous questions.

It really seems like I’m never going to get anywhere with swift, especially because of closure syntax and all this obfuscated / truncated code.

I’ve been trying to take what you said above and apply it to the next big chapter / video: Closures and Collections, and I admit, I’m so utterly lost and frustrated that I feel like giving up.

I’m writing because I’d like to ask for help in understanding what’s going on with the following syntax. I understand that there is less readability because of type inference going on, but I can’t read this, and I certainly could never come up with this on my own.

1.    let dwarvesAfterM = arrayOfDwarfArrays.flatMap 
2.    { 
3.        array -> [String] in
4.            return array.filter
5.            { 
6.               dwarf -> Bool in
7.                   dwarf > "M"
8.            }
9.    }

So, on line 3, you’re saying the ‘flatmap’ method takes an array and returns a string right?

So line 4, you’re using another closure to find and return that string… however…

In line 6, you’re saying the input is a ‘dwarf’ object (no type?! so what’s it inferring? and where is this being defined?!) and it’s returning a BOOL!??!?

I thought it was supposed to return a string?

I see on line 7, if we can ASSUME that ‘dwarf’ objects are strings, then you’re ‘filtering’ to return a string IF AND ONLY IF it meets this condition, but where does this returned BOOL go and why is it ignored and why doesn’t it become the return type of the thing returning back into the flatmap closure?

I’m so lost.

I apologise if this is trivial to others, but I understand procedural languages. This ‘functional’ stuff feels like nonsense to me. And utterly overcomplicating things. I miss Obj-C :frowning:

EDIT:

On a similar note, how do you even begin to work out how to turn the code signature from it’s Xcode prototype into the code from your example?! They don’t even resemble each other:

[]

Hi again!

I think you have a couple small misunderstandings here that are hopefully easy to clear up. Mostly, I think you’re confusing the inputs/outputs of flatMap/filter with those of their closure arguments.

I’m going to go through your questions, and at the end I’ll include an example of a for loop that gets you the same result as the flatMap/filter combo.

So, on line 3, you’re saying the ‘flatmap’ method takes an array and returns a string right?

Important differences:
1 - flatMap acts on a multidimensional array! In this case it’s an array of string arrays. The closure takes a one-dimensional string array.
2 - Both flatMap and the closure return a string array. The closure returns whatever remains of the string array that was passed into it. flatMap returns the contents of all the arrays returned by the closure, flattened into a one-dimensional array.

In line 6, you’re saying the input is a ‘dwarf’ object (no type?! so what’s it inferring? and where is this being defined?!) and it’s returning a BOOL!??!?

I thought it was supposed to return a string?

Usually, I recommend option-clicking on things to find out what type they are, but that’s not working for me in the closure parameter lists right now :[

For filter, the input for the closure is an element from the array filter is called by. In this case, that input is a string that I’ve named dwarf. The closure returns a bool. filter is returning a string array, and the bool determines whether each string (or dwarf, in this case) is included in that returned array.

And now, the for loop I promised ( I tried to use your bracing style here :] )

var dwarvesAfterM: [String] = []
// flatMap
for dwarfArray in arrayOfDwarfArrays
{
  // filter
  var dwarves: [String] = []
  for dwarf in dwarfArray 
  {
    if dwarf > "M" 
    {
      dwarves.append(dwarf)
    }
  }

  dwarvesAfterM += dwarves
}

Last note: I agree that the placeholders Xcode gives you don’t feel super helpful in these cases, and I rarely use them. I’ve often option-clicked on reduce/filter/etc. to look at the longer descriptions of the parameters when I’ve gotten stuck.

2 Likes

Hi
if by this point in this course I’m finding it hard to grasp, and I find that I’m not remembering everything, am I in trouble, or should I just carry on ?

Hi Hammam!

Fortunately, it’s not necessary to have it all memorized in order to accomplish wonderful things. If you’re either enjoying what you’re learning, or you know it will be helpful to you, I recommend persevering. You should expect the process to be challenging – it certainly was for me! :smiley_cat:

Someone else had a similar question recently. My answer to them is my answer to you, with the addition that you don’t even need to understand everything, let alone have it easily retrievable in your memory, in order to move along. A benefit of the recorded material is that you can come back to it whenever you’d like.

1 Like

Hi hammam,

I’m doing this course for the first time too. And this video was definitely the one the took me the longest so far. AND I come from a programming background! I had to do it a few times to grasp closures, so don’t worry, you’re not alone.
My understanding is that closures are basically functions (without a name or the ‘func’ keyword) that you can pass around like variables. They can be called at a later time. They remember the scope of the variables they use.

I also had the issue where I wasn’t remembering everything, I realised this in the Collections videos (Arrays, Dictionaries, Sets…) and this is what I did: I started the whole course again, and instead of just watching Jessie and Catie explain the concepts, I typed out everything that they were typing out. I didn’t download the starter playgounds. Now I have a playground in XCode with separate pages for each concept for each video. I’ve added my own helpful comments as i went along and it’s something I can refer back to without having to watch the videos again. I found that typing everything out as Jessie and Catie did it helped me to cement a lot of things - a lot more than simply doing the challenge or just downloading the end playground.

Also if you get stuck, then ask on here or ask someone. There are no dumb questions, there is always someone out there thinking the exact same thing you are. There are so many times I had to turn to my colleague when watching this one and ask things like “how did they get away with not defining this thing?”

All the best!

1 Like

Hi
thank you both for the encouraging words, I was beginning to think it was just me, thank you I shall soldier on hah

1 Like

Hi guys I have got this far OK I think, but this Closures and Collections
has knocked me back. Its like I’ve had a brain freeze, at the end with
the mini challenge shortening the syntax & writing it as a ‘for’ loop I am just
sitting here blank…
Its like writers block does this happen often or is it just me closures & collections
just wont sink in??

Is there any extra material that will help me I cant watch this section a tenth time.

1 Like

This has been the hardest video so far.

Hi! I know Jessy has already pointed you to the updated version of this course. We decided to split up our Swift content this year, so the Fundamentals course doesn’t cover closures at all.

Closures and higher-order functions can be a sticking point for a lot of people! I’m currently working on a second Swift course, which will spend a lot more time on an introduction to closures and how to use methods like map.

Since that isn’t ready for you, yet, we do have a written tutorial on Functional Programming in Swift that talks about map, filter, and reduce.