On Fri, 21 Aug 2020 at 23:12, jimmy frasche <soapboxcic...@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
}

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 <soapboxcic...@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.wagner...@googlemail.com> wrote:
> >
> > On Fri, Aug 21, 2020 at 11:46 PM Ian Lance Taylor <i...@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.wagner...@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.wagner...@googlemail.com> wrote:
> >> >>
> >> >>
> >> >>
> >> >> On Fri, Aug 21, 2020 at 11:30 PM roger peppe <rogpe...@gmail.com>
> wrote:
> >> >>>
> >> >>> On Fri, 21 Aug 2020 at 22:10, jimmy frasche <
> soapboxcic...@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 <rogpe...@gmail.com>
> wrote:
> >> >>>> >
> >> >>>> >
> >> >>>> > On Fri, 21 Aug 2020 at 01:28, Ian Lance Taylor <i...@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+unsubscr...@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+unsubscr...@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/CAJhgacgBbaTyw965AHNSsyFtZ%3DnsTtWRtrVqioy1X9Ouy%3D2G%3DQ%40mail.gmail.com.

Reply via email to