I’ve been spinning my wheels on this one for a couple of hours and can’t come 
up with a way to do it which doesn’t require checking for at least one 
potential data inconsistency at runtime with precondition() or assert(), so I’m 
wondering if anyone else has a solution.

I have a data type which is conceptually a Set (not an OptionSet, it’s not a 
bitfield and has no concrete representation, simply a Set). This Set may 
contain members chosen from a limited set of choices, which in Swift I 
represent as an enum:

enum Kind {
        case FirstKind
        case SecondKind
        case ThirdKind
}

typealias Kinds = Set<Kind>

The data to which this applies is a structure-

struct DataItem {
        let kinds: Kinds
        // other fields
}

This structure demands that the Kinds set must always contain at *least* one 
element, because conceptually "no kind" is not a sensible state for a data 
item. However, I can’t use just the enum because the data can be of more than 
one kind at a time. It can just never be of no kinds - in that case, there is 
no data at all, and I don’t need a state *within* the data to represent that, I 
would simply have no DataItem in the collection which holds the list of data 
items.

In a relational dataset, I would say that the "no kind" state was denormalized, 
because it can be represented by there being no row in a table. The other 
obvious alternative, to duplicate the DataItem for each Kind, is also 
denormalized (multiple rows whose data is not solely defined by the candidate 
keys). The less obvious alternative of having a map of [Kind : [DataItem]] (in 
a database this would be akin to having a kindID column in the DataItem table 
with a separate Kinds lookup table), while fully normalized, is not only 
inefficient and difficult to manipulate but also disassociates a critical piece 
of information about the item from the item itself. My in-memory data model is 
not a relational database.

Half-digression into relational theory aside, I can’t figure a way to make the 
compiler enforce this. An enum is "exactly one", a Set is "zero or more", a 
structure or class is "this group", an Optional is "zero or one". Obviously, I 
can do "precondition(kinds.count > 0)" to check this at runtime, but that 
admits that the data can exist in an inconsistent state. Is there some way, 
even a hacky one, to express in the data model itself (such that the compiler 
will enforce it) that there must be at least one "kind", as the enum already 
does for "only one at a time"?

There’s probably some bit of type theory which explains why this is either 
difficult or impossible in practice, but I’m hoping maybe it’s just a corner of 
knowledge I’ve yet to previously delve.

-- Gwynne Raskind



_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to