This is absolutely big improvement to make go generics simple and remove the gap between the old and new syntax :).
On Saturday, August 22, 2020 at 1:23:34 PM UTC+1 vkojo...@gmail.com wrote: > On Saturday, August 22, 2020 at 12:49:21 AM UTC+2 rog wrote: > >> On Fri, 21 Aug 2020 at 23:12, jimmy frasche <soapbo...@gmail.com> wrote: >> >>> I don't want a generic min unless it looks like this: >>> >>> func Min[T constraints.Ordered](a, b T) T { >>> switch T { >>> case float32: >>> return T(math.Min(float32(a), float32(b))) >>> case float64: >>> return T(math.Min(float64(a), float64(b))) >>> } >>> if a < b { >>> return a >>> } >>> return b >>> } >>> >> >> I'd really like to be able to write that as: >> >> func Min[T constraints.Ordered](a, b T) T { >> switch T { >> case float32: >> return math.Min(float64(a), float64(b)) >> case float64: >> return math.Min(a, b) >> >> } >> if a < b { >> return a >> } >> return b >> } >> > > Kotlin calls such a feature smart-casting, though it works for any type > rather than such generic types with type lists. I'd love if Go had such a > feature, even if it only applied to switch statements over generic types > with type lists in them. This wouldn't be conversion, since the type is the > actual type that is matched with the case. > > > >> >> But then there is the difficulty that the original T is no longer the >> same as the T inside the type switch. >> So this code would print false not true, which would be... somewhat >> unexpected: https://go2goplay.golang.org/p/d0cJBfYObAY >> >> Perhaps the type switch* should *allow declaring a new name for the >> switched type, making it clear that a new type was being declared inside >> the switch. >> >> Something like: >> >> switch T1 := T { >> } >> >> but the ":=" operator doesn't seem quite right there, and that still >> doesn't solve the original problem, because T1 is still incompatible with >> all the argument values. I guess that one could allow conversion or >> assignment compatibility between types involving T and T1, but that might >> complicate the spec too much. >> >> >> On Fri, 21 Aug 2020 at 23:12, jimmy frasche <soapbo...@gmail.com> wrote: >> >>> I don't want a generic min unless it looks like this: >>> >>> func Min[T constraints.Ordered](a, b T) T { >>> switch T { >>> case float32: >>> return T(math.Min(float32(a), float32(b))) >>> case float64: >>> return T(math.Min(float64(a), float64(b))) >>> } >>> if a < b { >>> return a >>> } >>> return b >>> } >>> >>> On Fri, Aug 21, 2020 at 3:03 PM Axel Wagner >>> <axel.wa...@googlemail.com> wrote: >>> > >>> > On Fri, Aug 21, 2020 at 11:46 PM Ian Lance Taylor <ia...@golang.org> >>> wrote: >>> >> >>> >> Yes, there are various such possibilities. >>> >> >>> >> What jimmy frasche said above is correct: nothing changes in the case >>> >> of a type switch of a type parameter. The code now knows the type >>> >> list element that the type argument matched, but it can't do anything >>> >> that it couldn't do anyhow. >>> > >>> > >>> > I think there are two reasonable things that it could be allowed to do >>> in the case, that aren't allowed outside: >>> > 1. Convert to the matched type. We have a guarantee that the matched >>> type is either identical or has the same underlying type, both of which >>> would allow a conversion in the language as-is. I feel allowing this >>> conversion would be sufficiently useful (e.g. passing things to >>> `strconv.Itoa` or functions from `math` can be very useful). >>> > 2. If the type is not a predeclared type, we could even take this a >>> step further, as the types must be identical - so we might allow treating >>> them as such. This feels natural when viewed from the "type lists are >>> essentially sum types" POV. However, it would treat predeclared types more >>> special than other declared types and so it may be too elaborate to put >>> into the spec. It would also allow what rog suggest - but only in certain >>> corner cases, which feels weird. >>> > >>> > The more I think about it, the less I understand the intention behind >>> the type-switch construct introduced. I tend to agree that 1. at least >>> should be possible to make it useful. But even then, it seems like kind of >>> a big change for relatively limited use. What was the motivation behind >>> that change? Is there discussion somewhere, of interesting use-cases this >>> enables? >>> > >>> > >>> >> >>> >> >>> >> Ian >>> >> >>> >> On Fri, Aug 21, 2020 at 2:43 PM Axel Wagner >>> >> <axel.wa...@googlemail.com> wrote: >>> >> > >>> >> > also, of course, you could still use operators with them, while now >>> also knowing the exact semantics of those operators (e.g. in regards to >>> overflow), which might also be useful. >>> >> > >>> >> > On Fri, Aug 21, 2020 at 11:42 PM Axel Wagner < >>> axel.wa...@googlemail.com> wrote: >>> >> >> >>> >> >> >>> >> >> >>> >> >> On Fri, Aug 21, 2020 at 11:30 PM roger peppe <rogp...@gmail.com> >>> wrote: >>> >> >>> >>> >> >>> On Fri, 21 Aug 2020 at 22:10, jimmy frasche <soapbo...@gmail.com> >>> wrote: >>> >> >>>> >>> >> >>>> I'd assume that would fail to compile as you're returning a []T >>> not a []int >>> >> >>> >>> >> >>> >>> >> >>> If that's the case, then I'm not sure that such a type switch >>> would be very useful. It would tell you what type the values are, but you >>> can't do anything with them because all the values would still be of the >>> original type. >>> >> >> >>> >> >> >>> >> >> You can reasonably convert them to their underlying type and >>> *then* use them as such. >>> >> >> That would make it useful while not allowing what you posit. >>> >> >> >>> >> >>> I had assumed that the intention was that within the arm of the >>> type switch, the switched type would take on the specified type. >>> >> >>> That would allow (for example) specialising to use underlying >>> machine operations on []T when T is a known type such as byte. >>> >> >> >>> >> >> >>> >> >> It would, however, prevent you from calling methods on the type or >>> pass it to a function taking an interface compatible with the constraint. >>> >> >> Also, I shudder to even imagine how this could be put into a spec. >>> >> >> >>> >> >>> >>> >> >>> >>> >> >>> >>> >> >>>> On Fri, Aug 21, 2020 at 2:07 PM roger peppe <rogp...@gmail.com> >>> wrote: >>> >> >>>> > >>> >> >>>> > >>> >> >>>> > On Fri, 21 Aug 2020 at 01:28, Ian Lance Taylor < >>> ia...@golang.org> wrote: >>> >> >>>> >> >>> >> >>>> >> After many discussions and reading many comments, we plan to >>> move >>> >> >>>> >> forward with some changes and clarifications to the generics >>> design >>> >> >>>> >> draft. >>> >> >>>> >> >>> >> >>>> >> 1. >>> >> >>>> >> >>> >> >>>> >> We’re going to settle on square brackets for the generics >>> syntax. >>> >> >>>> >> We’re going to drop the “type” keyword before type >>> parameters, as >>> >> >>>> >> using square brackets is sufficient to distinguish the type >>> parameter >>> >> >>>> >> list from the ordinary parameter list. To avoid the >>> ambiguity with >>> >> >>>> >> array declarations, we will require that all type parameters >>> provide a >>> >> >>>> >> constraint. This has the advantage of giving type parameter >>> lists the >>> >> >>>> >> exact same syntax as ordinary parameter lists (other than >>> using square >>> >> >>>> >> brackets). To simplify the common case of a type parameter >>> that has >>> >> >>>> >> no constraints, we will introduce a new predeclared >>> identifier “any” >>> >> >>>> >> as an alias for “interface{}”. >>> >> >>>> >> >>> >> >>>> >> The result is declarations that look like this: >>> >> >>>> >> >>> >> >>>> >> type Vector[T any] []T >>> >> >>>> >> func Print[T any](s []T) { … } >>> >> >>>> >> func Index[T comparable](s []T, e T) { … } >>> >> >>>> >> >>> >> >>>> >> We feel that the cost of the new predeclared identifier “any” >>> is >>> >> >>>> >> outweighed by the simplification achieved by making all >>> parameter >>> >> >>>> >> lists syntactically the same: as each regular parameter >>> always has a >>> >> >>>> >> type, each type parameter always has a constraint (its >>> meta-type). >>> >> >>>> >> >>> >> >>>> >> Changing “[type T]” to “[T any]” seems about equally readable >>> and >>> >> >>>> >> saves one character. We’ll be able to streamline a lot of >>> existing >>> >> >>>> >> code in the standard library and elsewhere by replacing >>> “interface{}” >>> >> >>>> >> with “any”. >>> >> >>>> >> >>> >> >>>> >> 2. >>> >> >>>> >> >>> >> >>>> >> We’re going to simplify the rule for type list satisfaction. >>> The type >>> >> >>>> >> argument will satisfy the constraint if the type argument is >>> identical >>> >> >>>> >> to any type in the type list, or if the underlying type of >>> the type >>> >> >>>> >> argument is identical to any type in the type list. What we >>> are >>> >> >>>> >> removing here is any use of the underlying types of the types >>> in the >>> >> >>>> >> type list. This tweaked rule means that the type list can >>> decide >>> >> >>>> >> whether to accept an exact defined type, other than a >>> predeclared >>> >> >>>> >> type, or whether to accept any type with a matching >>> underlying type. >>> >> >>>> >> >>> >> >>>> >> This is a subtle change that we don’t expect to affect any >>> existing >>> >> >>>> >> experimental code. >>> >> >>>> >> >>> >> >>>> >> We think that this definition might work if we permit >>> interface types >>> >> >>>> >> with type lists to be used outside of type constraints. Such >>> >> >>>> >> interfaces would effectively act like sum types. That is not >>> part of >>> >> >>>> >> this design draft, but it’s an obvious thing to consider for >>> the >>> >> >>>> >> future. >>> >> >>>> >> >>> >> >>>> >> Note that a type list can mention type parameters (that is, >>> other type >>> >> >>>> >> parameters in the same type parameter list). These will be >>> checked by >>> >> >>>> >> first replacing the type parameter(s) with the corresponding >>> type >>> >> >>>> >> argument(s), and then using the rule described above. >>> >> >>>> >> >>> >> >>>> >> 3. >>> >> >>>> >> >>> >> >>>> >> We’re going to clarify that when considering the operations >>> permitted >>> >> >>>> >> for a value whose type is a type parameter, we will ignore >>> the methods >>> >> >>>> >> of any types in the type list. The general rule is that the >>> generic >>> >> >>>> >> function can use any operation permitted by every type in the >>> type >>> >> >>>> >> list. However, this will only apply to operators and >>> predeclared >>> >> >>>> >> functions (such as "len" and "cap"). It won’t apply to >>> methods, for >>> >> >>>> >> the case where the type list includes a list of types that >>> all define >>> >> >>>> >> some method. Any methods must be listed separately in the >>> interface >>> >> >>>> >> type, not inherited from the type list. >>> >> >>>> >> >>> >> >>>> >> This rule seems generally clear, and avoids some complex >>> reasoning >>> >> >>>> >> involving type lists that include structs with embedded type >>> >> >>>> >> parameters. >>> >> >>>> >> >>> >> >>>> >> 4. >>> >> >>>> >> >>> >> >>>> >> We’re going to permit type switches on type parameters that >>> have type >>> >> >>>> >> lists, without the “.(type)” syntax. The “(.type)” syntax >>> exists to >>> >> >>>> >> clarify code like “switch v := x.(type)”. A type switch on a >>> type >>> >> >>>> >> parameter won’t be able to use the “:=” syntax anyhow, so >>> there is no >>> >> >>>> >> reason to require “.(type)”. In a type switch on a type >>> parameter >>> >> >>>> >> with a type list, every case listed must be a type that >>> appears in the >>> >> >>>> >> type list (“default” is also permitted, of course). A case >>> will be >>> >> >>>> >> chosen if it is the type matched by the type argument, >>> although as >>> >> >>>> >> discussed above it may not be the exact type argument: it may >>> be the >>> >> >>>> >> underlying type of the type argument. >>> >> >>>> > >>> >> >>>> > >>> >> >>>> > Here's one interesting implication of this: it allows us to do >>> type conversions that were not previously possible. >>> >> >>>> > >>> >> >>>> > For example, if we have "type I int", we can use a type switch >>> to convert some type []I to type []int: >>> >> >>>> > https://go2goplay.golang.org/p/-860Zlz7-cn >>> >> >>>> > >>> >> >>>> > func F[type T intlike](ts []T) []int { >>> >> >>>> > switch T { >>> >> >>>> > case int: >>> >> >>>> > return ts >>> >> >>>> > } >>> >> >>>> > return nil >>> >> >>>> > } >>> >> >>>> > >>> >> >>>> > It seems to me that this kind of thing will allow us to >>> perform a similar conversion (convert some part of the type to its >>> underlying type) on any type. >>> >> >>>> > >>> >> >>>> > In the early days of Go, the spec allowed this kind of >>> conversion as a normal type conversion. I wonder if it might be reasonable >>> to revert to those more relaxed semantics. I think they're potentially >>> useful, for example, when dealing with named types obtained from modules >>> with two different major versions without incurring copies. >>> >> >>>> > >>> >> >>>> > Although in the above-linked issue Robert talks about runtime >>> costs such as "possibly re-mapping method tables", I don't see that this >>> would necessarily be the case. Thoughts? >>> >> >>>> > >>> >> >>>> > -- >>> >> >>>> > 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...@googlegroups.com. >>> >> >>>> > To view this discussion on the web visit >>> https://groups.google.com/d/msgid/golang-nuts/CAJhgacjL7p7qck%3DSO0Nz9f%2BKZw6MNcgkD5REXwSNK7_fCTXYQg%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...@googlegroups.com. >>> >> >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/golang-nuts/CAJhgacjTm%3DC-6f%2B4%2BA0HCTDT0_U7pQZOmRjShuzigdocDzAcww%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/eefbb574-bd6d-42d4-9e18-f79ca7129b3en%40googlegroups.com.