Can I do swift extensions with inner generics? - swift

I want to make RxSwift and Realm work together, and I tried to build functions to help me.
For example, instead of using the function sorted on Results objects (which give you sorted Results), I want to build a function that do so directly on Observable>.
Thanks to the ObservableType protocol, I managed to do it on non-generic object, but can't find a way to do it on a generic way
Here is my actual code, which works only on specific Object :
public extension ObservableType where E == Results<MyRealmObject> {
public func sorted(key: String, ascending: Bool = true) -> Observable<Results<MyRealmObject>>
{
return self.map { $0.sorted(key, ascending: ascending) }
}
}
If I changed MyRealmObject by T, the compilers tell me that T is undeclared.
I've tried many syntaxes but none are working, and I don't know if it's possible.

I don't have these frameworks, but I'm guessing the types are analogous to the following:
protocol ObservableType {
associatedtype E
}
class Observable<T> : ObservableType {
typealias E = T
init() {}
}
enum Results<T> {
case None
case Some(T)
}
... in which case you could try:
extension ObservableType {
func sorted <T where Self.E == Results<T>> (/* ... */) -> Observable<Results<T>> {
return /* sorted */ Observable()
}
}
... which works:
let o = Observable<Results<Int>>()
o.sorted() // Observable<Results<Int>>
... but is not optimal because:
let x = Observable<Int>()
x.sorted() // compile-time error: Generic parameter `T` could not be infered
... which you'd prefer to say Value of type 'Observable<Int>' has no member 'sorted'. And though the error is at least thrown at compile time, I think your own approach is still preferable.
Just an afterthought based on #Denis Laboureyras' comments
Whilst trying out my solution, Denis could not access the value of type E as Results<T> without casting because the extension does not constrain the type of self but only the parameters of the method. All these issues go away in case of a free function (though I appreciate this is not ideal either):
protocol ObservableType {
associatedtype E
func map <X> (_: E -> X) -> Observable<X>
}
class Observable<T> : ObservableType {
typealias E = T
init() {}
func map <X> (f: E -> X) -> Observable<X> {
return Observable<X>(/* with f(e) */)
}
}
class Results<T> {
func sort(/* ... */) -> Results<T> {
return /* sorted */ self
}
}
func sort <O: ObservableType, T where O.E == Results<T>> (o: O/* ... */) -> Observable<Results<T>> {
return o.map{ $0.sort() }
}
let o = Observable<Results<Int>>()
sort(o) // Observable<Results<Int>>

Related

Why 'there cannot be more than one conformance, even with different conditional bounds'?

