Why specializing a generic function explicitly is not allowed? - swift

In Swift, one should use type of parameters or return value to implicitly specialize a generic function. The problem is, when I call function like this:
func serialize<T>(continuation: GenericWithLongName<T, NSError> -> Void) -> Void
I cannot just write
serialize<SomeType> {
obj in
...
}
It should be
serialize {
(obj: GenericWithLongName<SomeType, NSError>) -> Void in
...
}
which looks painful.
It seems this "feature" exists for a long time. Is it a design decision? Is there any negative implication from allowing explicitly specialization?
And is there any way to make code above neat and clean without refactoring that generic class?

One way to "specialize" the function is by including the generic type as a function parameter:
func serialize<T>(
t: T.Type,
continuation: GenericWithLongName<T, NSError> -> Void ) -> Void { }
Now you can "specialize" the function like this:
serialize(SomeType.self) {
obj in
...
}
I don't know the answer to why your requested feature is not available. I agree that the feature you recommend would be useful, but in the meantime this works just as well and is almost as concise.

Related

Swift Protocol inheriting Protocol method with same name

While reading swift forum about exceptions I found interesting issue. One of the examples about exceptions was something like this:
protocol Base {
func foo() throws -> Int
}
protocol Refined: Base {
func foo() -> Int
}
struct Test: Refined {
func foo() -> Int {
0
}
}
It's interesting, I thought it was typo that it would not compile, but it does. I am not sure how this does work behind the scenes. I mean when protocol adopts another protocol it adopts also its requirements. But in this case declaring same method without throws somehow satisfies also first protocol Base.
At the very least I expected Test to need to have 2 implementations of foo. What am I missing here?
This is because a non-throwing function is by definition a sub-type of a throwing function
From the Swift Programming Language book
The throws keyword is part of a function’s type, and nonthrowing functions are subtypes of throwing functions. As a result, you can use a nonthrowing function in the same places as a throwing one.
But you can't do it the other way around so the below code will generate an error
protocol Base {
func foo() -> Int
}
protocol Refined: Base {
func foo() throws -> Int //error: Cannot override non-throwing method with throwing method
}
Also note that this is not only for protocols, if you remove the func declaration from Refined you can still implement the function in Test as non throwing.

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)

Generic completion passed as non-generic

I'm working on some framework and faced a problem.
I have a public protocol:
public protocol MyPublicProtocol1 {
}
And another one, wich contains a function with generic argument passed. Generic argument has a constraint – argument type must implement the first public protocol:
public protocol MyPublicProtocol2 {
func someFunc<T: MyPublicProtocol1>(completion: (T) -> ())
}
Then I'm implementing my protocols not in public classes. Inside that function with generic argument I have to call another one that takes not generic argument and look like that:
func anotherFuncWith(completion: (MyPublicProtocol1) -> ())
And here's what implementation looks like:
class MyPublicProtocol1Impl: MyPublicProtocol1 {
}
class MyPublicProtocol2Impl: MyPublicProtocol2 {
func someFunc<T: MyPublicProtocol1>(completion: (T) -> ()) {
anotherFuncWith(completion: completion)
}
}
And of course I have an error in the last string.
I can't declare someFunc(completion:) with not a generic argument like:
func someFunc(completion: (MyPublicProtocol1Impl) -> ())
Because MyPublicProtocol1Impl class mustn't be public. And I also can't declare anotherFuncWith(completion:) to take generic argument too for some reasons.
Is there a way to somewhat "convert" (T: MyPublicProtocol1) -> () completion to be just a (MyPublicProtocol1) -> ()?
Any help or advices are very appreciated! And thank you for reading my story!
You've asked for something that is not provably true. You have a method:
func anotherFuncWith(completion: (MyPublicProtocol1) -> ())
This accepts a method that can receive any MyPublicProtocol1. You then pass it a method of type:
(T: MyPublicProtocol1) -> ()
anotherFuncWith may pass something that is not T, at which point this is undefined. To make it more concrete, let's get rid of most of the stuff here and make MyPublicProtocol1 be Any (just to pick a trivial protocol).
func anotherFuncWith(completion: (Any) -> ()) {
completion("This is a string which is an Any, so that's fine")
}
func someFunc<T: Any>(completion: (T) -> ()) {
anotherFuncWith(completion: completion)
}
This fails to compile exactly like your example. Now let's think through what I could do if it did compile. I could call:
func complete(x: Int) -> () {
print(x + 1)
}
someFunc(completion: complete)
So now anotherFuncWith calls complete passing a String, which can't be added. Crash.
The underlying problem here is that you've gotten covariance and contravariance backwards.
How do we fix it? Depends on what you really mean. This code is a little strange. Do you care about the actual type of T or not? You never seem to use it. If you don't care, then just use protocols:
public protocol MyPublicProtocol2 {
func someFunc(completion: (MyPublicProtocol1) -> ())
}
If you do care about the actual type, use a PAT:
public protocol MyPublicProtocol2 {
associatedtype T: MyPublicProtocol1
func someFunc(completion: (T) -> ())
}
Or you may want to rethink whether you need a protocol here at all. I often find people reach for protocols when they don't need them yet. Do you have multiple implementations of these protocols? Do you have multiple types that are passed? If not, I'd simplify and only go generic/protocol when you have a real problem you're solving in the current code. (You may need them; this is just my stock advice that many people have found useful when they've over-designed.)
The dirty way to get around this is
func someFunc<T: MyPublicProtocol1>(completion: (T) -> ()) {
anotherFuncWith { (thing) in
if let tThing = thing as? T {
completion(tThing)
}
}
}
I would only do this if you are very sure of the code surrounding it as it is certainly fallible.
Also, this works too. I'm unsure what you're actually trying to do so I'm not sure if it solves your problem
func anotherFuncWith<T: MyPublicProtocol1>(completion: (T) -> ()) {
}
class MyPublicProtocol2Impl: MyPublicProtocol2 {
func someFunc<T: MyPublicProtocol1>(completion: (T) -> ()) {
anotherFuncWith(completion: completion)
}
}

