Using Init method without passing a parameter?

51 Views Asked by At

I have an array of CLPlacemark. I'm following and example and I don't understand why the second code is correct.

Example 1: This code is correct.

let placemarks: [CLPlacemark]
....

placemarks
.compactMap({ placemark in
      Location(placemark: placemark)
})

...

Example 2: This code is also correct.

let placemarks: [CLPlacemark]
....

placemarks
.compactMap(Location.init(placemark:))

...

Do you know why I can create Locations without passing the parameter?

1

There are 1 best solutions below

1
Sweeper On BEST ANSWER

Initialisers can be thought of as a regular function that returns a value of whatever type the initialiser is initialising. They have a type when you explicitly write out init.

In the same way that you can write:

func makeLocation(placemark: CLPlacemark) -> Location? { ... }
// I'm not *calling* `makeLocation` here - I'm just assigning the function itself to f
let f: (CLPlacemark) -> Location? = makeLocation(placemark:) // or just makeLocation

You can also write:

struct Location {
    init?(placemark: CLPlacemark) { ... }
}
let f: (CLPlacemark) -> Location? = Location.init(placemark:) // or just Location.init

See also this section of the Swift Guide if this is the first time you have seen a function itself being used as a value, instead of being invoked.

It works the same way in compactMap. compactMap expects a function of type (T) -> U? where T and U are type parameters.

You could pass the lambda { placemark in Location(placemark: placemark) }. This lambda would be of type (CLPlacemark) -> Location?. But the type of Location.init is also (CLPlacemark) -> Location? matches this pattern, so you are able to pass it to compactMap too.