On Mon, 29 Apr 2024 at 22:06, Andrew Harris <harris.and...@gmail.com> wrote:

> 2. On implementation, before considering variadic tuple constraints: There
> is tuple machinery already in the type system
> <https://github.com/golang/go/blob/master/src/go/types/tuple.go>, used
> for assignments and signatures, but tuples are not first class. Also, we
> know where and how they fit in the unification algorithm
> <https://github.com/golang/go/blob/16ce8b3925deaeb72541ee96b6ee23a08fc21dea/src/go/types/unify.go#L629>.
>  It's
> as simple as one could hope: *match the arity, then unify the component
> types*. I take this as evidence the idea of a tuple constraint is
> feasible.
>

Note added emphasis above.


>
>
>
>
>
>
>
>
>
>
> *func main() {        for x := range FSeq(strconv.Atoi) {
> fmt.Println(reflect.TypeOf(x))        }}func FSeq[V (... any)](f
> func(string) V) iter.Seq[V] {        return func(yield func(v V) bool)) {
>               yield(f("1234"))        }}*
>
>
> *If it wouldn't be valid, why not? If it's OK, what would it print?*
> my pedantry would suggest spelling out the semantics `type R (Value int,
> Err error)` and `FSeq[R](strconv.Atoi)`.


I don't really understand how that could work, tbh. In `FSeq[R]` it seems
like you're passing a single type parameter of type R,
so the V type parameter would have a single member of type R. But then that
arity (1) wouldn't match the arity of the
argument count to strconv (2).

That is, given `FSeq[R]`, I'd expect it to take an argument of type
`func(string) R` not `func(string) (int, error)`
but if that's the case, the example wouldn't work AFAICS.

It seems to me that this conflation of sometimes-named tuples and
value-lists is a significant flaw in the suggested semantics.

  cheers,
    rog.

On Mon, 29 Apr 2024 at 22:06, Andrew Harris <harris.and...@gmail.com> wrote:

