What does the parentheses mean in this var declaration? - swift

I'm new to Swift and I just saw this declaration:
var completionHandlers = [(String) -> Void]()
As far as I know, this line is declaring an array of closures of type (String) -> Void, but I'm not sure of what the parentheses mean there.

[MyType]() is just syntactic sugar for Array<MyType>(), which itself is syntactic sugar for Array<MyType>.init(). It initializes an empty array of MyTypes.
It gets its own special syntax because Array is such a common data type.
Dictionary also has syntactic sugar in the style of [String: MyType](), for example.

The parenthesis is a way of calling the initialiser.
This is equivalent to:
var completionHandlers: [(String) -> Void] = []
Another way you will see it is:
var completionHandlers: [(String) -> Void] = .init()
You see it when initialising empty collections because if, for example you had:
var someVariable = ["hello", "world"]
The compiler would be able to infer the type of someVariable to be [String] because it knows the type of the contents. but You can't initialise an empty array like this because there is no information about the type. so [(String) -> Void]() is a way of providing the type to the empty initialiser.
The general recommendation in Swift is to use Type Inference where the type of the variable is inferred from it's initial value:
let intVariable = 3
let stringVariable = "Hello"
//etc
The style of code in your question follows this.
But in some cases with more complex types this can slow down the compiler, so many people are more explicit with their variable declarations.
let intVariable: Int = 3
let stringVariable: String = "Hello"
It's a matter of taste (and argument).

Related

Is there shorthand to specify a specific overload when passing a function as a closure-based argument?

I'm wondering if Swift has a way to let you pass in a specific overload of a function as an argument to a second function that takes a closure with a matching signature, based on type, but without explicitly creating a closure yourself.
Note: This is not a problem I'm trying to solve. It's just a curiosity about the language based on something I ran into when creating an extension to a struct that suddenly broke the compile. It was easily addressed with a closure, like below. It just had me wondering if there was another way to solve it.
Here's code showing what I mean. Let's start with this struct Foo...
struct Foo {
let value: Int
}
Once defined, we can use it as part of a mapping operation via a closure, like so...
let values = [1, 2, 3, 4]
let foos = values.map{ Foo(value: $0) }
However, since the initializer itself already matches the signature of the closure argument type-wise, you can skip the manually-created closure entirely and pass in the function directly, like so...
let values = [1, 2, 3, 4]
let foos = values.map(Foo.init)
What's interesting to note is Swift's compiler finds that match based only on the type of the argument to init, not it's label, which was required earlier in the closure version.
What I discovered is by defining the following extension somewhere in code-scope view of the values.map(Foo.init) call site...
extension Foo {
init(valueToDouble value: Int) { self.value = value * 2 }
}
...that call site suddenly gets flagged as ambiguous and it breaks the compile. This is because even though the labels are different, the argument type--Int in this example--is the same and it doesn't know which one to use.
Now again, this is easily solved with a simple closure, like so...
// Original init
let foos = values.map{ Foo(value: $0) }
// or init in the extension
let foos = values.map{ Foo(valueToDouble: $0) }
I'm just wondering if the Swift compiler has some 'magic sauce' that lets me do something like this...
let foos = values.map(Foo.init(valueToDouble:))
...which obviously doesn't work. :)
So is there anything like that, or is the closure-based version the (only) way to go?
Update
Well, nothing "obvious" about it being wrong because what was wrong is I had a typo (now fixed) and the above syntax does in fact work! Thanks, Itai! :)
In Swift, the "base name" of a method is the method name without any arguments:
Foo.init(x:y:z:) → Foo.init
Foo.bar(_:) → Foo.bar
Foo.baz(baz:) → Foo.baz
Foo.quux() → Foo.quux
When referring to a method by name (rather than calling it), Swift will allow you to refer to it by its base name, so long as the usage is not ambiguous:
struct Foo {
func f(intValue: Int) {}
}
let f = Foo().f
However, when there are multiple methods with the same base name, you can run into situations with ambiguity:
struct Foo {
func f(intValue: Int) {}
func f(stringValue: String) {}
}
let f = Foo().f // error: ambiguous use of 'f'
When this happens, you can either:
Use explicit typing to help disambiguate the methods, if possible:
let f1: (Int) -> Void = Foo().f
let f2: (String) -> Void = Foo().f
Or,
Refer to the method by its fully-qualified name (name with parameter names included):
let f1 = Foo().f(intValue:)
let f2 = Foo().f(stringValue:)
In your case, because both methods have the same type signature, you can't use approach (1) to disambiguate between the calls, and will have to resort to (2).
The issue you ran into is that the parameter name you were using was slightly off:
// ❌ Foo.init(doubleValue:)
// ✅ Foo.init(valueToDouble:)
let foos = values.map(Foo.init(valueToDouble:)) // ✅
This does work, and will work as a shorthand instead of having to call the method directly inside of a closure argument.

How to initialize OrderedDictionary - Swift Collections

Reading from the github docs I can see how to use it, but when I try to initialize it (to empty):
var responses: OrderedDictionary = [:]
it says: Empty collection literal requires an explicit type
I tried this:
var responses: OrderedDictionary<String: <TransactionsDataItemsClassAModel>> = [:]
but doesn't work, what's the proper way to initialize this?
This is how I have initialized my non ordered diccionary:
var dataDiccionary: [String: [TransactionsDataItemsClassAModel]] = [:]
Thanks
The regular syntax for generic types is like Array<T> and Dictionary<K, V>
There's short-hand syntax specific to Array and Dictionary: [T] and [K: V].
You're confusing some things and combined the two into an an invalid middle-ground.
OrderedDictionary doesn't have any special short-hands, so you would just treat it like any other generic type. The generic type parameters are specified with a comma separated list:
OrderedDictionary<String, [TransactionsDataItemsClassAModel]>

