I think the major difference is that by using EventID as a constrained type, 
you are then attempting to constrain index values - for which there are no 
constraints other than slice length. 

Similarly, using an enum as a slice index would NEVER be safe. Enums are 
sparse. Slices are contiguous. Any safety here would only be by convention - 
and subject to great runtime risk (invalid index). 

I really believe using EventList and the Iterable pattern will give you the 
greatest type safety and “idiomatic Go” simplicity. 

As you state, you are already doing this (but you omitted it). The type casts 
are zero cost. Can you explain why this pattern doesn’t work for you (other 
than the common arguments for genetics)?

> On Feb 2, 2020, at 9:08 PM, Steve Roth <st...@rothskeller.net> wrote:
> 
> 
> Hi, Robert,
> 
> Thanks for the quick replies.  Let me address each of your points:
> 
> "Slice indexes are ints" is clearly true in the current language definition.  
> From a pure language standpoint, one might assert that any index type other 
> than plain int requires a map.  However, if one has a data structure indexed 
> by (small positive) typed integers, it is unrealistic to suggest using a map 
> for storage of it when a slice is dramatically more efficient in both space 
> and time.  I wrote up this potential proposal because my colleagues and I 
> have tripped over this issue multiple times in real-world applications.
> 
> What I'm suggesting may be covered by generics if and when they ever happen, 
> but considering that generics are a breaking change and are years away at 
> best, they are not relevant to the evaluation of a small, backward-compatible 
> change.
> 
> As for the simple structs like EventList: they don't solve the problem of 
> excess type casts; they merely move it to a different part of the code.  In 
> fact we do use encapsulating structures, but I omitted them from my writeup 
> for clarity.
> 
> As a separate, straw-man example, consider the common case of defining an 
> enumerated integer type:
> type MyEnum int
> const (
> EnumVal1 MyEnum = iota
> EnumVal2
> EnumVal3
> )
> Once again, if one needs a data structure indexed by MyEnum, it makes much 
> more sense to define it as a slice rather than a map.  The use of iota quite 
> literally guarantees that the values are suitable for slice indexing.  I'm 
> simply trying to alleviate the need for excess, error-prone casting when 
> doing so.
> 
> Regards,
> Steve
> 
> 
>> On Sun, Feb 2, 2020 at 6:37 PM Robert Engels <reng...@ix.netcom.com> wrote:
>> One last point, if you are interested in type safety, why not create simple 
>> structs like EventList to encapsulate the indexing, etc. Trivial and can be 
>> done today. 
>> 
>>>> On Feb 2, 2020, at 8:28 PM, Robert Engels <reng...@ix.netcom.com> wrote:
>>>> 
>>> 
>>> Also, what you are asking for I believe is covered by generics. 
>>> 
>>>>> On Feb 2, 2020, at 8:17 PM, Steve Roth <st...@rothskeller.net> wrote:
>>>>> 
>>>> 
>>>> Oh, please, Robert.  No need to be condescending.  I know perfectly well 
>>>> how to use the value when that's what I want.  Often it is not.  The 
>>>> examples that I cited are such a case: we are adding the IDs of the events 
>>>> — the indices of the slice — to the person.Events field.  If you don't 
>>>> like my example, take a look through the standard library code: you'll 
>>>> find a great many instances of range loops using only the index.
>>>> 
>>>> Regards,
>>>> Steve
>>>> 
>>>> 
>>>>> On Sun, Feb 2, 2020 at 5:56 PM Robert Engels <reng...@ix.netcom.com> 
>>>>> wrote:
>>>>> You are using range incorrectly - you are using the index not the value. 
>>>>> 
>>>>> See https://tour.golang.org/moretypes/16
>>>>> 
>>>>>>> On Feb 2, 2020, at 7:39 PM, Steve Roth <st...@rothskeller.net> wrote:
>>>>>>> 
>>>>>> 
>>>>>> Greetings,
>>>>>> 
>>>>>> I'm considering submitting a proposal for a language change, and would 
>>>>>> like some informal feedback on the idea before engaging the formal 
>>>>>> process.  The idea being proposed here is intended to improve type 
>>>>>> safety by removing the need for some error-prone type casting.  It is a 
>>>>>> backward compatible change.
>>>>>> 
>>>>>> Consider a body of code that works with people and events.  Both are 
>>>>>> identified with integer IDs; in order to prevent them being used in the 
>>>>>> wrong contexts, they are given specific integer types:
>>>>>> type EventID int
>>>>>> type PersonID int
>>>>>> Assume also that people have lists of events they attend:
>>>>>> type Person struct {
>>>>>> Events []EventID
>>>>>> }
>>>>>> The code maintains slices of each type:
>>>>>> var events []*Event
>>>>>> var people []*Person
>>>>>> When indexing into those slices, one can use the appropriate ID type:
>>>>>> var eventID EventID = 3
>>>>>> println(events[eventID])
>>>>>> 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
>>>>>> 
>>>>>> -- 
>>>>>> You received this message because you are subscribed to the Google 
>>>>>> Groups "golang-nuts" group.
>>>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>>>> an email to golang-nuts+unsubscr...@googlegroups.com.
>>>>>> To view this discussion on the web visit 
>>>>>> https://groups.google.com/d/msgid/golang-nuts/CAAnpqKHS%3D2z0ZbNVSrULXLLGz%3DhAqpmrsLieciFu8L6%3DAn%3DLHA%40mail.gmail.com.
>>>> 
>>>> -- 
>>>> You received this message because you are subscribed to the Google Groups 
>>>> "golang-nuts" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send an 
>>>> email to golang-nuts+unsubscr...@googlegroups.com.
>>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/golang-nuts/CAAnpqKEEOPicjwD%3Dmy08ORMzOwFiMFy4F%3DG3L9bdLFfbbsnHWA%40mail.gmail.com.
>>> -- 
>>> You received this message because you are subscribed to the Google Groups 
>>> "golang-nuts" group.
>>> To unsubscribe from this group and stop receiving emails from it, send an 
>>> email to golang-nuts+unsubscr...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/golang-nuts/75113376-DE42-4B0E-BF0E-456AC8D44418%40ix.netcom.com.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/515B6A8D-5F71-4E8F-9CD9-378E6F164C4E%40ix.netcom.com.

Reply via email to