(a few days ago there was some lively discussion about relaxing type requirements for array indices which the forums seem to have lost, so this is my attempt to restart that discussion.)
it’s well known that swift is opinionated about standardizing on Int
as an index type, which is why we cannot directly subscript Array
with UInt
, Int32
, UInt8
, etc. i don’t really disagree with this idea in general; i’ve always hated how C brackets all the integer types.
but there is one downside to Int
, compared to say, Int32
, in that Int
has a huge stride: 8 bytes!
obviously, there are a lot of situations where this is not a problem at all:
-
Int
uses more memory thatInt32
, but it’s highly uncommon forInt
itself to be your memory bottleneck, so usingInt
fields for in-memory structures is usually okay. -
Int
can use a lot more storage thanInt32
when serialized to a text-based format like JSON, but it almost never does, because JSON is a variable-length encoding:{"_id":1}
uses the same amount of storage regardless of original bit width. so serializing
Int
to JSON is usually okay.
so, Int
is good for in-memory stuff, and Int
is good for JSON-encoded stuff.
but… Int
is not good for binary-serialized stuff, like BSON, because BSON is a fixed-length encoding, and always uses 8 bytes to encode Int
, which is twice as much storage as it uses to encode Int32
.
i suppose one thing we can do is to use Int
exclusively from the swift side, and narrow the Int
s to Int32
when encoding to BSON. but now we’ve lost the compile-time guarantee of not trapping/throwing on encode, and (unlike decoders), encoders are not supposed to trap, or really, fail at all.
another approach could be to implement a more intelligent encoding + decoding strategy for these Int
-typed fields, that encodes Int32
if it fits, and Int64
otherwise. but this adds a lot of complexity to the encoding + decoding logic just to serialize a simple Int
field. MongoDB is totally cool with this (it brackets Int64
and Int32
when executing queries), but it’s a nightmare to handle in the strongly-typed swift world, because you have taken something that was a scalar type in your database schema, and turned it into a sum type with two cases.
i could also use a property wrapper to make the Int32
“look like an Int
”, but this presents some challenges for algorithms that mutate the field, and if we really think about it, making the Int32
behave like an Int
is a non-goal, the only reason we are pretending it is an Int
is to be able to subscript an Array
with it.
what are we to do about Int
?