On Fri, Jun 19, 2020 at 9:31 AM Bryan C. Mills <[email protected]> wrote:
>
> On Fri, Jun 19, 2020 at 1:30 AM Ian Lance Taylor <[email protected]> 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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/CAOyqgcU7c1T%3DKYA6YM2v0RnWTTn0b0A3prJ-k2%2Bhraw5VDUNHg%40mail.gmail.com.