Annotating the whole of a function declaration with a typealias - swift

My goal is to use a typealias as a one-word reminder “attached” to a function declaration. Say,
typealias VoidToVoid = () -> ()
I can use the type alias when stating the expected type of a closure, thus
let f : VoidToVoid = { return }
assert(f is VoidToVoid)
However, this does not seem the most usual way of declaring functions. I was hoping for a way to tell the reader that a function declared like f′ below, should be of type VoidToVoid, and using that name.
(But without the reader having to infer, or to think, or to wait for the compiler to tell him or her about the type. Aggravating the situation, the compiler cannot know the type alias name I had wanted with f′ and will likely output messages stating the bare type, not the alias.)
func f′() : VoidToVoid { // tentative syntax
return
}
Can I get there at all?
Edit: There are two ends at which the type alias is to be used. At one end, this is now possible:
func giveMeAClosure(_ f: VoidToVoid) {
f()
}
At the other end, being VoidToVoid is implicit:
func canBeGivenAsClosure() {
// ...
}
That is, where canBeGivenAsClosure is declared, it is true but not obvious that there is a connection between the two ends through VoidToVoid. This is different from the let case, which can have "VoidToVoid" as its type annotation.

Closures are unnamed closure expressions, which is why we may use a function type typealias to specify the type of the closure, even for closures that have a non-empty argument list.
typealias VoidToVoid = () -> ()
typealias IntToVoid = (Int) -> ()
// unnamed closure expressions
let f: VoidToVoid = { print("foo") }
let g: IntToVoid = { print($0) }
Note here that f and g in these exaples are not functions: they are simply immutable properties that holds references to (the backing storage of) the unnamed closures specified at the time of their declaration.
A function, one the other hand, is a special case of a closure; a closure with a name. Moreover, any function with a non-empty argument list needs to supply in internal (and optionally) and external parameter names in its declaration. A function type typealias, however, may not contain argument labels for its parameter names:
typealias IntToVoid = (a: Int) -> ()
/* Error: function types cannot have argument
label 'a'; use '_' instead */
This means that a function type typealias can't possible be used a substitute for the combined parameter and return type declaration part of a function (not even in the () -> () case).
For details, see e.g.:
The Language Guide - Closures
Closures
...
Global and nested functions, as introduced in Functions, are actually
special cases of closures. Closures take one of three forms:
Global functions are closures that have a name and do not capture any values.
Nested functions are closures that have a name and can capture values from their enclosing function.
Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
On another note, you may naturally test the type of a given function to some existing function type typealias.
typealias VoidToVoid = () -> ()
typealias IntToVoid = (Int) -> ()
func f() -> () {}
func g(_ a: Int) -> () { _ = a }
print(f is VoidToVoid) // true
print(g is IntToVoid) // true

Related

Swift Passing a member function to a function that takes an optional closure

I'm trying to construct a table that contains, among other things, an optional closure. When I try to instantiate an instance of the table, passing a member function for the closure I get a compile error.
From the error msg it appears that a member function can not be converted to an optional member function. I don't see why not; an Int or other types can easily be converted to optionals.
struct Foo {
typealias Routine = (_ x: Int) -> Int
let int: Int
let aRoutine: Routine?
init(_ int: Int, _ routine: Routine? = nil) {
self.int = int
self.aRoutine = routine
}
}
class Bar {
let foo = Foo(5, doSomething) // Compile error here
func doSomething(_ x: Int) -> Int {
return x
}
}
Cannot convert value of type '(Bar) -> (Int) -> Int' to expected argument type 'Foo.Routine?' (aka 'Optional<(Int) -> Int>')
You've just discovered that member functions (a.k.a. instance methods) are curried in Swift. See Instance Methods are “Curried” Functions in Swift
Foo.doSomething(_:) isn't just a free function (a.k.a. global function). It's an instance method that has access to the instance, self. But if you just take the method as a closure directly, it doesn't know what the value of self would be.
There are several options:
If your implementation of doSomething(_:) doesn't need to access self, then you can move it out of the Foo's declaration, and declare it as a global function.
Alternatively, you can turn it into a static function by keeping it where it is and using the static modifier. This has an added benefit over a global function, in that it "organizes" your code by moving it into an appropriate namespace.
If your implementation of doSomething(_:) does need an instance to operate on, then you can access the unapplied method of that instance. Here's an example. I've added explicit type annotations for demonstration, but you should usually omit those.
let object: Bar = Bar() // an object of type Bar
let boundDoSomethingMethod: (Int) -> Int = object.doSomething // a bound method which operates on `object`
// alternatively:
let unboundDoSomethingMethod: (Bar) -> (Int) -> Int = Bar.doSomething
let boundDoSomethingMethod: (Int) -> Int = unboundDoSomethingMethod(object)

Are closures implemented as classes in the Swift compiler? Is a common closure a subclass of a throwing closure?

