public enum Outer<Inner> { }
public extension Outer where Inner == Self { }
yields
Cannot build rewrite system for generic signature; concrete nesting limit exceeded
I think that means it's impossible to combine the following into one type. Correct?
enum ReferenceArrayNest<Element> {
case element(Element)
case array([Reference<Self>] = [])
}
enum ValueArrayNest<Element> {
case element(Element)
case array([Self] = [])
}
/// Adds reference semantics to a value type.
@propertyWrapper public final class Reference<Value> {
public var wrappedValue: Value
public var projectedValue: Reference { self }
public init(wrappedValue: Value) {
self.wrappedValue = wrappedValue
}
}
…and it's also impossible to write either of those types to use Sequence<Self>-deriving protocols, rather than copying and pasting again for any type other type but Array?
What do you mean by “combining” into one type? With a wrapper type? If so, do you need to express additional generic parameters on that type? What errors are you encountering when you try?
And what to you mean about “using” Sequence-derived protocols? Do you want to conform your enums to Collection and other protocols in the hierarchy? If so, what is the difficulty you need to work around when trying to do so?
What’s the relationship between @propertyWrapper class Reference<Value> and enum ReferenceArrayNest and enum ValueArrayNest? Without understanding that, I find it difficult to grasp your ultimate goal.
I feel like this thread has filled up with noise about an "ultimate goal". I tried to create two simple examples and apparently I needed to go simpler to get an answer to the question in the title.
Either someone can show me the following code working, using
One enumeration instead of two.
No protocol.
…or I'll just take it as a limitation of the language which warrants code generation.
@Reference var referenceArrayNest = ReferenceArrayNest.element("🐈⬛")
ValueArrayNest(referenceArrayNest)
previous code, consolidated
public enum ReferenceArrayNest<Element> {
case element(Element)
case array([Reference<Self>] = [])
}
public enum ValueArrayNest<Element>: ArrayNestProtocol {
case element(Element)
case array([Self] = [])
}
/// Adds reference semantics to a value type.
@propertyWrapper public final class Reference<Value> {
public var wrappedValue: Value
public var projectedValue: Reference { self }
public init(wrappedValue: Value) {
self.wrappedValue = wrappedValue
}
}
public protocol ArrayNestProtocol<Element, ArrayElement> {
associatedtype Element
associatedtype ArrayElement
static func element(_: Element) -> Self
static func array(_: [ArrayElement]) -> Self
}
public extension ArrayNestProtocol where ArrayElement == Self {
init(_ referenceArrayNest: ReferenceArrayNest<Element>) {
switch referenceArrayNest {
case .element(let element):
self = .element(element)
case .array(let array):
self = .array(
array.map { .init($0.wrappedValue) }
)
}
}
}
I don’t understand “the question in the title.” What is a “generic placeholder?” What type-system relationship does “with Self” mean? What is the problem that requires a “workaround”?
As @xwu said, your simplest example fails because Outer<Inner> where Outer == Self is an infinite type. In your second example, do you want to combine ReferenceArrayNest, ValueArrayNest, and Reference all into one class? Or do you just want to combine ValueArrayNest and ReferenceArrayNest?
Would this result in a type that can wrap a Sequence of anything, including other Sequences?
I too truly do not understand what your goal is with the ArrayNest types. This works in Swift 5.7 (though printing it requires a 5.7 stdlib at run time):
public enum ArrayNest<Element> {
case element(Element)
case array(any Sequence<Self> = [])
}
let x: ArrayNest<Int> = .array([.element(1), .array([.element(2)])])
print(x)
This does not quite work…
// error: generic enum 'ArrayNest' has self-referential generic requirements
public enum ArrayNest<Element, Collection: Sequence>
where Collection.Element == Self {
case element(Element)
case array(Collection)
}
let x: ArrayNest<Int, _> = .array([])
print(x)
…and to my knowledge making it work requires higher-kinded types, so you can pass Array and not Array<Something> as the Collection parameter. (Or having a language that supports self-referential requirements, which I think is what your "simplest example" is getting at, but higher-kinded types would be sufficient even without self-referential requirements.)
But there's no reason to move on to it before addressing the first. I should have made two posts.
You don't need to understand the motivation to provide an answer, but the motivation is that it's too hard to mutate the nested arrays (e.g. in last week's advent of code) if they're value types. It's easiest to build them up with references and then remove the references afterwards.
This is a general usability with Swift, but without associated types and nesting involved, it's manageable addressing everything with indices instead.