How to extend String.Iterator in Swift









up vote
4
down vote

favorite












I have a String like LINNIIBDDDN, basically a series of tokens. I'd like to use multiple iterators, one for each token type. I'd like to have each iterator ignore the tokens that don't belong to it. That is, I want to call something like next_ish(), to advance the iterator to the next element of its particular token. So if the Niterator is at index 3, and I call next_ish(), I want it to go to index 10, the next N, not the I at index 4. I have some code that already works, but it's a lot of code, it makes the String into an array, and I have subclassed iterators, basically hand-written, with no help from Swift, although I'm sure the Swift iterators are more stable and thoroughly tested. I'd rather use their code than mine, where possible.



It seems like it should be easy just to extend String.Iterator and add next_ish(), but I'm at a loss. My first naive attempt was to extend String.Iterator. I get the error Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause. I went looking to figure out what kind of where clause to use, and I haven't found anything.



There are a lot of answers here on SO, about extending arrays and generics, pulling all the elements of a certain type into an array of their own, even some answers about specialized for...in loops, but I can't find anything about extending iterators. I've read through Collections.swift and haven't found anything helpful. Is it possible to extend String.Iterator? That would make my life a lot easier. If not, is there some sort of built-in Swift mechanism for doing this sort of thing?










share|improve this question

























    up vote
    4
    down vote

    favorite












    I have a String like LINNIIBDDDN, basically a series of tokens. I'd like to use multiple iterators, one for each token type. I'd like to have each iterator ignore the tokens that don't belong to it. That is, I want to call something like next_ish(), to advance the iterator to the next element of its particular token. So if the Niterator is at index 3, and I call next_ish(), I want it to go to index 10, the next N, not the I at index 4. I have some code that already works, but it's a lot of code, it makes the String into an array, and I have subclassed iterators, basically hand-written, with no help from Swift, although I'm sure the Swift iterators are more stable and thoroughly tested. I'd rather use their code than mine, where possible.



    It seems like it should be easy just to extend String.Iterator and add next_ish(), but I'm at a loss. My first naive attempt was to extend String.Iterator. I get the error Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause. I went looking to figure out what kind of where clause to use, and I haven't found anything.



    There are a lot of answers here on SO, about extending arrays and generics, pulling all the elements of a certain type into an array of their own, even some answers about specialized for...in loops, but I can't find anything about extending iterators. I've read through Collections.swift and haven't found anything helpful. Is it possible to extend String.Iterator? That would make my life a lot easier. If not, is there some sort of built-in Swift mechanism for doing this sort of thing?










    share|improve this question























      up vote
      4
      down vote

      favorite









      up vote
      4
      down vote

      favorite











      I have a String like LINNIIBDDDN, basically a series of tokens. I'd like to use multiple iterators, one for each token type. I'd like to have each iterator ignore the tokens that don't belong to it. That is, I want to call something like next_ish(), to advance the iterator to the next element of its particular token. So if the Niterator is at index 3, and I call next_ish(), I want it to go to index 10, the next N, not the I at index 4. I have some code that already works, but it's a lot of code, it makes the String into an array, and I have subclassed iterators, basically hand-written, with no help from Swift, although I'm sure the Swift iterators are more stable and thoroughly tested. I'd rather use their code than mine, where possible.



      It seems like it should be easy just to extend String.Iterator and add next_ish(), but I'm at a loss. My first naive attempt was to extend String.Iterator. I get the error Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause. I went looking to figure out what kind of where clause to use, and I haven't found anything.



      There are a lot of answers here on SO, about extending arrays and generics, pulling all the elements of a certain type into an array of their own, even some answers about specialized for...in loops, but I can't find anything about extending iterators. I've read through Collections.swift and haven't found anything helpful. Is it possible to extend String.Iterator? That would make my life a lot easier. If not, is there some sort of built-in Swift mechanism for doing this sort of thing?










      share|improve this question













      I have a String like LINNIIBDDDN, basically a series of tokens. I'd like to use multiple iterators, one for each token type. I'd like to have each iterator ignore the tokens that don't belong to it. That is, I want to call something like next_ish(), to advance the iterator to the next element of its particular token. So if the Niterator is at index 3, and I call next_ish(), I want it to go to index 10, the next N, not the I at index 4. I have some code that already works, but it's a lot of code, it makes the String into an array, and I have subclassed iterators, basically hand-written, with no help from Swift, although I'm sure the Swift iterators are more stable and thoroughly tested. I'd rather use their code than mine, where possible.



      It seems like it should be easy just to extend String.Iterator and add next_ish(), but I'm at a loss. My first naive attempt was to extend String.Iterator. I get the error Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause. I went looking to figure out what kind of where clause to use, and I haven't found anything.



      There are a lot of answers here on SO, about extending arrays and generics, pulling all the elements of a certain type into an array of their own, even some answers about specialized for...in loops, but I can't find anything about extending iterators. I've read through Collections.swift and haven't found anything helpful. Is it possible to extend String.Iterator? That would make my life a lot easier. If not, is there some sort of built-in Swift mechanism for doing this sort of thing?







      swift iterator extension-methods






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 11 at 21:58









      GreatBigBore

      2,23721634




      2,23721634






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          String.Iterator is (implicitly) defined as



          typealias Iterator = IndexingIterator<String>


          and the error message




          Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause




          means that we must define extension methods as



          extension IndexingIterator where Elements == String 


          Alternatively (with increasing generality):



          extension IndexingIterator where Elements: StringProtocol 
          extension IndexingIterator where Elements.Element == Character


          I haven't found a way to access the underlying collection (or position)
          from within an extension method, the corresponding members are defined as
          “internal”:



          public struct IndexingIterator<Elements : Collection> 
          internal let _elements: Elements
          internal var _position: Elements.Index
          // ...



          What you can do is to pass the wanted element to your “next-ish” method,
          either as the element itself, or as a predicate:



          extension IndexingIterator where Elements.Element == Character 

          mutating func next(_ wanted: Character) -> Character?
          while let c = next()
          if c == wanted return c

          return nil


          mutating func next(where predicate: ((Character) -> Bool)) -> Character?
          while let c = next()
          if predicate(c) return c

          return nil




          Example usage:



          var it1 = "ABCDABCE".makeIterator()
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("D")
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("E")
          print(it1.next("C") as Any) // nil

          var it2 = "LINnIIBDDDN".makeIterator()
          while let c = it2.next(where: "Nn".contains($0) )
          print(c, terminator: ", ")

          print()
          // N, n, N,


          But actually I would consider String.Iterator being an IndexingIterator an implementation detail, and extend the IteratorProtocol instead:



          extension IteratorProtocol where Element: Equatable 
          mutating func next(_ wanted: Element) -> Element?
          while let e = next()
          if e == wanted return e

          return nil



          extension IteratorProtocol
          mutating func next(where predicate: ((Element) -> Bool)) -> Element?
          while let e = next()
          if predicate(e) return e

          return nil




          That makes it usable for arbitrary sequences. Example:



          var it3 = [1, 1, 2, 3, 5, 8, 13, 21, 34].makeIterator()
          while let e = it3.next(where: $0 % 2 == 0 )
          print(e, terminator: ", ")

          print()
          // 2, 8, 34,





          share|improve this answer






















          • Thanks again! Your username is all over my code.
            – GreatBigBore
            Nov 12 at 14:52










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53253658%2fhow-to-extend-string-iterator-in-swift%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          2
          down vote



          accepted










          String.Iterator is (implicitly) defined as



          typealias Iterator = IndexingIterator<String>


          and the error message




          Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause




          means that we must define extension methods as



          extension IndexingIterator where Elements == String 


          Alternatively (with increasing generality):



          extension IndexingIterator where Elements: StringProtocol 
          extension IndexingIterator where Elements.Element == Character


          I haven't found a way to access the underlying collection (or position)
          from within an extension method, the corresponding members are defined as
          “internal”:



          public struct IndexingIterator<Elements : Collection> 
          internal let _elements: Elements
          internal var _position: Elements.Index
          // ...



          What you can do is to pass the wanted element to your “next-ish” method,
          either as the element itself, or as a predicate:



          extension IndexingIterator where Elements.Element == Character 

          mutating func next(_ wanted: Character) -> Character?
          while let c = next()
          if c == wanted return c

          return nil


          mutating func next(where predicate: ((Character) -> Bool)) -> Character?
          while let c = next()
          if predicate(c) return c

          return nil




          Example usage:



          var it1 = "ABCDABCE".makeIterator()
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("D")
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("E")
          print(it1.next("C") as Any) // nil

          var it2 = "LINnIIBDDDN".makeIterator()
          while let c = it2.next(where: "Nn".contains($0) )
          print(c, terminator: ", ")

          print()
          // N, n, N,


          But actually I would consider String.Iterator being an IndexingIterator an implementation detail, and extend the IteratorProtocol instead:



          extension IteratorProtocol where Element: Equatable 
          mutating func next(_ wanted: Element) -> Element?
          while let e = next()
          if e == wanted return e

          return nil



          extension IteratorProtocol
          mutating func next(where predicate: ((Element) -> Bool)) -> Element?
          while let e = next()
          if predicate(e) return e

          return nil




          That makes it usable for arbitrary sequences. Example:



          var it3 = [1, 1, 2, 3, 5, 8, 13, 21, 34].makeIterator()
          while let e = it3.next(where: $0 % 2 == 0 )
          print(e, terminator: ", ")

          print()
          // 2, 8, 34,





          share|improve this answer






















          • Thanks again! Your username is all over my code.
            – GreatBigBore
            Nov 12 at 14:52














          up vote
          2
          down vote



          accepted










          String.Iterator is (implicitly) defined as



          typealias Iterator = IndexingIterator<String>


          and the error message




          Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause




          means that we must define extension methods as



          extension IndexingIterator where Elements == String 


          Alternatively (with increasing generality):



          extension IndexingIterator where Elements: StringProtocol 
          extension IndexingIterator where Elements.Element == Character


          I haven't found a way to access the underlying collection (or position)
          from within an extension method, the corresponding members are defined as
          “internal”:



          public struct IndexingIterator<Elements : Collection> 
          internal let _elements: Elements
          internal var _position: Elements.Index
          // ...



          What you can do is to pass the wanted element to your “next-ish” method,
          either as the element itself, or as a predicate:



          extension IndexingIterator where Elements.Element == Character 

          mutating func next(_ wanted: Character) -> Character?
          while let c = next()
          if c == wanted return c

          return nil


          mutating func next(where predicate: ((Character) -> Bool)) -> Character?
          while let c = next()
          if predicate(c) return c

          return nil




          Example usage:



          var it1 = "ABCDABCE".makeIterator()
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("D")
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("E")
          print(it1.next("C") as Any) // nil

          var it2 = "LINnIIBDDDN".makeIterator()
          while let c = it2.next(where: "Nn".contains($0) )
          print(c, terminator: ", ")

          print()
          // N, n, N,


          But actually I would consider String.Iterator being an IndexingIterator an implementation detail, and extend the IteratorProtocol instead:



          extension IteratorProtocol where Element: Equatable 
          mutating func next(_ wanted: Element) -> Element?
          while let e = next()
          if e == wanted return e

          return nil



          extension IteratorProtocol
          mutating func next(where predicate: ((Element) -> Bool)) -> Element?
          while let e = next()
          if predicate(e) return e

          return nil




          That makes it usable for arbitrary sequences. Example:



          var it3 = [1, 1, 2, 3, 5, 8, 13, 21, 34].makeIterator()
          while let e = it3.next(where: $0 % 2 == 0 )
          print(e, terminator: ", ")

          print()
          // 2, 8, 34,





          share|improve this answer






















          • Thanks again! Your username is all over my code.
            – GreatBigBore
            Nov 12 at 14:52












          up vote
          2
          down vote



          accepted







          up vote
          2
          down vote



          accepted






          String.Iterator is (implicitly) defined as



          typealias Iterator = IndexingIterator<String>


          and the error message




          Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause




          means that we must define extension methods as



          extension IndexingIterator where Elements == String 


          Alternatively (with increasing generality):



          extension IndexingIterator where Elements: StringProtocol 
          extension IndexingIterator where Elements.Element == Character


          I haven't found a way to access the underlying collection (or position)
          from within an extension method, the corresponding members are defined as
          “internal”:



          public struct IndexingIterator<Elements : Collection> 
          internal let _elements: Elements
          internal var _position: Elements.Index
          // ...



          What you can do is to pass the wanted element to your “next-ish” method,
          either as the element itself, or as a predicate:



          extension IndexingIterator where Elements.Element == Character 

          mutating func next(_ wanted: Character) -> Character?
          while let c = next()
          if c == wanted return c

          return nil


          mutating func next(where predicate: ((Character) -> Bool)) -> Character?
          while let c = next()
          if predicate(c) return c

          return nil




          Example usage:



          var it1 = "ABCDABCE".makeIterator()
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("D")
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("E")
          print(it1.next("C") as Any) // nil

          var it2 = "LINnIIBDDDN".makeIterator()
          while let c = it2.next(where: "Nn".contains($0) )
          print(c, terminator: ", ")

          print()
          // N, n, N,


          But actually I would consider String.Iterator being an IndexingIterator an implementation detail, and extend the IteratorProtocol instead:



          extension IteratorProtocol where Element: Equatable 
          mutating func next(_ wanted: Element) -> Element?
          while let e = next()
          if e == wanted return e

          return nil



          extension IteratorProtocol
          mutating func next(where predicate: ((Element) -> Bool)) -> Element?
          while let e = next()
          if predicate(e) return e

          return nil




          That makes it usable for arbitrary sequences. Example:



          var it3 = [1, 1, 2, 3, 5, 8, 13, 21, 34].makeIterator()
          while let e = it3.next(where: $0 % 2 == 0 )
          print(e, terminator: ", ")

          print()
          // 2, 8, 34,





          share|improve this answer














          String.Iterator is (implicitly) defined as



          typealias Iterator = IndexingIterator<String>


          and the error message




          Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause




          means that we must define extension methods as



          extension IndexingIterator where Elements == String 


          Alternatively (with increasing generality):



          extension IndexingIterator where Elements: StringProtocol 
          extension IndexingIterator where Elements.Element == Character


          I haven't found a way to access the underlying collection (or position)
          from within an extension method, the corresponding members are defined as
          “internal”:



          public struct IndexingIterator<Elements : Collection> 
          internal let _elements: Elements
          internal var _position: Elements.Index
          // ...



          What you can do is to pass the wanted element to your “next-ish” method,
          either as the element itself, or as a predicate:



          extension IndexingIterator where Elements.Element == Character 

          mutating func next(_ wanted: Character) -> Character?
          while let c = next()
          if c == wanted return c

          return nil


          mutating func next(where predicate: ((Character) -> Bool)) -> Character?
          while let c = next()
          if predicate(c) return c

          return nil




          Example usage:



          var it1 = "ABCDABCE".makeIterator()
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("D")
          print(it1.next("C") as Any) // Optional("C")
          print(it1.next() as Any) // Optional("E")
          print(it1.next("C") as Any) // nil

          var it2 = "LINnIIBDDDN".makeIterator()
          while let c = it2.next(where: "Nn".contains($0) )
          print(c, terminator: ", ")

          print()
          // N, n, N,


          But actually I would consider String.Iterator being an IndexingIterator an implementation detail, and extend the IteratorProtocol instead:



          extension IteratorProtocol where Element: Equatable 
          mutating func next(_ wanted: Element) -> Element?
          while let e = next()
          if e == wanted return e

          return nil



          extension IteratorProtocol
          mutating func next(where predicate: ((Element) -> Bool)) -> Element?
          while let e = next()
          if predicate(e) return e

          return nil




          That makes it usable for arbitrary sequences. Example:



          var it3 = [1, 1, 2, 3, 5, 8, 13, 21, 34].makeIterator()
          while let e = it3.next(where: $0 % 2 == 0 )
          print(e, terminator: ", ")

          print()
          // 2, 8, 34,






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 12 at 9:13

























          answered Nov 12 at 6:41









          Martin R

          388k55840950




          388k55840950











          • Thanks again! Your username is all over my code.
            – GreatBigBore
            Nov 12 at 14:52
















          • Thanks again! Your username is all over my code.
            – GreatBigBore
            Nov 12 at 14:52















          Thanks again! Your username is all over my code.
          – GreatBigBore
          Nov 12 at 14:52




          Thanks again! Your username is all over my code.
          – GreatBigBore
          Nov 12 at 14:52

















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53253658%2fhow-to-extend-string-iterator-in-swift%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Top Tejano songwriter Luis Silva dead of heart attack at 64

          政党

          天津地下鉄3号線