On Wed, 8 Jul 2020 at 00:33, Steven Blenkinsop <steven...@gmail.com> wrote:

> On Tue, Jul 7, 2020 at 10:44 AM, roger peppe <rogpe...@gmail.com> wrote:
>
>>
>> In my description, there's no assumption that doing it over the type
>> parameter implies a refinement of the previously set type constraints. In
>> fact it definitely implies otherwise because (for example) if you know that
>> a generic type parameter has the known type "string", then it's a loosening
>> rather than a tightening of the constraint - you can now do more things
>> with values of that type than you could previously.
>>
>
> I think this is speaking at cross purposes. The identity of the type is
> more constrained (it must be string  as opposed to any other type
> satisfying a particular interface), but you can do more with it in your
> generic code. You're refining the constraint on the identity of the type
> while at the same time expanding its capabilities. An unconstrained type
> parameter can be any type but supports the fewest operations.
>

Fair point.


>
> I don't think it's sufficient. Consider this program:
>> https://go2goplay.golang.org/p/wO0JHIuHH2l. If "string" matches both
>> "myString" and "string" itself, then the type checker would allow the
>> assignment of a function of type "func(string) uint64" to a function of
>> type "func(myString) uint64" with no explicit type conversion, which breaks
>> an important safety constraint in the language. Worse, if we let an
>> interface type match any concrete type that happens to implement that
>> interface, then there's a serious issue because those types probably don't
>> have the same shape, so can't be used interchangeably. For example, this
>> program would be valid, but isn't possible to compile because io.Stringer
>> and string have different representations:
>> https://go2goplay.golang.org/p/_uLjQxb-z-b
>>
>
> I would think that in the second case, the assignment to xx wouldn't type
> check because T is only known to implement io.Stringer rather than being
> identical to io.Stringer.
>

That depends on the semantics of the type switch. In my suggestion, it
would type check because the case would only be chosen if the argument type
is *exactly* that type (but the xx slice wouldn't be assigned to). You'd
need to add a "type" qualifier to match on any type that implements
io.Stringer.

Perhaps this would be more clear if it was written as
>
> type switch {
> case T io.Stringer:
>       // Code here can treat the type parameter T
>       // as though the generic type list defining
>       // it was `(type T io.Stringer)`
> }
>

That's another interesting syntax. I'm not sure whether there's any
particular advantage in mentioning the type parameter in each case,
although I guess it does mean that the syntax for multiple matches is
straightforward and can allow an "any" match.

    type switch {
    case T1 string, T2 string:
    case T1 []byte, T2 string:
    case T1 string:
    }

If my syntax were to support multiple type parameters, that might look like

   switch T1, T2 {
   case (string, string):
   case ([]byte, string):
   case (string, type interface{}):
   }

One could define _ to be a synonym for "type interface{}", I guess.


Of course, this wouldn't allow you to write either of your examples. But
> then, your stringHash example could be written using:
>
> func stringHash(type S interface{type string})(s S) uint64 {
> return 1
> }
>

That doesn't seem ideal to me. There are many potentially useful
non-generic functions out there and I think it would be nice to be able to
use them in this way.

>
> https://go2goplay.golang.org/p/FAaqnFalYCL
>
> I think the key tension with allowing you to match on the specific type
> passed in is that, if you actually need to do this, then that means your
> function can't handle certain type parameters which are permitted by its
> signature, i.e. it's not total over its type parameter domain.
>

ISTM that technically the function is still total over the type parameter
domain (assuming you don't panic in the default case) - it just has
different behaviour depending on the type parameters, which is exactly what
the type switch is for. Also, you can *already* do this in a slightly more
limited way, by converting to interface{} and type switching on that,
although that's restrictive because it doesn't allow you to assign back to
generic values - the types aren't unified - which is why we're talking
about this feature here.


> If interfaces allowed you to restrict the type parameters passed in to the
> specific ones you can handle, then you would necessarily also be able to
> handle each specific case by matching on interface satisfaction as well.
>

I'd hope that most people using type switches for specialisation would
include a generic fallback for unknown types. The main use cases I see for
it are optimisation and preserving backward compatibility.

  cheers,
    rog.

-- 
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/CAJhgachtriny-g5%2BHGD2SqhopSxYcrsZw90AJvTh7%3DU4KxNsTA%40mail.gmail.com.

Reply via email to