swiftswiftuisyntactic-sugar

Using Init method without passing a parameter?


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?


Solution

  • 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.