I hoped that Swift gives me the ability to create an extension for type with specified conditions in where block. I imagined that I can extend the same generic type with different extensions dependent on concrete generic type value (T). But not. Following example demonstrates my problem:
protocol P {
associatedtype Prop
var property: Prop { get }
}
enum E<T: P> {
case single(T)
case double(T)
}
extension E: P where T.Prop == Int {
var property: Int {
switch self {
case .single(let o): return o.property
case .double(let o): return o.property * 2
}
}
}
extension E: P where T.Prop == String {
var property: String {
switch self {
case .single(let o): return o.property
case .double(let o): return o.property + o.property
}
}
}
struct Int4: P {
var property: Int {
return 4
}
}
struct StringHello: P {
var property: String {
return "Hello"
}
}
print(E.single(Int4()).property)
print(E.double(StringHello()).property)
Following error and note are the result of the compilation.
error: conflicting conformance of 'E' to protocol 'P'; there cannot be more than one conformance, even with different conditional bounds
extension E: P where T.Prop == String {
note: 'E' declares conformance to protocol 'P' here
extension E: P where T.Prop == Int {
Is it really impossible? Why? What can I do with my code to succeed?
Some details to demonstrate the problem in my real situation.
I have some generic enum, which is used with many different wrapped types.
enum Color<T> {
case red(T), green(T)
func map<T2>(_ transform: (T) -> T2) -> Color<T2> {
switch self {
case .red(let o): return .red(transform(o))
case .green(let o): return .green(transform(o))
}
}
}
Very often, I need different extensions for Color to conform it to different protocols depending on the wrapped type. Sometimes these protocols have the same base (super) protocol and as a result, I have the current problem. Sometimes I cant extend Color to conform this base (super) protocol for all deriving protocols because I need different implementations.
Is it impossible? Yes and no. It's not currently possible in Swift, as it has been implemented. It is in principle possible to be implemented.
The name for this is "overlapping conformances", and it was explicitly and purposely rejected. You can find the rationale in the "Alternatives considered" section of SE-0143 Conditional conformances. The TL;DR is: because it's really complicated.
Without knowing more about what exactly you were trying to use this for, there's not much direction we can provide.
As was described earlier you cannot just do this kind of extension. However, you can use hack like this:
protocol SomeExtension {
func doSomething()
}
extension SomeExtension {
func doSomething() {
print("Do nothing or error")
}
}
extension SomeExtension where Self == [String] {
func doSomething() {
print("String")
}
}
extension SomeExtension where Self == [Int] {
func doSomething() {
print("Int")
}
}
extension Array: SomeExtension { }
let stringsArr = ["a", "b", "d"]
let numbersArr = [1, 2, 3]
stringsArr.doSomething()
numbersArr.doSomething()
In console you can see
String
Int

Swift: func return type inheritting class and conforming one or more protocols

From an external library I've got the following scenario.
The protocol and base class:
protocol P1 {
// P1 Stuff
}
class A {
// A Stuff
}
Then there is an extension, which causes my troubles. It is defined for the combination of types P1 and A.
extension P1 where Self : A {
public func myDesiredFunc() {
// Do stuff.
}
}
And finally there are the implementations B1 - Bn, which I use.
class B1 : A, P1 {
}
class B2 : A, P1 {
}
...
In my code I need to put together instances of B-classes and work with them. The problem is, that I need to use the extension func myDesiredFunc(). So I need somehow define, that the array type is something like [(A & P1)] and the return type of producing funciton is (A & P1) as well.
However, with this code:
func createBeeInstance() -> (A & P1) {
if something {
return B1()
} else if something {
return B2()
}
...
}
I'm getting the error:
Non-protocol type 'A' cannot be used within a protocol composition.
Is there a way to say that the return type is a composition of class and protocol? I'm not able to change the scenario because it's an external library.
Swift 4:
^_^
it's possible now to compose class and protocol in swift 4 so modifying the previous snippets to this should work
class A {
// A Stuff
required init () {}
}
protocol P1 {
// P1 Stuff
}
class B1 : A {}
class B3: P1 {}
class B2 : A, P1 {}
func createBeeInstance<T: P1 & A>(type: T.Type) -> T {
return type.init()
}
var things = [P1 & A]() // still Element has to be P1 as well
let f = createBeeInstance(type: B2.self)
//let f1 = createBeeInstance(type: B1.self) // will error
//let f2 = createBeeInstance(type: B3.self) // will error
things.append(f) // is fine
--- OLD Way which did not work ---
You may use this way ,
having the Sample you provided with modifying class A to have init
class A {
// A Stuff
required init () {}
}
modifying createBee method to
func createBeeInstance<T: P1>(type: T.Type) -> T where T: A {
return type.init()
}
this way you will provide the type as an input e.g. B1.self
for array we can provide typealieased generic
typealias B<T:P1> = T where T: A
var things = [B<A>]() // still Element has to be P1 as well
let f = createBeeInstance(type: B2.self)
let f1 = createBeeInstance(type: B1.self)
things.append(f)
One possible solution would be to define a protocol that defines the essential nature of objects of type A (let's call the new protocol Aable), and make the A type conform to it:
class A: Aable {
// A stuff
}
You could then constrain the P1 protocol extension with Aable instead of A:
extension P1 where Self : Aable {
func myDesiredFunc() {
// Do stuff.
}
}
That would allow you to use protocol composition for the return type of a function...
func createBeeInstance(useB1: Bool) -> (Aable & P1) {
return useB1 ? B1() : B2()
}
...as well as for the element type of an array:
var things = [Aable & P1]()
for i in 1...5 {
let b = createBeeInstance(useB1: i % 2 == 0)
things.append(b)
}
for thing in things {
thing.myDesiredFunc()
}

How do I declare a generic function in a protocol that returns self? [duplicate]

I have a protocol P that returns a copy of the object:
protocol P {
func copy() -> Self
}
and a class C that implements P:
class C : P {
func copy() -> Self {
return C()
}
}
However, whether I put the return value as Self I get the following error:
Cannot convert return expression of type 'C' to return type 'Self'
I also tried returning C.
class C : P {
func copy() -> C {
return C()
}
}
That resulted in the following error:
Method 'copy()' in non-final class 'C' must return Self to conform
to protocol 'P'
Nothing works except for the case where I prefix class C with final ie do:
final class C : P {
func copy() -> C {
return C()
}
}
However if I want to subclass C then nothing would work. Is there any way around this?
The problem is that you're making a promise that the compiler can't prove you'll keep.
So you created this promise: Calling copy() will return its own type, fully initialized.
But then you implemented copy() this way:
func copy() -> Self {
return C()
}
Now I'm a subclass that doesn't override copy(). And I return a C, not a fully-initialized Self (which I promised). So that's no good. How about:
func copy() -> Self {
return Self()
}
Well, that won't compile, but even if it did, it'd be no good. The subclass may have no trivial constructor, so D() might not even be legal. (Though see below.)
OK, well how about:
func copy() -> C {
return C()
}
Yes, but that doesn't return Self. It returns C. You're still not keeping your promise.
"But ObjC can do it!" Well, sort of. Mostly because it doesn't care if you keep your promise the way Swift does. If you fail to implement copyWithZone: in the subclass, you may fail to fully initialize your object. The compiler won't even warn you that you've done that.
"But most everything in ObjC can be translated to Swift, and ObjC has NSCopying." Yes it does, and here's how it's defined:
func copy() -> AnyObject!
So you can do the same (there's no reason for the ! here):
protocol Copyable {
func copy() -> AnyObject
}
That says "I'm not promising anything about what you get back." You could also say:
protocol Copyable {
func copy() -> Copyable
}
That's a promise you can make.
But we can think about C++ for a little while and remember that there's a promise we can make. We can promise that we and all our subclasses will implement specific kinds of initializers, and Swift will enforce that (and so can prove we're telling the truth):
protocol Copyable {
init(copy: Self)
}
class C : Copyable {
required init(copy: C) {
// Perform your copying here.
}
}
And that is how you should perform copies.
We can take this one step further, but it uses dynamicType, and I haven't tested it extensively to make sure that is always what we want, but it should be correct:
protocol Copyable {
func copy() -> Self
init(copy: Self)
}
class C : Copyable {
func copy() -> Self {
return self.dynamicType(copy: self)
}
required init(copy: C) {
// Perform your copying here.
}
}
Here we promise that there is an initializer that performs copies for us, and then we can at runtime determine which one to call, giving us the method syntax you were looking for.
With Swift 2, we can use protocol extensions for this.
protocol Copyable {
init(copy:Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(copy: self)
}
}
There is another way to do what you want that involves taking advantage of Swift's associated type. Here's a simple example:
public protocol Creatable {
associatedtype ObjectType = Self
static func create() -> ObjectType
}
class MyClass {
// Your class stuff here
}
extension MyClass: Creatable {
// Define the protocol function to return class type
static func create() -> MyClass {
// Create an instance of your class however you want
return MyClass()
}
}
let obj = MyClass.create()
Actually, there is a trick that allows to easily return Self when required by a protocol (gist):
/// Cast the argument to the infered function return type.
func autocast<T>(some: Any) -> T? {
return some as? T
}
protocol Foo {
static func foo() -> Self
}
class Vehicle: Foo {
class func foo() -> Self {
return autocast(Vehicle())!
}
}
class Tractor: Vehicle {
override class func foo() -> Self {
return autocast(Tractor())!
}
}
func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
let vehicle = Vehicle.foo()
let tractor = Tractor.foo()
print(typeName(vehicle)) // Vehicle
print(typeName(tractor)) // Tractor
Swift 5.1 now allow a forced cast to Self, as! Self
1> protocol P {
2. func id() -> Self
3. }
9> class D : P {
10. func id() -> Self {
11. return D()
12. }
13. }
error: repl.swift:11:16: error: cannot convert return expression of type 'D' to return type 'Self'
return D()
^~~
as! Self
9> class D : P {
10. func id() -> Self {
11. return D() as! Self
12. }
13. } //works
Following on Rob's suggestion, this could be made more generic with associated types. I've changed the example a bit to demonstrate the benefits of the approach.
protocol Copyable: NSCopying {
associatedtype Prototype
init(copy: Prototype)
init(deepCopy: Prototype)
}
class C : Copyable {
typealias Prototype = C // <-- requires adding this line to classes
required init(copy: Prototype) {
// Perform your copying here.
}
required init(deepCopy: Prototype) {
// Perform your deep copying here.
}
#objc func copyWithZone(zone: NSZone) -> AnyObject {
return Prototype(copy: self)
}
}
I had a similar problem and came up with something that may be useful so I though i'd share it for future reference because this is one of the first places I found when searching for a solution.
As stated above, the problem is the ambiguity of the return type for the copy() function. This can be illustrated very clearly by separating the copy() -> C and copy() -> P functions:
So, assuming you define the protocol and class as follows:
protocol P
{
func copy() -> P
}
class C:P
{
func doCopy() -> C { return C() }
func copy() -> C { return doCopy() }
func copy() -> P { return doCopy() }
}
This compiles and produces the expected results when the type of the return value is explicit. Any time the compiler has to decide what the return type should be (on its own), it will find the situation ambiguous and fail for all concrete classes that implement the P protocol.
For example:
var aC:C = C() // aC is of type C
var aP:P = aC // aP is of type P (contains an instance of C)
var bC:C // this to test assignment to a C type variable
var bP:P // " " " P " "
bC = aC.copy() // OK copy()->C is used
bP = aC.copy() // Ambiguous.
// compiler could use either functions
bP = (aC as P).copy() // but this resolves the ambiguity.
bC = aP.copy() // Fails, obvious type incompatibility
bP = aP.copy() // OK copy()->P is used
In conclusion, this would work in situations where you're either, not using the base class's copy() function or you always have explicit type context.
I found that using the same function name as the concrete class made for unwieldy code everywhere, so I ended up using a different name for the protocol's copy() function.
The end result is more like:
protocol P
{
func copyAsP() -> P
}
class C:P
{
func copy() -> C
{
// there usually is a lot more code around here...
return C()
}
func copyAsP() -> P { return copy() }
}
Of course my context and functions are completely different but in spirit of the question, I tried to stay as close to the example given as possible.
Just throwing my hat into the ring here. We needed a protocol that returned an optional of the type the protocol was applied on. We also wanted the override to explicitly return the type, not just Self.
The trick is rather than using 'Self' as the return type, you instead define an associated type which you set equal to Self, then use that associated type.
Here's the old way, using Self...
protocol Mappable{
static func map() -> Self?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> Self? {
...
}
}
Here's the new way using the associated type. Note the return type is explicit now, not 'Self'.
protocol Mappable{
associatedtype ExplicitSelf = Self
static func map() -> ExplicitSelf?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> SomeSpecificClass? {
...
}
}
To add to the answers with the associatedtype way, I suggest to move the creating of the instance to a default implementation of the protocol extension. In that way the conforming classes won't have to implement it, thus sparing us from code duplication:
protocol Initializable {
init()
}
protocol Creatable: Initializable {
associatedtype Object: Initializable = Self
static func newInstance() -> Object
}
extension Creatable {
static func newInstance() -> Object {
return Object()
}
}
class MyClass: Creatable {
required init() {}
}
class MyOtherClass: Creatable {
required init() {}
}
// Any class (struct, etc.) conforming to Creatable
// can create new instances without having to implement newInstance()
let instance1 = MyClass.newInstance()
let instance2 = MyOtherClass.newInstance()

Extending the SequenceType in Swift

I wondered why map() and filter() in SequenceType return both an Array.
Actually, I don't think that's necessary. Returning a sequence again feels much more sensible to me.
However, I got stuck when trying to add sequential versions. Here's my attempt with map:
extension SequenceType {
func seqMap<T, S: SequenceType where S.Generator.Element == T>(
transform: Self.Generator.Element -> T) -> S
{
var sourceGen = generate()
let tGen: AnyGenerator<T> = anyGenerator {
if let el = sourceGen.next() {
return transform(el)
} else {
return nil
}
}
return AnySequence { tGen }
}
}
XCode tells me at the last return statement the following error:
cannot invoke initializer for type 'AnySequence<T>' with an argument list of type '(() -> AnyGenerator<T>)'
note: overloads for 'AnySequence<T>' exist with these partially matching parameter lists: (S), (() -> G)
Actually, my tGen is of type () -> G, so why does XCode think it is ambiguous?
The problem becomes more apparent if you split the return statement:
let tSeq = AnySequence { tGen }
return tSeq // error: cannot convert return expression of type 'AnySequence<T>' to return type 'S'
The compiler would infer the placeholder type S from the context
of a method call, and that could be any sequence
type with element type T, and not necessarily an AnySequence.
Here is a simple example demonstrating the same problem:
protocol MyProtocol { }
struct MyType { }
extension MyType : MyProtocol { }
func foo<P : Protocol>() -> P {
return MyType() // error: cannot convert return expression of type 'MyType' to return type 'P'
}
To solve the problem, change the return type to AnySequence<T>
and drop the generic type S:
extension SequenceType {
func seqMap<T>(transform: Self.Generator.Element -> T) -> AnySequence<T>
{
var sourceGen = generate()
let tGen: AnyGenerator<T> = anyGenerator {
if let el = sourceGen.next() {
return transform(el)
} else {
return nil
}
}
return AnySequence { tGen }
}
}
which can be written more compactly as
extension SequenceType {
func seqMap<T>(transform: Self.Generator.Element -> T) -> AnySequence<T>
{
var sourceGen = generate()
return AnySequence(anyGenerator {
sourceGen.next().map(transform)
})
}
}
using the map() method of the Optional type.
But note that SequenceType already has a lazy method which returns
a LazySequenceType:
/// A sequence containing the same elements as a `Base` sequence, but
/// on which some operations such as `map` and `filter` are
/// implemented lazily.
///
/// - See also: `LazySequenceType`
public struct LazySequence<Base : SequenceType>
and you can use
someSequence.lazy.map { ... }
to get a (lazily evaluated) sequence of the mapped values.

Implementing generic interfaces in Apple's Swift

I have a class with a property which should have as type what in other languages would be called a generic (or template) interface. When I try to mimic this behavior in Swift I cannot get protocols to work with the idea. For example:
protocol P {
typealias T
func returnT() -> T
}
class G<T>: P {
var t: T
init(t: T) {
self.t = t
}
func returnT() -> T {
return t
}
}
class C {
var p: P<Int> // Cannot specialize non-generic type 'P'
init(instanceOfP: P<Int>) { // Cannot specialize non-generic type 'P'
p = instanceOfP
}
func usePsT() -> Int {
return p.returnT() // 'P' does not have a member named 'returnT'
}
}
Errors from the compiler are reported as comments. It seems clear to me that such a situation should not be problematic: but since Swift's protocols cannot be generics (they use this obscure typealias syntax instead) C has no way to know that every class that implements P can be specialized for Int. Is there a Swift-y way to represent this situation correctly? Or is there any known workaround so that I don't have to force or de-generalize the class structure?
The generic isn't really needed in your protocol (use Any) - it's needed in your class G<T>. You could do this...
protocol P {
func returnT() -> Any
}
class G<T>: P {
var t: T
init(t: T) {
self.t = t
}
func returnT() -> Any {
return t
}
}
class C {
var p: P
init(instanceOfP: P) {
p = instanceOfP
}
func usePsT() -> Any {
return p.returnT()
}
}
let gi = G<Int>(t: 7) // {t 7}
let ci = C(instanceOfP: gi) // {{t 7}}
ci.usePsT() // 7
let gs = G<String>(t: "Hello")
let cs = C(instanceOfP: gs)
cs.usePsT() // "Hello"
My solution is not ideal but saves me a lot of complications, still code is readable...
Instead of interfaces I use base class with open empty functions.
Like this:
public class CSTableControllerFilter<Row: CSTableControllerRow, Data> {
open func filter(data: [Row]) -> [Row] { data }
open func onReloadDone(in controller: CSTableController<Row, Data>) {}
}