How to extend String.Iterator in Swift












4














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



























    4














    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

























      4












      4








      4







      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,24721634




      2,24721634
























          1 Answer
          1






          active

          oldest

          votes


















          2














          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',
          autoActivateHeartbeat: false,
          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









          2














          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
















          2














          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














          2












          2








          2






          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

          390k55848957




          390k55848957












          • 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

          Full-time equivalent

          さくらももこ

          13 indicted, 8 arrested in Calif. drug cartel investigation