>
> *> FWIW this kind of restriction has no precedent in Go. Currently any
> type may be unnamed. This restriction seems arbitrary and irregular to me. *
> It seems unpopular.
>
>
> *> Isn't this illegal according to your TupleType syntax above? *
> Further evidence of a wrong idea :)
>
>
>
>
> *>> [T (any, any)] describes the type set consisting of any 2-ary tuple>
> By analogy with [T map[any]any] I'd expect the "any" there to be the
> regular "any" type (as used outside generics) rather than the type
> constraint "any". That is, my intuition would expect this to disallow a
> (string, string) tuple, but my sense is that that's not what you're
> suggesting. In general, a type constraint can be either a regular type (a
> type set) or an interface type, but this doesn't seem like either, and
> looks to me like it would significantly complicate the generics
> specification.*
> Yes - I'm suggesting a third category of constraint. It would be a
> significant change, and a tradeoff that would add weight to the generics
> spec. To further detail what I think this involves:
>
> 1. The amount of syntax is on the same order as specifying tuples for
> non-generic code. Introducing tuples is pretty efficient. I'd imagine a
> sharp, finely tuned framing the tuple->list-of-types substitution adds more
> cases to existing syntax, on the same order as #64457 (tuples for go) or
> #66651 (variadic type parameters) would also require. Overall, #64613 (just
> `...` for structs) seems simpler.
>
> 2. On implementation, before considering variadic tuple constraints: There
> is tuple machinery already in the type system
> <https://github.com/golang/go/blob/master/src/go/types/tuple.go>, used
> for assignments and signatures, but tuples are not first class. Also, we
> know where and how they fit in the unification algorithm
> <https://github.com/golang/go/blob/16ce8b3925deaeb72541ee96b6ee23a08fc21dea/src/go/types/unify.go#L629>.
>  It's
> as simple as one could hope: match the arity, then unify the component
> types. I take this as evidence the idea of a tuple constraint is feasible.
>
> 3. On implementation with variadiac tuple constraints: So long as
> variadicity is limited to a single, trailing tuple component, the
> corresponding step in unification - matching arity - is nearly trivial, and
> unification of types is likewise uncomplicated.
>
> 4. Considering varidiac elements of a tuple constraint in positions other
> than the tail: I don't have a confident analysis of everything that comes
> to mind, but I'm thinking this leads to bad outcomes, like an increase in
> the computational complexity of the unification algorithm, or obnoxiously
> esoteric rules for how constraints intersect.
>
>
>
> *>> [T (K, any), K comparable] describes the type set of 2-ary tuples that
> begin with a comparable element.> How would you see that as different from
> [T (comparable, any)] ?*
>
> The type parameter `K` might be significant elsewhere, e.g. `func F[T (K,
> any), K any](f func(T), input K)`.
>
>
>
> *> Would these two be equivalent too?> func F[K comparable, V any](f
> []func(K, V)) {}> func F[KV (comparable, any)](f []func(KV)) {}*
>
> Yes, and I can be sharper about "equivalent". I don't think that the type
> parameter lists should be equivalent. Tuple constraints capture essential
> information about grouping and position of types. But any
> slice-of-functions type should be equivalently valid or invalid for either.
>
>
>
>
>
>
>
>
>
>
>
> *func main() {        for x := range FSeq(strconv.Atoi) {
> fmt.Println(reflect.TypeOf(x))        }}func FSeq[V (... any)](f
> func(string) V) iter.Seq[V] {        return func(yield func(v V) bool)) {
>               yield(f("1234"))        }}*
>
>
> *If it wouldn't be valid, why not? If it's OK, what would it print?*
> My understanding is that how helpful type inference can be is not a
> question of specification. I would hope the code successfully infers
> without hints, and prints `(int, error)`. If not, by #64457 rules the hint
> would be `FSeq[(int, error)](strconv.Atoi)`; my pedantry would suggest
> spelling out the semantics `type R (Value int, Err error)` and
> `FSeq[R](strconv.Atoi)`. (I'm losing conviction on that pedantry...)
> On Monday, April 29, 2024 at 2:24:46 AM UTC-7 roger peppe wrote:
>
>> On Sun, 28 Apr 2024 at 12:10, Andrew Harris <harr...@spu.edu> wrote:
>>
>>> Bouncing out from some recent discussions on the github issue tracker,
>>> it seems like there's some interest in tuples in Go. I thought the
>>> discussion in #66651 led to some interesting ideas, but it's also beginning
>>> to drift. Maybe this is a better place to brain-dump some ideas. (This
>>> could be a proposal but I'm not sure that's quite right either, that might
>>> be spammy.)
>>>
>>> Some recent issues:
>>> 1. #64457 "Tuple types for Go"
>>> <https://github.com/golang/go/issues/64457> (@griesemer)
>>> 2. #66651 "Variadic type parameters"
>>> <https://github.com/golang/go/issues/66651> (@ianlancetaylor)
>>> 3. "support for easy packing/unpacking of struct types"
>>> <https://github.com/golang/go/issues/64613> (@griesemer)
>>>
>>> Synthesizing from those discussions, and satisfying requirements framed
>>> by @rogpeppe
>>> <https://github.com/golang/go/issues/66651#issuecomment-2054198677>,
>>> the following is a design for tuples that comes in two parts. The first
>>> part explores tuples in non-generic code, resembling a restrained version
>>> of #64457. The second part explores tuple constraints for generic code,
>>> reframing some ideas from #66651 in terms of tuples. It's a fungal kingdom
>>> approach, where tuples occupy some unique niches but aren't intended to
>>> dominate the landscape.
>>>
>>> *TUPLES IN NON-GENERIC CODE*
>>>
>>> Tuples are evil
>>> <https://github.com/golang/go/issues/32941#issuecomment-509367113> because
>>> the naming schemes are deficient. To enjoy greater name abundancy, this
>>> design tweaks tuple *types* from #64457 in the direction of 
>>> "super-lightweight
>>> structs"
>>> <https://github.com/golang/go/issues/64457#issuecomment-1834358907>. It
>>> still allows tuple *expressions* from #64457, for tuples constructed
>>> from bare values.
>>>
>>> *1. Tuple types*
>>> Outside of generics, tuple *type* syntax requires named fields.
>>>
>>> TupleType = "(" { IdentifierList Type [ ", " ] } ")" .
>>>
>>> // e.g.:
>>> type Point (X, Y int)
>>>
>>> More irregularly, the TupleType syntax is used *exclusively* to declare
>>> named types, and these named tuple types cannot implement methods. As a
>>> result, a named tuple type is entirely defined at the site of the type
>>> definition.
>>>
>>
>> FWIW this kind of restriction has no precedent in Go. Currently any type
>> may be unnamed. This restriction seems arbitrary and irregular to me.
>>
>>>
>>> *2. Tuple literals*
>>> The tuple *expression* syntax of #64457 remains valid. The result is an
>>> implicitly typed tuple value. Literals of a named tuple type are also
>>> valid, and resemble struct literals.
>>>
>>> point1 := (0, 0) // implicitly typed
>>> point2 := Point(X: 0, Y: 0) // explicitly typed
>>>
>>>
>>> *3. Promotion and expansion*
>>> There is no way to capture the type of an implicitly typed tuple value -
>>> the result of a bare tuple *expression* - with tuple *type* syntax.
>>> However, promotion and expansion are available as way to leverage tuple
>>> values.
>>>
>>> - Promotion: An implicitly typed tuple value is freely and automatically
>>> promoted to a value of a named tuple type, if and only if the sequence of
>>> types is congruent (same types, same order, same arity) between the
>>> implicit and named type:
>>>
>>> type T (string, string)
>>>
>> Isn't this illegal according to your TupleType syntax above?
>>
>>> var t T
>>> t := ("foo", "bar")
>>>
>>> The RHS of the assignment is implicitly typed (string, string), so the
>>> value can be promoted to the LHS's congruent type T without further
>>> ceremony.
>>>
>>> - Any tuple value can, under the condition of congruence, expand with
>>> ... "wherever a list of values is expected" (#66651). This means places
>>> like assignments, function calls, function returns, struct/slice/array
>>> literals, for/range loops, and channel receives. Each of the github issues
>>> (#64457, #64613, #66651) explores this in more detail. Qualifications and
>>> some subjectivity are involved, and a full proposal would explore this more
>>> completely and sharply, but the intuitive notion is pretty straightforward.
>>>
>>>
>>> *TUPLE CONSTRAINTS*
>>> For generic code, this design's driving concept is tuple constraints. A
>>> tuple constraint describes type sets that are exclusively composed of tuple
>>> types. Loosely, where union-of-types or set-of-methods type constraints are
>>> currently, a tuple constraint would also be allowed. The rules for code
>>> parameterized on tuple constraints should resemble #66651 in many ways.
>>> Most essentially, it should be possible to substitute a tuple constraint
>>> "wherever a list of types is permitted", as suggested in #66651.
>>>
>>>
>>> *1. Non-variadic tuple constraints*
>>> The current TypeParamDecl production is:
>>>
>>> TypeParamDecl = IdentifierList TypeConstraint .
>>>
>>> Adding tuple constraints can be accomplished by extending TypeParamDecl 
>>> syntax
>>> to include an alternative to the TypeConstraint, a TupleConstraint.
>>> Then, a tuple constraint is constructed from TypeConstraint elements.
>>>
>>> TypeParamDecl = IdentifierList ( TypeConstraint | TupleConstraint ) .
>>> TupleConstraint = "(" { TypeConstraint [ "," ] } ")" .
>>>
>>> Some examples:
>>> [T (any, any)] describes the type set consisting of any 2-ary tuple
>>>
>>
>> By analogy with [T map[any]any] I'd expect the "any" there to be the
>> regular "any" type (as used outside generics) rather than the type
>> constraint "any". That is, my intuition would expect this to disallow a
>> (string, string) tuple, but my sense is that that's not what you're
>> suggesting.
>>
>> In general, a type constraint can be either a regular type (a type set)
>> or an interface type, but this doesn't seem like either, and looks to me
>> like it would significantly complicate the generics specification.
>>
>>
>>> [T (K, any), K comparable] describes the type set of 2-ary tuples that
>>> begin with a comparable element.
>>>
>>
>> How would you see that as different from [T (comparable, any)] ?
>>
>>
>>>
>>> Via tuple -> list-of-types substitution, the following would be
>>> equivalent:
>>>
>>> func F[K comparable, V any](f func(K, V)) { ... }
>>> func F[KV (comparable, any)](f func(KV)) { ... }
>>
>>
>> Would these two be equivalent too?
>>
>> func FK comparable, V any](f []func(K, V)) {}
>>
>> func F[KV (comparable, any)](f []func(KV)) {}
>>
>>> *2. Variadic tuple constraints*
>>>
>>> A variadic tuple constraint is described with an extension to the
>>> TupleConstraint production: an optional VariadicTupleElement is
>>> appended to it.
>>>
>>> TupleConstraint = "(" { TypeConstraint [ "," ] } [ VariadicTupleElement
>>> ] ")" .
>>> VariadicTupleElement = "..." TypeConstraint .
>>>
>>> The identifier for a variadic tuple constraint may be still be
>>> substituted for a list of types. Drawing from use cases discussed in
>>> #66651, this leads to function signatures like:
>>>
>>> func Filter[V (... any)](f func(V), seq Seq[V]) Seq[V]
>>>
>>> func MergeFunc[V (... any)](xs, ys Seq[V], f func(V, V) int) Seq[V]
>>>
>>
>> It sounds like by your explanation here that this code should be valid:
>>
>> func main() {
>>         for x := range FSeq(strconv.Atoi) {
>>                 fmt.Println(reflect.TypeOf(x))
>>         }
>> }
>>
>> func FSeq[V (... any)](f func(string) V) iter.Seq[V] {
>>         return func(yield func(v V) bool)) {
>>                 yield(f("1234"))
>>         }
>> }
>>
>> If it wouldn't be valid, why not? If it's OK, what would it print?
>>
> --
> 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/a7482fb7-a130-4ba7-aad6-9f81910e7b95n%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/a7482fb7-a130-4ba7-aad6-9f81910e7b95n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
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/CAJhgacgYSsa6GzSbW1_C8H--K7EjRJajUKBXodUw1nWUBZUzbQ%40mail.gmail.com.

Reply via email to