Binkan Salaryman
Binkan Salaryman

Reputation: 3058

Swift - Make func type explicit (in protocol)

Suppose, we have a protocol with typealiases like this:

// common closure types
typealias Action = () -> Void
typealias Consumer<T> = (T) -> Void

// here starts the fun
typealias AsyncAction = (Action?) -> Void
typealias AsyncGetter<T> = (Consumer<T>?) -> Void
typealias AsyncSetter<T> = (T, Action?) -> Void

// make compiler and you happy
typealias Foo = Void
typealias Bar = Void

protocol FooBarDatabaseAccess {
    func doSomething()
    func doSomethingAsync(completion: Action?)//: AsyncAction
    func getFooAsync(completion: Consumer<Foo>?)//: AsyncGetter<Foo>
    func getBarAsync(completion: Consumer<Bar>?)//: AsyncGetter<Bar>
    func setBarAsync(value: Bar, completion: Action?)//: AsyncSetter<Bar>
}


I would like to specify the function type similar to let/var declarations with a colon followed by its assignable type:

/* -- let/var -- */

// implicitly typed as String, determined from initial assignment
let implicitString = ""

// explicitly typed as String, though initialisation is omitted here
let explicitString: String


/* -- func -- */

// implicitly typed as () -> Void, determined from argument/return type(s)
func implicitAction()

// explicitly typed as Action, compiler should complain if it does not conform to the type (alias)
???


How can I achieve that?

A possible workaround is to transform it into a property declaration, but that is confusing:

var explicitAction: Action = { get }

Upvotes: 0

Views: 257

Answers (1)

rraphael
rraphael

Reputation: 11066

As Action is a typealias and not a type, swift can't differentiate them.

As explained in the documentation:

After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type.

Edit: My bad, I thought you wanted to differentiate () -> Void and Action. As far as I know, using a closure is the only way of doing this in swift.

typealias Foo = (Int) -> Void

protocol FooBar {
  var foo: Foo { get }
}

class FooBarBaz: FooBar {
  var foo: Foo = { intValue in
    // ...
  }
}

Edit 2: Additional information:

According to the Grammar of a function declaration, the only way of declaring a function is to explicitly provide a parameter-clause, which require listing all parameters between parentheses:

function-declaration → function-head function-name generic-parameter-clauseopt function-signature generic-where-clauseopt function-bodyopt

function-signature → parameter-clause throwsopt function-resultopt

parameter-clause → ( ) | ( parameter-list )

So apparently, it's not possible to declare a function with a type as signature without using a closure.

Upvotes: 4

Related Questions