The above seems to work. Changing the definition of Vertex to use T1 instead of T stops the confusion between the types. You don't need to use T as it picks that up from the definition of vertices in the Graphing struct.
I assumed (incorrectly, but I don't think unreasonably) that a nested generic declaration <XXX:YYY>{} introduced a new type scope, in a similar manner to:
if let x : Int? = 1
{
let x : Float = 2.0
}
@JohnBlackburne - your approach compiles succesfully, although I'm uncertain of the rules making it work.
@Peter-Schorn - I tried your suggestion of renaming types uniquely, but encountered the exact same compilation errors as before:
import Foundation
protocol Something {}
struct Graphing<T:Something>
{
let vertices : [ Graphing.Vertex<T> ]
struct Vertex<U:Something>
{
let placeholder = true
}
struct Region<V:Something>
{
let placeholder = true
static func fail1( _ graph : Graphing<V> ) -> [ Graphing.Region<V> ]
{
let x : [ Graphing.Vertex<V> ] = graph.vertices
}
static func fail2<W:Something>( _ graph : Graphing<W> ) -> [ Graphing.Region<W> ]
{
let x : [ Graphing.Vertex<W> ] = graph.vertices
}
}
}
I believe there is more to understand. Do you know of any documentation explaining generic type scoping and propagation within hierarchies? This topic is not covered within the standard docs: Generics — The Swift Programming Language (Swift 5.7)
struct Vertex<T1:Something>
{
let placeholder = true
}
tells it use the type T1, providing it conforms to Something. Then this line
let vertices : [ Graphing.Vertex<T> ]
tells it the type is an array of Vertex, and tells it to use T which is the same T as the Graphing struct, as the type for the Vertex struct. I.e. the T1 gets replaced by T by that line, so you don't need to use T yourself in the Vertex definition.
It's a bit hard to offer you broader advice how to structure it as it's hard to tell what you're trying to do: what sort of data is T, what is Something, and what will replace the placeholders? The closest thing to that in my code I don't use a hierarchy, just separate structs. But I also don't use generics for vertex or related data, as they're all very concrete.
With different names, the diagnostics can now tell you exactly what is going on. In fail1, you have an argument of type Graphing<V> named graph. You access a member vertices, which has type [Graphing<V>.Vertex<V>]. You then assign it to a variable x of type [Graphing<T>.Vertex<V>], but T is not V.
Perhaps you are unfamiliar with the shorthand that Swift allows you to use within the scope of a type. Inside Graphing<T>, when you write Graphing without generic parameters, it is a shorthand for Graphing<T>.
Or perhaps you are unaware that nested types capture and are parameterized by the generic parameters of the parent type. That is, there isn't one type Graphing.Region<V>, but rather every type Graphing<A>.Region<V>, Graphing<B>.Region<V>, etc. is distinct.
Another way which might be clearer is strip out all your references to TinsideGraphing. I mean like this.
protocol Something {}
struct Graphing<T:Something>
{
let vertices : [ Graphing.Vertex ]
struct Vertex
{
let placeholder = true
let elements: [T] = []
}
struct Region
{
let placeholder = true
static func fail1( _ graph : Graphing ) -> [ Graphing.Region]
{
let x : [ Graphing.Vertex ] = graph.vertices
return []
}
}
}
You then will use T, inside Vertex and perhaps other places, to fill in its contents, as I've indicated. Vertex will use the T from Graphing to implement the contents, so you don't need to include `'T' in its definition or where it's later used.
Outside of the Graphing struct though you need to refer to Vertex through it belonging to Graphing and from that it gets the T to use. E.g.
struct Foo: Something {}
let v: Graphing<Foo>.Vertex = .init()
let g = Graphing<Foo>(vertices: [v])
let r = Graphing<Foo>.Region.fail1(g)