However, iterating over these slices requires casting in the current Go specification:
for eventID := range events {
// eventID here has type int, not type EventID
person.Events = append(person.Events, eventID) // compile error, wrong type
person.Events = append(person.Events, EventID(eventID)) // cast required
}
In cases where the event ID needs to be used inside the loop, it has lost its type safety. It has to be casted back to the type it is supposed to have. And that casting is error-prone; I could easily cast it to PersonID by mistake. This seems to be a noteworthy gap in type safety.
My proposal is to allow this construction:
var eventID EventID
for eventID = range events {
// eventID here has type EventID
person.Events = append(person.Events, eventID) // accepted by compiler
}
Phrased more formally: a slice range operator can be assigned to a variable of any integer-derived type, not just "int". If this were done, error-prone casting could be avoided.
Admittedly, there is still room for error here, since it would be possible to write
var eventID PersonID
for eventID = range events {
// eventID here has the wrong type PersonID
person.Events = append(person.Events, eventID) // compile error, wrong type
}
However, this error seems far less likely that a mistaken cast. And since there's no expectation that casts should be needed, the compiler error would cause greater scrutiny leading to fixing the real problem. (In any case, I don't wish to propose the (much larger and more impactful) change of having slices with typed indices.)
I believe this proposal would significantly improve type safety in programs that work with multiple integer-derived types (such as most anything working with a relational database that prefers integer primary keys). I also believe it is backward compatible since it does not change the semantic of any existing code; it just adds a semantic to code that currently would not compile.
I solicit the community's feedback. Should this proposal be formally submitted?
Regards,
Steve