In Swift, the only reference type available to a programmer is a class. We know that closures are objects as they store references to variables captured in the parent scope. Closures are also reference types, according to Apple's Swift Programming Language Guide. You can see that assigning a closure doesn't create a copy of a captured environment and creates a new reference to the existing environment like in this example:
func test1() {
var x = 42
let f = {
print(x)
}
f() // prints 42
// `g` stores a reference to `f`
let g = f
x = 24
g() // prints 24
}
Are closures implemented in the Swift compiler with a similar "infrastructure" used for implementing classes? Is there a code in the compiler internals hidden from language users that could have looked like this when exposed?
// pseudocode
final class Closure<ArgumentType, ReturnType> {
}
typealias ArgumentType -> ReturnType = Closure<ArgumentType, ReturnType>
If so, is there a separate treatment for throwing closures that looks like this?
// pseudocode
final class ThrowingClosure<ArgumentType, ReturnType> {
}
typealias ArgumentType throws -> ReturnType = Closure<ArgumentType, ReturnType>
The main question here is, can we consider a common closure a subclass of a throwing closure? Because it clearly looks like you can assign a common closure to a whatever place that expects a throwing closure type:
func test(f: () throws -> Int, g: () -> Int) {
print((try? f())!)
print((try? g())!)
}
// prints 4 and 2
test(f: { 4 }, g: { 2 })

How to express the type of a constrained-generic function in Swift?

I can define a function
func myGenericFunc<A: SomeProtocol>(_ a: A) -> A { ... }
Now I want to type a variable to hold exactly this kind of function, but I find I can't spell the type:
let f: (SomeProtocol) -> SomeProtocol // doesn't express the genericity
let f: <A: SomeProtocol>(A) -> A // non-existent syntax
Is there any way I can express this directly?
Note that in particular I want f to still be generic: it should accept any SomeProtocol conformer (so no fixing the generic type parameter in advance). In other words: anything I can do with myGenericFunc I want to also be able to do with f.
The quick answer is no, you can't use a single variable to hold different function implementations. A variable needs to hold something concrete for the compiler to allocate the proper memory layout, and it can't do it with a generic construct.
If you need to hold different closure references, you can use a generic type alias:
typealias MyGenericFunction<T: SomeProtocol> = (T) -> T
var f1: MyGenericFunction<SomeConformerType> // expanded to (SomeConformerType) -> SomeConformerType
var f2: MyGenericFunction<AnotherConformerType> // expanded to (AnotherConformerType) -> AnotherConformerType
My original question was about expressing the type directly, but it's also interesting to notice that this is impossible for a different reason:
func myGenericFunc<A: SomeProtocol>(_ a: A) -> A { ... }
let f = myGenericFunc // error: generic parameter 'A' could not be inferred
You could see this as the "deeper reason" there's no spelling for the generic type I wanted: a variable (as opposed to a function) simply cannot be generic in that sense.

Why does an instance method have this type in Swift?

Given this code:
struct Foo {
func f() {}
}
let f = Foo.f // (Foo) -> () -> ()
Why does f have the type (Foo) -> () -> () and not (Foo) -> ()? Wouldn’t it make sense for instance methods like Foo.f to be directly interchangeable with free functions of type (Foo) -> …?
Why does f have the type (Foo) -> () -> () and not (Foo) -> ()?
That's just currently how unapplied instance method references are implemented; they're curried functions that follow the model of "give me an instance, and I'll give you back a partially-applied instance method" (partially applied with that instance).
However this is problematic in some areas, firstly because it's generally more useful for them to be of the form (Self, Args...) -> Ret, but also more importantly because it because it leads to issues around mutating methods. These end up looking like (inout Self) -> (Args...) -> Ret with the current system, which is problematic because the window of mutation for inout only lasts for the duration of the call.
This means the following currently compiles, but is actually undefined behaviour:
struct S {
var i: Int
mutating func increment() {
i += 1
}
}
var s = S(i: 0)
let unappliedIncrement = S.increment
let increment = unappliedIncrement(&s)
increment() // undefined behaviour
These are the main motivations behind SE-0042, which will change unapplied instance method references from being of the form (Self) -> (Args...) -> Ret to being of the form (Self, Args...) -> Ret (and with inout, Self will be inout Self – allowing the mutation of the instance without UB).
This proposal is yet to be implemented, but once it is, assuming empty parameter lists get flattened out (so you don't end up with a trailing Void parameter), Foo.f will indeed be of type (Foo) -> Void.
It's because, by saying this:
let f = Foo.f
you've described f as a class method, Foo.f. But in your declaration of Foo, f is an instance method. You have thus accidentally discovered the deep dark secret that instance methods are class methods in disguise; you are seeing the signature of the secret class method.
If you had said
let f = Foo().f
you would have gotten the expected result.

Swift - What Type is '()'?

I tested some code to understand completion handlers, and I found that there are types such as ()->() and ().
I know ()->() means "no parameters and no return value"; but what type is ()?
If I define a function like this:
func sayHello(){
print("hello")
}
and then check the type:
type(of: sayHello) // ()->()
type(of: sayHello()) // ()
Is "function execution" (()), a type?
What you are really asking is why does type(of: sayHello()) result in ().
Start by thinking about what sayHello() does. It actually calls the function. So type(of:) is telling you the type of the result of that call. Since the return type of sayHello is Void, the type is (). It's basically the second () of () -> () seen in the first call to type(of:).
If you change sayHello to have a return type of Int instead of Void, then the 2nd type(of:) returns Int instead of (). And the 1st type(of:) would change from () -> () to () -> Int.
tl;dr - () represents Void. The return type of calling sayHello().
typealias Void = ()
The return type of functions that don't explicitly specify a return
type; an empty tuple (i.e., ()).
When declaring a function or method, you don't need to specify a
return type if no value will be returned. However, the type of a
function, method, or closure always includes a return type, which is
Void if otherwise unspecified.
Use Void or an empty tuple as the return type when declaring a
closure, function, or method that doesn't return a value.