Conforming to `Collection` with `String` as `Key`

Conforming to Collection with String as Key

Dear Swift Community,

I would like some advice on making a Dictionary-like structure conform to Collection. The difference between this structure and Dictionary is that the structure's key is always a String, while a Dictionary's Key only has to conform to Hashable.

Let's say we have this structure:

/// A table in a TOML document.
public class TOMLTable: Sequence, IteratorProtocol {
	public var keys: [String] { ... }
	public var values: [TOMLValue] { ... }
	public var count: Int { ... }
	public var isEmpty: Bool { ... }

	public init(...) { ... }

	public func contains(key: String) -> Bool { ... }

	public func contains(element: TOMLValueConvertible) -> Bool { ... }

	func insert(_ value: TOMLValueConvertible, at key: String { ... }

	func remove(at key: String) -> TOMLValueConvertible? { ... }

	// For conforming to Sequence and IteratorProtocol
	func next() -> (String, TOMLValueConvertible)? { ... }

	public subscript(key: String) -> TOMLValueConvertible? {
		get { ... }
		set(value) { ... }
	}
	...
}

With some modifications, the insert(_:at:), contains(element:), and remove(at:) functions, and the subscript can be used to conform to Collection. The problem is that associatedtype Index requirement in Collection seems to only work with an Int-based index, and most the functions and properties that use Index seem to be make for an Index of Int. For example, the indices property is a Range of Index, but you cannot make a Range from a String. Is there another way to conform to Collection? Or is there another protocol TOMLTable should conform to?

Jeff

Check the “ Conforming to the Collection Protocol” section in Collection reference. You only need to implement:

You can optionally implement other required functions (those marked with “default implementation provided”) to speed up your data structure should you know you can do better than the naive approach. Still, the provided implementation is usually good enough.

Index can be any type. It’s pretty rare to have Int index in Swift. Only Array (and the slices thereof) comes to mind.

You need first to decide what information is required to access an element at a particular location. This information constitutes the index. It’s usually a custom type you implement separately.

The index of String is an opaque String.Index, and the index of Range<X> is X. Again, none of which are Int.

PS

Are you sure you need to conform your type to Collection? It only allows you to support build-in for in syntax (inherited from Sequence protocol), and a few other helpful instance functions.

That said, if you’re planning to read a TOML file into memory, it may be be better to specify structurestr upfront, and deserialize it upon loading. See “Encoding and Decoding Custom Types”. Then again, you’d need a TOML decoder, which I’m not sure there’s a library for that.

@Lantua Thank you for your advice. After reading your comments, I’ve decided that TOMLTable does not need to conform to the Collection protocols, only Sequence and IteratorProtocol.

Commonly, Sequence and its Iterator are different types so that they support multiple iterations. I suggest that you do the same since that's how people who use for-in would normally expect.