Bill Chan
Bill Chan

Reputation: 3455

Generic function parameter default value

I am working with swift-snapshot-testing and found a problem about Generic function parameter default value.

The framework provide a method like this:

func verifySnapshot<Value, Format>(matching value: Value,
                                   as snapshotting: Snapshotting<Value, Format>,
                                   snapshotDirectory: String? = nil) -> String? 

where Snapshotting is a generic struct like this:

struct Snapshotting<Value, Format> {}

extension Snapshotting where Value == UIViewController, Format == UIImage {
    static var image: Snapshotting<UIViewController, UIImage> {
      :
    }
}

extension Snapshotting where Value == UIView, Format == UIImage {
    static var image: Snapshotting<UIView, UIImage> {
      :
    }
}

I want to create a helper method and this works:

func verify<Value, Format>(matching value: Value,
                           as snapshotting: Snapshotting<Value, Format>) {
    let snapshotDirectory = "/path"

    let failure = verifySnapshot(matching: value,
                                 as: snapshotting,
                                 snapshotDirectory: snapshotDirectory)

    print(failure ?? "Done!")
}

But when I want to give snapshotting a default parameter value .image, it does not compile for the error Ambiguous reference to member 'image'

func verify<Value, Format>(matching value: Value,
                           as snapshotting: Snapshotting<Value, Format> = Snapshotting<Value, Format>.image)

My question is: can Swift infer the generic type Format for default parameter value?

Upvotes: 2

Views: 106

Answers (2)

Bill Chan
Bill Chan

Reputation: 3455

Ref to @Rob Napler's answer I made a work-round to make the interface looks like with default value:

///interface to accept snapshotting argument 
func verify<Value, Format>(matching value: Value,
                           as snapshotting: Snapshotting<Value, Format>)

///interfaces to accept specific kind of value 
func verify(matching value: UIView)
func verify(matching value: UIViewController)
:
:

and we can call it like

verify(matching: aView)

or

verify(matching: aView, as: .image)

Upvotes: 0

Rob Napier
Rob Napier

Reputation: 299355

The main problem here is that .image does not exist for every <Value, Format> pair. It only exists for <UIViewController, UIImage>, and <UIView, UIImage>. To assign a default here, it has to be applicable to every way that verify can be called.

Default parameters can always be expressed as a separate function with fewer parameters, so you just need to add the desired overloads rather than the default value.

func verify(matching value: UIViewController) {
    verify(matching: value, as: .image)
}

func verify(matching value: UIView) {
    verify(matching: value, as: .image)
}

Upvotes: 1

Related Questions