On Fri, Jun 19, 2020 at 1:30 AM Ian Lance Taylor <i...@golang.org> wrote:

> On Wed, Jun 17, 2020 at 7:58 PM 'Bryan C. Mills' via golang-nuts
> <golang-nuts@googlegroups.com> wrote:
> >
> > On Wednesday, June 17, 2020 at 12:08:59 AM UTC-4 Ian Lance Taylor wrote:
> >>
> >> On Tue, Jun 16, 2020 at 9:04 PM Xie Zhenye <xiez...@gmail.com> wrote:
> >> >
> >> > I agree. constraint is different from normal interface. It's better
> to use type SomeConstraint constraint {} than type SomeConstraint interface
> {}
> >>
> >> That is an option, but then we would have two different concepts,
> >> constraints and interfaces, that are very very similar. It's not
> >> clear that that is better.
> >
> >
> > I think we already have two very different concepts — we're just
> conflating them together by giving them the same name.
> > As far as I can tell, the semantics of non-type-list interface types and
> the semantics of type-list interface types are not compatible.
> >
> > Today, if we have two interface types T1 and T2, with T1's method set is
> a superset of T2's, then any value assignable to T1 is also assignable to
> T2: that is, T1 is a subtype of (not just assignable to!) T2. That
> observation is also reflected in the Featherweight Go paper, in which a
> type argument satisfies a type constraint if (and only if) the argument is
> a subtype of the constraint.
> >
> > Based on the semantics of type-lists in type constraints, I would expect
> that a run-time interface type containing a type list would mean “an
> interface value whose dynamic type is one of the listed types”, or perhaps
> “an interface value whose dynamic type has one of the listed types as its
> underlying type”. For consistency, such interfaces should also have the
> same sort of subtyping relationship: if type T1's type-list is a strict
> subset of T2's type-list, then any value assignable to T1 (including a
> variable of type T1 itself!) should be assignable to T2.
> >
> > So, for example:
> > type SmallInt interface { type int8, int16 }
> > should be a subtype of
> > type MediumInt interface { type int8, int16, int32 }
> >
> > However, in the current design draft, a constraint that is a type-list
> interface allows use of the operators common to the types in the list.
> > In the presence of type-list subtypes of interface types, the semantics
> for those operators would be confusing at best. Consider the program:
> >
> > func Add(type T MediumInt)(x, y T) T {
> > return x + y
> > }
> >
> > func main() {
> > var a int8 = 127
> > var b int16 = 1
> > fmt.Println(Add(SmallInt)(a, b))  // Should this print 128, or -128?
> > }
>
> I'm not sure whether it affects your point, but I want to point out
> that this program is invalid.  The MediumInt type constraint accepts
> any type whose underlying type is int8, int16, or int32.  The type
> SmallInt, an interface type, is not one of those types.  So you are
> not only extending the design draft to permit SmallInt to be an
> ordinary interface type, you are extending the meaning of a type list
> in a constraint to accept an interface type that implements the type
> constraint.  That can't work, and this example shows why it can't
> work: you can't add an int8 value and an int16 value.
>
> This code is acting as though, if ordinary interface types could have
> type lists, it would be OK to write
>
> func Add2(x, y SmallInt) SmallInt { return x + y }ᵢ
>
> That is not OK, even though SmallInt has a type list.  Even though
> every type in theSmallInt type list supports +, they don't support +
> with every other type in the type list.
>

Yes, that is exactly my point: the fact that that program is invalid
implies that type-list interfaces are not consistent with the semantics of
other interface types.

As a *run-time* interface type, MediumInt clearly must implement itself
(that is a fundamental property of interface types), and SmallInt (I claim)
must also implement MediumInt because the concrete values it allows are a
strict subset of the values allowed for MediumInt. (Otherwise, interface
types seem incoherent as a concept.)

The constraint-satisfaction rule for ordinary (non-type-list) interfaces,
both in the current draft design and in FGG, is very simple: “Implementing
a constraint is simply implementing the interface type.” (In the FGG
paper, constraint-satisfaction is formalized as the judgement “Φ :=Δ φ”,
which is defined using a single, uniform rule.)

However, type-list interfaces in the current design have a different, more
complex rule: “[the type argument must implement the methods in the
interface type *and*] the underlying type of the type argument must be
identical to the underlying type of one of the types in the type list.”
That is a much stronger requirement than “simply implementing the interface
type”, and it implies that for an interface I that happens to include a
type-list, there is no way to express the simple constraint “T implements
interface I” without *also* adding the secondary constraint that “the
underlying type of [T] must be … one of types in the type list”.

Similarly, the type-checking rule for non-type-list interfaces is simple:
“assuming that the type arguments are distinct types that each implement
their constraint interfaces, check the body of the declaration”. In
contrast, the type-checking rule for type-list interfaces has an extra
condition: “assuming that the type arguments are distinct type that each
implement their constraint interfaces, *and assuming that each argument
whose constraint is a type-list has an underlying type identical to one of
the types in the list*, check the body of the declaration”.

Because the rules for type-list interfaces always have an extra condition
beyond “simply implementing the interface type”, we would be locked into at
least one of the following limitations on the evolution of the language:

   -
   - A type-list interface can never be used as a type argument.
   - Or, a type parameter of an interface type can never be allowed as the
   constraint of another type parameter, nor embedded in the constraint of
   another type parameter.

Otherwise, we would break the substitution property: the meaning of a
type-list interface would depend upon whether it was written literally in
the source code or passed as a type argument. (That is: the meaning of a
generic declaration instantiated with a given list of argument types would
be *different from* the meaning of the same declaration with some of its
actual arguments substituted for the corresponding parameters.)

I think both of those limitations are severe.

   - If a type-list interface cannot be used as a type argument, then
   type-list interfaces are not really “interface types” — in fact, they are
   not “types” at all, because they cannot be used as even unrestricted type
   arguments.
   - On the other hand, if parameters of interface type cannot be used as
   constraints for other type parameters, then the constraints are not really
   “interface types” in general, but rather something more restricted. (In the
   current draft we have no explicit way to express that a parameter is “of
   interface type” in general, but it doesn't seem like a stretch to make
   parameters-as-subtyping-constraints work in general.)

To me, this all suggests that the “underlying type” sort of constraint
should be conceptually and syntactically different from the “simply
implementing the interface type” sort of constraint.

> So type-lists as they are defined in the current draft either cannot have
> the subtyping properties of ordinary interfaces, or must have a meaning as
> type constraints that is fundamentally different from their meaning as
> interfaces. Either way, they don't seem at all consistent with ordinary
> interfaces to me, so I would prefer that we not call them interfaces.
>
> Maybe this is still true.  I'm not sure.  But I don't yet see a reason
> to think that this is true.
>
> Thanks.
>
> Ian
>

-- 
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/CAKWVi_QqjCJL1cnSdaZRrO4Jr0gj9_Ayso0tTZc%2BrXgHMvcYKw%40mail.gmail.com.

Reply via email to