0

I am trying to create a protocol R with an array of objects n which can be, in principle, different classes (N1, N2) but all subjects of the same protocol N. Classes that submit to the protocol R (M1, M2) can decide whether their property array n will hold only specific kind of R or any.

This compiles just fine:

protocol N { }
class N1: N { }
class N2: N { }

protocol R {
    associatedtype NType
    var n: [NType] { get set }
}

class M1: R {
    var n: [N] = [N1(), N2()]
}

class M2: R {
    var n: [N1] = [N1(), N1()]
}

But I don't understand how to add a constraint to the associatedtype Ntype that it must conform to N. Something in the lines of

protocol N { }
class N1: N { }
class N2: N { }

protocol R {
    associatedtype NType: N
    var n: [NType] { get set }
}

class M1: R {
    var n: [N] = [N1(), N2()]
}

class M2: R {
    var n: [N1] = [N1(), N1()]
}

This doesn't compile saying that Type 'M1' does not conform to protocol 'R'.

AnderCover
  • 2,488
  • 3
  • 23
  • 42
Jan12
  • 101
  • 7
  • You can make `N` an `@objc` protocol. See [here](https://stackoverflow.com/questions/33112559/protocol-doesnt-conform-to-itself) for more info. – Sweeper Dec 05 '22 at 14:41
  • Or skip the associated type and declare n as `var n: [N] { get set }` although then you must always implement `n` exactly as that. – Joakim Danielson Dec 05 '22 at 14:48
  • @Sweeper Thanks, your method works! – Jan12 Dec 05 '22 at 14:51
  • @JoakimDanielson As you commented yourself the solution is not optimal because then `M2` can't have property `n` stored as `[N1]`. – Jan12 Dec 05 '22 at 14:53

1 Answers1

0

Using swift 5.7.1 you can use [any N] I would not change N, N1, N2 or R:

protocol N { }
class N1: N { }
class N2: N { }

protocol R {
    associatedtype NType
    var n: [NType] { get set }
}

But I would implement M1 differently using and array of any N eg.:

class M1: R {
    var n: [any N] = [N1(), N2()]
}

which compiles and prints:

let m1 = M1()
print(m1.n) // [__lldb_expr_13.N1, __lldb_expr_13.N2]
m1.n.append(N2()) // [N1, N2, N2]
m1.n.append(N1()) // [N1, N2, N2, N1]

but it can also hold a specific kind of N, eg.:

class M2: R {
    var n: [N1] = [N1(), N1()]
}

which outputs:

let m2 = M2()
print(m2.n) // [__lldb_expr_17.N1, __lldb_expr_17.N1]
m2.n.append(N1()) // [N1, N1, N1]
m2.n.append(N2()) // No exact matches in call to instance method 'append'

as you can see m1.n is an heterogeneous array of objects conforming to NType aka N while m2.n can only hold N1 values.

AnderCover
  • 2,488
  • 3
  • 23
  • 42
  • This is true and I have already provided this solution in the first code snippet in the question. What I would like to know is how to add constraint on NType that it must conform to protocol N, which now that I ask it like that, requires a protocol to conform to itself, which I know is not allowed. But maybe there is a way by restructuring the code or something. I know that it works if I convert `N` to a class, but this is not an ideal solution. – Jan12 Dec 06 '22 at 06:27
  • I don't see `[any N]` in you code snippets, `Any N` means any type conforming to `N` and it looks like what you are looking for. Anyway this is the way I would _restructure_ the code. I edited my answer for clarity. – AnderCover Dec 06 '22 at 15:05
  • But using this solution I must force cast `n` to `[any N]` if I only know that an instance is conforming to protocol `R` but not necessarily which class it is. In other words, you do not answer the question on how to add constraint on `Ntype` so that it conforms to `N`. – Jan12 Dec 07 '22 at 08:10
  • Here you have a protocol R with an array of objects `n` which can be, in principle, different classes (`N1`, `N2`) but all subjects of the same protocol `N`. Classes that submit to the protocol `R` (`M1`, `M2`) can decide whether their property array `n` will hold only specific kind of `N` or `any N`. Can you explain why you need to force cast? – AnderCover Dec 07 '22 at 12:42
  • 1
    "Here you have a protocol R with an array of objects `n` which can be, in principle, different classes (`N1`, `N2`) but all subjects of the same protocol `N`." Where exactly is this constraint placed in your code? Let's say I create an array `r: [any R]` and an element of `r` will know that it has a property called `n` of type `[NType]`, but `NType` is at this point undefined, i. e. `Any`. I can cast it to `[N]` but I want to avoid it. – Jan12 Dec 07 '22 at 14:17