Infer closure return type from closure body when working with generics

I think best if I start with an example:
class Test<T> {
func test(closure: (T) -> Void) { }
func test(closure: (T) -> T) { }
func test(closure: (T) -> Test<T>) { }
}
Test<Int>().test { a in }
The code above gives the following error:
error: ambiguous use of 'test'
This is because the Swift compiler doesn't know to which one of the three methods is should map the call to. But from the closure body it's quite clear that it returns a Void, so it should pick the first method.
Looks like the Swift compiler cannot determine to which method overload to map the call to based on the closure body. If I explicitly specify the closure signature, then the problem goes away:
Test<Int>().test { (a: Int) -> Void in }
My question is: can I somehow instruct Swift to pick-up the correct overload for short-hand closure expressions like the one in discussion, or will I have to explicitly declare the closure signature?
Actually, it seems that I was pushing the compiler limits too hard (as #Martin R pointed in the comments). The { a in } closure was kinda incomplete, since the compiler had no statements to infer the closure return type from.
This works:
Test<Int>().test { (a: Int) -> Void in () }
Same as the following:
func doNothing() { }
Test<Int>().test { (a: Int) -> Void in doNothing() }
In the above examples the compiler is provided with the minimum amount of information to determine which overload to pick.

Lenses into Swift properties

Is there some way to automatically generate a getter/setter function pair for a property in a class in Swift? Something along the lines of a lens in Haskell.
I've been able to do the following manually:
class PropertyLens<U, T> {
let getter: U -> T
let setter: (U, T) -> ()
init(getter: (U -> T), setter: ((U, T) -> ())) {
self.getter = getter
self.setter = setter
}
func get(u: U) -> T {
return getter(u)
}
func set(u: U, t: T) {
setter(u, t)
}
}
// ...
let myPropertyLens = PropertyLens<MyClass, Int>(getter: { $0.myProperty }, setter: { $0.myProperty = $1 })
However, that becomes verbose, tedious, and more error-prone than I'd like. Is there a built-in feature I'm missing?
For the answer itself, so far (1.1) no language construct will substitute what you are doing (wrapping the access process of a stored property into a referenciable object).
For the opinion part of the answer, it looks like your code only works with public variables, which are nasty for they break basic encapsulation rules, is that correct?
You should give Sourcery a try. I have the same problem and I run into this tool, if you make a quick search you should easily find some already made templates for Sourcery that lets you generate lenses for your data types.