Overload dictionary subscript two times and forward call - swift

I'm trying to extend Dictionary and allow extracting values casted to a certain types and with a given default value. For this I added two overloads for the subscript function, one with a default value, one without:
extension Dictionary {
subscript<T>(_ key: Key, as type: T.Type, defaultValue: T?) -> T? {
// the actual function is more complex than this :)
return nil
}
subscript<T>(_ key: Key, as type: T.Type) -> T? {
// the following line errors out:
// Extraneous argument label 'defaultValue:' in subscript
return self[key, as: type, defaultValue: nil]
}
}
However when calling the three-argument subscript from the two-argument one I get the following error:
Extraneous argument label 'defaultValue:' in subscript
Is this a Swift limitation? Or am I missing something?
I'm using Xcode 10.2 beta 2.
P.S. I know there are other alternatives to this, like dedicated functions or nil coalescing, trying to understand what went wrong in this particular situation.

Subscripts have different rules than functions when it comes to argument labels. With functions, argument labels default to the parameter name – for example if you define:
func foo(x: Int) {}
you would call it as foo(x: 0).
However for subscripts, parameters don't have argument labels by default. Therefore if you define:
subscript(x: Int) -> X { ... }
you would call it as foo[0] rather than foo[x: 0].
Therefore in your example with the subscript:
subscript<T>(_ key: Key, as type: T.Type, defaultValue: T?) -> T? {
// the actual function is more complex than this :)
return nil
}
The defaultValue: parameter has no argument label, meaning that the subscript would have to be called as self[key, as: type, nil]. In order to add the argument label, you need to specify it twice:
subscript<T>(key: Key, as type: T.Type, defaultValue defaultValue: T?) -> T? {
// the actual function is more complex than this :)
return nil
}

Related

What does the swift keyword Wrapped mean in the Optional extension?

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.

Swift 4, Generics why do I need to cast to T here?

When running this code in Swift 4, The compiler throws the following error:
"Cannot convert return expression of type 'Comment?' to return type '_?', when running this code in a playground:
import UIKit
class Comment {}
class Other {}
func itemForSelectedTabIndex<T>(index: Int, type: T.Type) -> T? {
return (type is Comment.Type) ? getComment() : getOther()
}
func getComment() -> Comment {
return Comment()
}
func getOther() -> Other {
return Other()
}
let thing = itemForSelectedTabIndex(index: 0, type: Other.self)
In order to make this work, I need to cast the return value as generic, like this:
return (type is Comment.Type) ? getComment() as! T : getOther() as! T
Could someone explain the logic behind this?
If the expected return value is a 'Generic', and basically it won't matter what type I return, why the compiler complains about it? Shouldn't this work without casting?
Generics aren't some magical wildcards that can just have any value at any time.
When you callitemForSelectedTabIndex(index: 0, type: Comment.self), T is inferred to Comment. Likewise, for Other.
When T has been inferred to Comment, the same value of T is consistent throughout everywhere it's used. Thus, the return value must be of type Comment (or a sub-type).
Another is with your expression (type is Comment.Type) ? getComment() : getOther(). There are 2 cases, and neither of them are valid:
type is Comment.Type: getComment() returns a Comment, a type that is compatible with the value of T, which is Comment. But, the two operands of the conditional operator have no common supertype. That's not valid.
type is not Comment.Type: getOther() returns an Other, which may or may not be compatible with T. All we know about T is that it is not comment. This doesn't mean it's necessarily Other. It can be any other type, like Int. Thus, this return expression fails.
What you need is a common supertype of both types you wish to return. Most probably, a protocol is the correct choice (rather than a shared superclass):
protocol TabItem {}
class Comment {}
class Other {}
func itemForSelectedTabIndex<T: TabItem>(index: Int, type: T.Type) -> TabItem {
return getCommentOrOtherOrSomethingElse()
}

Using Swift function that a function that takes a generic sequence

I'm picking swift up now and the generics are pretty different than what I'm used to. What is the right way to do something like this?
func createThing<T, Seq: Sequence>(_ type: T.Type, _ block : #escaping (_ sequence: Seq) -> Void) where Seq.Element == T {
// ...
}
enum MyEnum {
case A
case B
}
// error: generic parameter 'Seq' could not be inferred
createThing(MyEnum.Type, { sequence in
for i in sequence{
//...
}
})
I would love to just supply a generic type parameter directly with createThing<MyEnum>(...) but that apparently isn't something Swift can do and generics seem to work pretty different for protocols than they do everything else.
Seq is part of the generic signature of the createThing function, which means that the compiler either needs to be able to infer this from the calling context, or be explicitly be told what concrete implementation of Sequence should expect. Also placing the Sequence generic at the function level really limits what you can do within that function, since it cannot instantiate a protocol.
You can convert the (Seq) -> Void block to a (T) -> Void one, and move the sequence iteration in doSomething, this will remove the compile error. And while you're at it, you can add a default value for the type parameter, this will enable type inferring and automatic filling of that parameter
func createThing<T>(_ type: T.Type = T.self, _ block: (T) -> Void) {
// ...
// assuming sequence is create above
sequence.forEach(block)
}
enum MyEnum {
case a
case b
}
// a dedicated function for processing items also means better structured code :)
func processEnum(_ value: MyEnum) {
// do your stuff
}
// you can now pass only the second argument
createThing(processEnum)

What is the syntax for a closure argument in swift

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

Swift Generic constraints in init

I have generic and I want to be able to initialize it with specific constrains. The constraints are only there for initialization. The rest of the class doesn't care. Here is a simplified example:
struct Generic<T> {
let compare: (T, T) -> Bool
init<T: Equatable>(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
insert(data)
}
init(compareHandler: (T, T) -> Bool, data[T]) {
compare = self.compareHandler
insert(data)
}
}
You can see there's two initializers. The second one obviously works fine. However, in the first one the local type T is mismatched with the struct's generic Type. So, for example, attempting to insert data I get Cannot invoke 'insert' with an argument list of type '([T])'. Is it possible for me to specialize the Struct's generic type only for the initialization or a specific function?
Note, I've already tried init<T where T:Equatable>(data: [T]) to the same effect.
Update
I'm using the following workaround: I create a top level function and removing the specialized init:
func equatableHandler<T: Equatable>(left: T, right: T) -> Bool {
return left == right
}
Clients of the struct can initialize using: Generic(compareHandler: equatableHandler, data: data)
It's not quite the "convenience" of using a specialized init, but I suppose it works well enough for my purposes. I'm not a fan of creating top-level functions, but the generic is used so often for "Equatable" generics that it makes sense for me to define the handler once for clients to use.
The problem is that the first init method
init<T: Equatable>(data: [T])
introduces a local type placeholder T which hides (and is completely
unrelated to) the placeholder T of the Generic type, so it
is essentially the same problem as in Array extension to remove object by value.
As of Swift 2 you can solve that with a "restricted extension":
extension Generic where T : Equatable {
init(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
// ...
}
}
For Swift 1.x the only solution is probably to define a global helper
function
func makeGeneric<T : Equatable>(data: [T]) -> Generic<T> {
return Generic(compareHandler: { $0 == $1 }, data: data)
}
(and I could not think of a sensible name for the function :).