Why does a Swift enum with optional associated value require trailing parentheses when being declared?

I have a Swift Enum with a computed property. There are several cases that include a single, optional, associated value. If I want to call the computed property on a variable holding a case value that contains an associated value, then I have to declare the variable with trailing parentheses, otherwise I get a compiler error.
If I don't want to call the computed property, then I don't need to include the parentheses.
Why is that and how are the trailing parentheses changing the "type" of the property such that a computed property can then be called on it?
A simple example to highlight the issue:
import Foundation
enum Animal {
case dog
case other(String? = nil)
var isFriendly:Bool {
switch self {
case .dog: return true
default: return false
}
}
}
// This generates the error:
// Value of type '(String?) -> Animal' has no member 'isFriendly'
let exoticBird = Animal.other
print("Is exotic bird friendly: \(exoticBird.isFriendly)")
// This line, with the trailing parentheses, does not.
let exoticFish = Animal.other()
print("Is exotic fish friendly: \(exoticFish.isFriendly)")
It compiles with Xcode 11 beta and produces a case constructor. Here is the link to Swift evolution proposal.
Your exoticBird is not Animal, it is rather a case constructor. Alt + Click on your exoticBird variable and you will see type of it defined as follows.
let exoticBird: (String?) -> Animal
I think when you leave out associated type in enum, it creates a function based on associated type.
You could pass string to it and then call isFriendly on it like so,
isExoticBird(nil).isFriendly
So, it seems that you cannot leave associated type if you want to create the type explicitly unless you want to do some functional programming.
Now, Small functional transformation with the case constructor type.
Define a function like so,
func isOtherAnimalFriendly(_ f: #escaping (String?) -> Animal) -> (String?) -> Bool {
return { animalName in
f(animalName).isFriendly
}
}
And now, use the following code,
let exoticFish = Animal.other
let namedAnimal = isOtherAnimalFriendly(exoticFish)
Notice that the type of namedAnimal is now,
let namedAnimal: (String?) -> Bool
And you could use this new function with name,
print("Is exotic fish friendly: \(namedAnimal(nil))")
Also use higher order functions such as map on it,
["Cat", "Cow", "Horse"].map(Animal.other) // array of animals with associated values

swift 3.0 Problems about String initialization

I am quite new to Swift and when I learning about initializing a string, I find a wired syntax that I cannot understand.
For example
If I initialize a string using:
var str:String = "Hello, playground"
str.isEmpty
This works well
However, if I initialize a string with a constructor
var str = String("Hello, playground")
str.isEmpty
this does not work.
And the compiler fix it by changing the syntax to
str?.isEmpty
I have no idea about what is that “?” for.
Any suggestion is appreciated.
When you say:
let str = String("Hello, playground")
you're using String's init?(_ description: String) initialiser, which satisfies LosslessStringConvertible's initialiser requirement, as not all types that conform have a representation for an arbitrary string (for example, Double).
Because the initialiser is failable, it returns an optional string instance (i.e String?), hence why the compiler is prompting you to use optional chaining (if not already, I would highly recommend reading the optionals section of the language guide).
However it's worth noting there's absolutely no need for String's implementation of this initialiser to be failable – as a string can always represent a string! This will be fixed in Swift 4, it will be implemented as a non-failable initialiser satisfying the failable requirement. This is because it doesn't break the contract with the protocol of either returning a new instance or nil (it just never happens to do the latter).
In the mean time however, you could just force unwrap the result, as it will always succeed. But really the use of the initialiser here is completely redundant. You should use a string literal, such as in your first example:
let str = "Hello, playground"
str will simply be initialised to a non-optional String instance with the contents of the string literal. Note that Swift can infer str to be of type String – you don't need to explicitly annotate it as such.
var str = String("Hello, playground")
This produces what is called an "Optional". In Swift, if something can be null/nil, then it is wrapped in an Optional. The '?' tries to unwrap the optional and produce a String.
If you KNOW that the value can never be null, then you can force unwrap it like this:
var str = String("Hello, playground")
str!.isEmpty
or
var str2 = String("Hello, playground")!
str2.isEmpty
Generally though forced unwrapping is frowned upon, as it can lead to crashes. Better approaches:
struct MyError:Error {
var message:String
}
guard let str3 = String("Hello, playground") else {
throw MyError(message:"failed")
}
str3.isEmpty
if let str4 = String("Hello, playground") {
str4.isEmpty
}

Difference between [] and []() in Swift

I tried searching around for what this is
[]()
But I'm not really sure. In a playground, I did this:
var test = [Int]();
test.append(1);
test.append(2);
If I leave off the () and do
var test = [Int];
test.append(1);
test.append(2);
It still looks like an array of Ints to me. What is the difference?
Type() means "call init()" - i.e., make a new instance of Type.
[Int] is a type, like String. [Int] means "array-of-Int".
String() makes a new empty String instance. [Int]() makes a new empty array-of-Int instance.
You can declare a variable as being of type array-of-Int. Or you can make and assign a new array-of-Int instance. Which is what you are doing here:
var test = [Int]()
But you cannot assign a type to a variable without further syntax. Thus, this is illegal:
var test = [Int]
EXTRA for experts
You can say:
var test = [Int].self
That does assign the type to the variable! That is unlikely to be what you want here, because now you have no array; you have a type, itself, as object!!
[Type] is syntactic sugar for Array<Type>, so it represents the array type, which is a generic struct, and for which you specify the type of elements it holds (Int in this example)
So the difference between:
[Int]
and
[Int]()
is the same as for
Array<Int>
and
Array<Int>()
The first is just a type, which you can use when declaring a variable or a function parameter.
The second invokes the parameterless constructor on that type, i.e. creates an instance of that type.