On Fri, Jun 19, 2020 at 9:31 AM Bryan C. Mills <bcmi...@google.com> wrote:
>
> On Fri, Jun 19, 2020 at 1:30 AM Ian Lance Taylor <i...@golang.org> wrote:
>>
>> 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.

I'm sure that I don't really understand what you are saying.

But from my perspective using a type list in an interface type used as
a type constraint permits certain operations in that generic function.
That is a specific feature of generic functions.  You seem to be
trying to extend that capability to non-generic functions.  But that
doesn't work.

A generic function permits saying that certain values are exactly the
same type.  There is no way to say that using interface types in a
non-generic function.

The fact that this function is invalid:

func Add2(x, y SmallInt) SmallInt { return x + y }

is no more interesting than the fact that this function is invalid:

func Add2(type T1 SmallInt, T2 SmallInt)(x T1, y T2) T1 { return T1(x + y) }

You can only use the + operator if you have the same underlying type
on both sides.  Neither of these variants of Add2 guarantee that.
Only a generic function can guarantee that, and that guarantee is
entirely separate from whether constraints are interfaces, or
contracts, or something else entirely.


> 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”.

That all sounds right to me.


> 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.

I don't understand what the second limitation means.  The current
design draft has no way to require that a type parameter have an
interface type.  Can you give an example of what you mean?


> 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.)

Again I'm sure that I don't understand what you are saying.  My
initial reaction is that of course the meaning of a type-list
interface depends on whether it is used as a type constraint or is
passed as a type argument.  Those are two entirely different
operations.  You can't use a type parameter as a type constraint.  I
suppose you could regard that as a limitation of the system, but it's
an intentional one.  If a type parameter can be a type constraint,
then there is no contract for the generic function: it has ceded
control over what type arguments are permitted.  It is no longer
possible to compile the generic function separately.  It's a very
different semantic model.


> 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.)

I don't know if I would say that they are something more restricted,
exactly, but using them in a different way has a different effect.

> 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.

I don't necessarily object, if we can find the right name and syntax,
but I don't understand how that would be effectively different from
what the design draft says today.  We would say that a type constraint
can be an interface type, or it can be this other thing that is an
interface type plus a list of types.

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/CAOyqgcU7c1T%3DKYA6YM2v0RnWTTn0b0A3prJ-k2%2Bhraw5VDUNHg%40mail.gmail.com.

Reply via email to