Trying to make sense of the code below.
I understand that T is passed by when instantiating the Optional, as in Optional, but what about the U type in map. What type does that assume?
enum Optional<T> : LogicValue, Reflectable {
case None
case Some(T)
init()
init(_ some: T)
/// Allow use in a Boolean context.
func getLogicValue() -> Bool
/// Haskell's fmap, which was mis-named
func map<U>(f: (T) -> U) -> U?
func getMirror() -> Mirror
}
The type U comes from the f parameter to the map function. So if you pass a closure that returns a Int, then map returns a Int?. If you pass a closure that returns a Array<Int>, then map returns a Array<Int>?.
For example, try this:
var opt1: Optional<Int> = .Some(1)
var opt2 = opt1.map { (i: Int) -> String in return "String: \(i)" }
You'll find that opt1 is an Int? and opt2 is a String?.
When calling the map function the caller must provide a single argument which is a closure that:
Has a single argument that is the same type as the one used to
instantiate Optional, i.e. T
Has a return value of some type.
U will then be the type of said return value.
Related
What does the swift keyword Wrapped mean in the Optional extension?
extension Optional {
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U? {
guard let x = self else { return nil }
return transform(x)
}
}
In extensions, the generic parameters of the type that you are extending can be referenced by just writing their simple names, and notice that Optional is a generic type.
#frozen enum Optional<Wrapped>
So Wrapped in the function declaration refers to the generic parameter declared there.
As you may know, optional types are usually written as T? (where T is some type), which is a syntactic sugar for Optional<T>. For example, Int? is the same as Optional<Int>, and String? is the same as Optional<String>, etc.
In other words, Wrapped basically just means the type that precedes the ?, whatever that may be. If you have a String? (aka Optional<String>), then the signature of flatMap for that would be:
func flatMap<U>(_ transform: (String) -> U?) -> U?
There is no keyword "Wrapped." This is a type parameter. This is similar to runtime parameters. If you see:
func f(x: Int) { ... }
x is not a keyword. It's just a parameter name. In the same way, Optional is defined as:
enum Optional<Wrapped>
"Wrapped" is just the type parameter passed to Optional. So in this extension:
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U? {
"Wrapped" just refers to whatever Optional is wrapping.
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)
In my simplified example I'm getting the error: Cannot convert value of type 'Foo' to expected argument type BaseItem<Any>
But the class Foo extends BaseItem<String>.
This is the example code:
class BaseItem<T> {
var param: T?
}
class Foo: BaseItem<Int> {
}
func checkItem(item: BaseItem<Any>) -> Bool{
return item.param != nil;
}
I get the error when calling
checkItem(item: Foo())
What am I missing?
You need to define your checkItem function in terms of generics too:
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
Gotta define checkItem function with generics too.
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
The problem is that generics are invariant – consider if your checkItem(item:) function had said:
func checkItem(item: BaseItem<Any>) {
item.param = "foo"
}
That would be illegal for a BaseItem<Int>, as you cannot possibly assign a String instance to an Int? property – which is why it (an instance of Foo) cannot be typed as a BaseItem<Any>.
The solution, as other answers have said, is to use a generic placeholder for the function:
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
Now, rather than saying that you're taking a BaseItem<Any>, that has a param of type Any? (can be assigned a value of any type) – you're now saying that you're taking a BaseItem with any specific placeholder type; which will be satisfied at the call-site of the function.
The function implementation itself therefore cannot make any assumptions about this type, and will disallow the assignment of an arbitrary value to param. The compiler will only allow an assignment of a value of type T.
The signature of checkItem function should be: checkItem<T>(item: BaseItem<T>) -> Bool, as follows:
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
Usage:
checkItem(item: Foo()) // false
let myFoo = Foo()
myFoo.param = 0
checkItem(item: myFoo) // true
The reason of why the compiler complains about
Cannot convert value of type 'Foo' to expected argument type
BaseItem
is that you are trying to pass BaseItem<Int> instance as BaseItem<Any> which is invalid (Any data type is not T generic type).
I am attempting to create a function that can return any type. I do not want it to return an object of type Any, but of other types, i.e. String, Bool, Int, etc. You get the idea.
You can easily do this using generics in this fashion:
func example<T>(_ arg: T) -> T {
// Stuff here
}
But is it possible to do it without passing in any arguments of the same type? Here is what I am thinking of:
func example<T>() -> T {
// Stuff here
}
When I try to do this, everything works until I call the function, then I get this error:
generic parameter 'T' could not be inferred
is it possible to do it without passing in any arguments of the same type?
The answer is yes, but there needs to be a way for the compiler to infer the correct version of the generic function. If it knows what it is assigning the result to, it will work. So for instance, you could explicitly type a let or var declaration. The below works in a playground on Swift 3.
protocol Fooable
{
init()
}
extension Int: Fooable {}
extension String: Fooable {}
func foo<T: Fooable>() -> T
{
return T()
}
let x: String = foo() // x is assigned the empty string
let y: Int = foo() // y is assigned 0
In Swift headers, the isSeparator: argument accepts a closure
public func split(maxSplit: Int = default, allowEmptySlices: Bool = default, #noescape isSeparator: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.SubSequence]
But in the documentation, it lists closure syntax differently
{ (parameters) -> return type in
statements
}
How are you supposed to know that (Self.Generator.Element) throws -> Bool rethrows refers to a closure / requires a closure? Are there other ways that the headers/docs might list argument as meaning a closure?
The "thing" giving away that this is a closure is the ->. The full type is
(Self.Generator.Element) throws -> Bool
It means that the closure takes a variable of type Self.Generator.Element and has to return a Bool upon some calculation based on the input. It may additionally throw some error while doing so - that is what the throws is for.
What you then write
{ (parameters) -> return type in
statements
}
would be an actual implementation, a value of some generic closure type.
The type of a closure is for example (someInt:Int, someDouble:Double) -> String:
var a : ((someInt:Int, someDouble:Double) -> String)
Once again the thing giving away that a is actually a closure is the -> in the type declaration.
Then you assign something to a via some code snippet following your second code block:
a = { (integer, floating) -> String in
return "\(integer) \(floating)"
}
You can tell by the argument's type. Everything in Swift has a type, including functions and closures.
For example, this function...
func add(a: Int, to b: Int) -> Int { return a + b }
...has type (Int, Int) -> Int. (It takes two Ints as parameters, and returns an Int.)
And this closure...
let identity: Int -> Int = { $0 }
...has type Int -> Int.
Every function and closure has a type, and in the type signature there is always a -> that separates the parameters from the return value. So anytime you see a parameter (like isSeparator) that has a -> in it, you know that the parameter expects a closure.
the isSeparator definition means (Self.Generator.Element) throws -> Bool that you will be given an Element and you should return a Bool. When you will call split, you then can do the following :
[1,2,3].split(…, isSeparator : { element -> Bool in
return false
})
This is a pure silly example but that illustrates the second part of your question