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/CANG3jXL6WBB2pFQuAJtEfLwtQYnD%3DkjbBD90QsZes-t4qMY37Q%40mail.gmail.com.

Reply via email to