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.

Reply via email to