8 Replies
      Latest reply: Mar 5, 2017 2:45 PM by eskimo RSS
      czak Level 1 Level 1 (0 points)

        I'm implementing a simple linked-list stack.

        I can get the following Int-only implementaion to work just fine:

         

        class LinkedListIntStack {
            class Node {
                let item: Int
                var next: Node?
                init(item: Int) {
                    self.item = item
                }
            }
        
            /* ... implementation omitted for brevity ... */
        }
        

         

        Unfortunately, I can't get the same nested construct to work with a generic type:

         

        class LinkedListStack<T> {
            class Node<T> {
                let item: T
                var next: Node?
                init(item: T) {
                    self.item = item
                }
            }
        
        
           /* ... omitted for brevity ... */
        }
        

         

        The above fails to compile with the error message:

         

        error: generic type 'Node' nested in type 'LinkedListStack' is not allowed

         

        I can work around this by moving Node<T> outside of LinkedListStack<T>.

        However, I find the nested type solution more elegant.

         

        My questions:

        1. Is it wrong for me to expect this to work? Is there a mistake I'm making and not realizing?
        2. Is this a design decision or just a current limitation of Swift? If it's the former, what is the motivation behind it?
        3. Are there alternative solutions you can recommend?

         

        Thanks!

        • Re: Nested generic types not allowed?
          Jens Level 3 Level 3 (230 points)

          Just as a complementary note, generic types aren't allowed to have any nested types (no matter if the nested type is generic or not):

          struct Foo<T> {
              struct Bar { // Error: Type 'Bar' nested in generic type 'Foo' is not allowed
              }
          }
          
            • Re: Nested generic types not allowed?
              ObjectHub Level 2 Level 2 (30 points)

              Generic types are allowed to have associated types. So, it is actually possible to define something like this:

               

              class LinkedListStack<T> {
                private typealias Node = (item: T, next: AnyObject)
                ...
              }
              

               

              Unfortunately, Node is a recursive data structure which cannot be encoded as a tuple even if the recursion is indirect. So, it won't be possible to replace AnyObject with Node?.

            • Re: Nested generic types not allowed?
              lostatseajoshua Level 1 Level 1 (0 points)

              Late to the party. Unfortunately this is a limitation in Swift 2.2 and below as it is available in Swift 3.

              The limitation is explained here - https://devforums.apple.com/message/1046539#1046539

              "It's an implementation limitation. We'll remove the restriction once our compiler and runtime are able to correctly handle types nested in generic contexts." - jckarter (In response to racoiaws on Sep 20, 2014 9:51 AM)

               

              As a workaround you can just create the node outside of the class.

               

              class Node<T> {
                   let item: T
              }
              
              class LinkedListStack<T> {
                   var head: Node<T>?
              }
              
              

               

              This also work with protocols on the generic types as long as they both implement the same protocols.

               

              class Node<T: Equatable> {
                   let item: T
              }
              class LinkedListStack<T: Equatable> {
                   var head: Node<T>?
              }
              
              
                • Re: Nested generic types not allowed?
                  grillbrick Level 1 Level 1 (0 points)

                  So this is available in swift 3? I get the same error is swift 3 - is there some special syntax for it?

                    • Re: Nested generic types not allowed?
                      yannmm Level 1 Level 1 (0 points)

                      me too, with Xcode 8.1.

                      gosh, I'm so eager to implement all the fantastic swift3.0 features, while this issue really upset me.

                      My code will look bitterly ungly if i move the nested type outside.

                        • Re: Nested generic types not allowed?
                          eskimo Apple Staff Apple Staff (6,470 points)

                          The Generics Manifesto still lists this as not supported.

                          My code will look bitterly ungly if i move the nested type outside.

                          Which specific thing do you find ungly [sic :-]?  Personally I just move my type up to the top level, set up a type alias, and move on.

                          struct LinkedListStack<T> { 
                              private typealias Node = ListNode<T>
                              private var items: [Node] = []
                              …
                          }
                          
                          fileprivate struct ListNode<T> {
                              …
                          }
                          

                          Share and Enjoy

                          Quinn “The Eskimo!”
                          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                          let myEmail = "eskimo" + "1" + "@apple.com"

                            • Re: Nested generic types not allowed?
                              couchdeveloper Level 1 Level 1 (0 points)

                              I stumbled above the same limitation. The "ugliness" here is, that you need to _prefix_ the name of the nested class in order to avoid name clashes.

                               

                              IMHO, the support of nested types (with or without generics) leaves much to be desired.

                                • Re: Nested generic types not allowed?
                                  eskimo Apple Staff Apple Staff (6,470 points)

                                  The "ugliness" here is, that you need to prefix the name of the nested class in order to avoid name clashes.

                                  Sure, but if you always refer to it by its typealias that’s a small bit of boilerplate that you can write and then try to forget about.

                                  I’m not arguing that the current behaviour is ideal, just that I don’t lose a lot sleep about it, especially compared to some of the other items listed in the Generics Manifesto.

                                  Share and Enjoy

                                  Quinn “The Eskimo!”
                                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                  let myEmail = "eskimo" + "1" + "@apple.com"