Update: I updated the post to make use of
S: SequenceType
instead ofT: GeneratorType
; it's a cleaner API.
: .info
Yesterday, I wrote about how we needed to build the following class:
struct UnicodeScalarParsingBuffer {
var generator: String.UnicodeScalarView.Generator
var current: UnicodeScalar? = nil
init(_ generator: String.UnicodeScalarView.Generator) {
self.generator = generator
}
mutating func next() -> UnicodeScalar? {
self.currentUnicodeScalar = generator.next()
return self.currentUnicodeScalar
}
}
When we look at the code above, we can observe a few things:
- The code is tightly coupled to
String.UnicodeScalarView.Generator
- The code is tightly coupled to
UnicodeScalar
- The code loosely conforms to
GeneratorType
We can make this code better and more suitable for other instances of GeneratorType
; or to put it another way, generic.
Let's start from bullet #3; we should be conforming to the GeneratorType
protocol because this really is simply another type of generator.
The definition starts to take shape like this:
struct BufferedGenerator : GeneratorType {
var generator: GeneratorType
mutating func next() -> UnicodeScalar?
}
Bullets #1 and #2 are aspects of the same coin as Generator
and Generator.Element
are really defined from the same construct.
The interface now looks more like this:
struct BufferedGenerator<S: SequenceType> : GeneratorType {
typealias Sequence = S
var generator: Sequence.Generator
var current: Sequence.Generator.Element? = nil
init(_ sequence: Sequence) {
self.generator = sequence.generate()
}
mutating func next() -> Sequence.Generator.Element? {
self.current = generator.next()
return self.current
}
}
This implementation now let's us use any type of SequenceType
as a BufferedGenerator
.
We use
SequenceType
as the generic constraint instead ofGeneratorType
because it creates a better ownership model for the underlying generator. The call tonext()
should only be done from a single generator; this code puts that burden onBufferedGenerator<S>
instead of the caller.
: .info
Generics can be a great way to reduce type information that simply doesn't need to be there. In this case, there was no reason that the original UnicodeScalarParsingBuffer
needed to be tied to a specific type. Generics can also help greatly in code reuse, which is almost always a good thing.
The full source for the json-swift library can be found over on GitHub.