Changeset 1b770e40


Ignore:
Timestamp:
Oct 6, 2024, 5:19:21 PM (2 hours ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Parents:
b0fcd0e
Message:

first proofread of tuple proposal

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/tuples.md

    rb0fcd0e r1b770e40  
    22======
    33
    4 This proposal is to update tuples, as they were created by Rob in his thesis,
    5 to address problems that have appeared in their use since then. This proposal
    6 is an attempt to address some of those problems. Adding new functionality,
    7 updating existing features and removing some problematic features.
    8 
    9 The core of change is breaking the current restructurable tuples into
    10 unstructured tuples and structured tuples. Unstructured tuples handle most
    11 of the existing uses, with structured tuples filling in a few missing
    12 use cases.
     4Tuples were introduced by Dave Till in K-W C, added to CFA by Rodolfo Esteves,
     5and extended by Robert Schluntz. This proposal discusses updates for CFA tuples
     6to address problems that have appeared in their usage over the past 6 years.
     7The proposal attempts to address problems by adding new functionality, updating
     8existing features, and removing some problematic ones.
     9
     10The core change is breaking the current restructurable tuples into unstructured
     11and structured tuples. Unstructured tuples handle most of the existing uses,
     12with structured tuples filling in a few missing use cases.
    1313
    1414Current State of Tuples
    1515-----------------------
    16 An overview of the current design, as the starting place for the proposal.
     16An overview of the current tuples design is the starting place for the proposal.
    1717
    1818### Tuple Syntax
    1919
    20 An overview of the syntax for the main three components of tuples, the types
    21 of tuples, the tuple expressions/values (constructing tuples) and tuple index
    22 expressions (deconstructing tuples).
    23 
    24 Current syntax for tuple types:
     20Currently, tuples have three main components: tuple types, tuple
     21expressions/values (constructing tuples), and tuple index expressions
     22(deconstructing tuples).
     23
     24Current syntax for tuple types.
     25
    2526-   Nullary: [void] or []
    2627-   Unary: [TYPE]
    27 -   Binary: [TYPE, TYPE]
    28 -   The pattern continues for three or more elements.
     28-   Nary: [TYPE, TYPE, ...]
     29
     30Tuple types can appear in a function return and parameter declaration, or a
     31tuple variable declaration. Note, the Nullary tuple is only meaningful in the
     32return context,
     33
     34        void f(...);   // equivalent
     35        [void] f(...);
     36        [] f(...);
     37
     38as C does not support a void declaration.
     39
     40        int f( void x );    // disallowed
     41        int f( [void] x );
     42        int f( [] x );
    2943
    3044Current syntax for tuple expressions:
    31 -   Nullary: None. (Same as `void`, use return without an expression.)
    32 -   Unary: {EXPR} (This might be an error, but I can't make [EXPR] work.)
    33 -   Binary: [EXPR, EXPR]
    34 -   The pattern from binary continues for three or more elements.
    35 
    36 Current syntax for tuple index expressions, is much simpler. It uses the
    37 member index expression syntax, except the member name is replaced with the
    38 element index, which is an integer literal, showing the index of the element
    39 to get.
    40 
    41 Here is a brief example showing all three parts.
     45
     46-   Nullary: (Same as `void`, use return without an expression.)
     47
     48        [] f( ) { return; }
     49        [] f( ) { return [] ; }
     50
     51-   Unary:
     52
     53        [int] f( ) { return 3; }
     54        [int] f( ) { return [3]; }
     55
     56-   Nary: [EXPR, EXPR]
     57
     58        [int,int] f( ) { return [3,4]; }
     59
     60Currently, there is a parsing problem for nullary and unary tuple expression,
     61which is being looked at. Hence, only these two forms work.
     62
     63        [] f( ) { return; } // nullary
     64        [int] f( ) { return 3; } // unary
     65   
     66Current syntax for tuple indexing is an integer constant, where its value
     67selects a tuple member, e.g.:
    4268
    4369        [char, int] tup;
    4470        tup = ['a', 0];
    45         int value = t.1;
     71        char ch = t.0; // select first tuple member
     72        int value = t.1; // select second tuple member
    4673
    4774### Mass and Multi-Assignment
    4875
    49 Two special forms of assignment can be used to set values in tuples.
    50 Mass Assignment assigns every element in the tuple to a single source value.
     76Two special forms of assignment can be used to set values in tuples: mass and
     77multi.  Mass assignment assigns every element in the destination tuple to a
     78single source value.
    5179
    5280        [int, long, float] dst;
    5381        int src = 4
    54         dst = src;
    55         // Expands to roughly: dst.0 = src, dst.1 = src, dst.2 = src
    56 
    57 Multi-Assignment assigns every element to the matching element of a source
    58 tuple (both tuples must be the same size).
    59 
    60         [int, long, float] dst;
    61         [int, long, double] src = [1, 20, 300.0];
    62         dst = src;
    63         // Expands to roughly: dst.0 = src.0, dst.1 = src.1, dst.2 = src.2
    64         // Note that the last assignment is not an exact match,
    65         // an implicit conversion will be applied.
     82        dst = src;  // => dst.0 = src; dst.1 = src; dst.2 = src
     83
     84Multi-assignment assigns every element in the destination tuple to the
     85corresponding element in the source tuple. Both tuples must be the same size
     86and the elements assignment compatible => conversions.
     87
     88        [long, int, float] dst;
     89        [int, char, double] src = [1, 'a', 300.0];
     90        dst = src;   // => dst.0 = src.0; dst.1 = src.1; dst.2 = src.1
    6691
    6792### Tuple Restructuring
    6893
    6994Tuples can be restructured as part of overload resolution. Function calls
    70 will unpack tuples and repack tuples to match signatures. This is a type of
    71 implicit conversion and is considered during overload resolution.
     95unpack tuples and repack tuples to match signatures. This semantics is a form
     96of implicit conversion and is considered during overload resolution.
    7297
    7398A simple example is matching multiple parameters of a function to a single
    74 argument expression, each parameter is bound to a different element of the
    75 returned tuple.
    76 
    77         [int, int] paramFunc();
    78         void callFunc(int a, int b, int c, int d);
    79 
    80         void restructure() {
    81                 callFunc(paramFunc(), paramFunc());
     99argument expression, where each parameter is bound to a different element of
     100the returned tuple.
     101
     102        [int, int] argFunc();
     103        void parmFunc(int a, int b, int c, int d);
     104
     105        parmFunc(argFunc(), argFunc());
     106
     107        // Roughly equivilent to:
     108        [int, int] fst = argFunc();
     109        [int, int] snd = argFunc();
     110        parmFunc(fst.0, fst.1, snd.0, snd.1);
     111
     112There are few languages supporting multiple return-values as a standalone
     113feature (SETL). Go has multiple return-values but restricts their use in
     114matching arguments to parameters.
     115
     116        func argFunc() (int, int) {
     117            return 3, 7
    82118        }
    83         // Roughly equivilent to:
    84         void restructure() {
    85                 [int, int] fst = paramFunc();
    86                 [int, int] snd = paramFunc();
    87                 callFunc(fst.0, fst.1, snd.0, snd.1);
     119        func parmFunc( a int, b int ) {
     120             fmt.Println(a, b )
    88121        }
    89 
    90 This is the unique feature of Cforall tuples. There are a few languages with
    91 multiple return values, but they are usually are a stand alone feature.
     122        func main() {
     123             parmFunc2( argFunc() ); // arguments must match exactly with parameters
     124        }
    92125
    93126### Tuple Casts
    94127
    95128C-style casts can be used on tuples. These are usually conversion casts (casts
    96 that preform operations on the cast type, as opposed to reinterpreting the
     129that perform operations on the cast type, as opposed to reinterpreting the
    97130existing value).
    98131
     
    103136        ([int, char])x;
    104137
    105 This casts the first element type from a char to an int and drops the last
     138This casts the first element type of x from a char to an int and drops the last
    106139element. The second line can be replaced with the following code, which creates
    107 a new tuple by casting the kept elements of the old tuple:
     140a new tuple by directly casting the kept elements of the old tuple:
    108141
    109142        [(int)x.0, (char)x.1];
     
    111144Note, tuple casting is more restricted than the implicit tuple restructuring.
    112145It cannot do any restructuring beyond dropping the trailing elements of
    113 tuples. For example, you cannot cast `[int, [bool, char], int]` to be a
    114 `[int, bool, char, int]`.
     146tuples. For example,
     147
     148        int i; char c; bool b;
     149        [i, b, c, i] = [i, [b, c], i];
     150        [int, [bool, char], int] w;
     151        [i, b, c, i] = w;
     152        [i, b, c, i] = ([int, bool, char, int])w; // fails
     153        [i, b, c] = ([int, [bool, char]])w; // works
    115154
    116155### Polymorphic Tuple Parameters
     
    121160sequence of types.
    122161
    123         forall(T, Ts... | { T max(T, T); T max(Ts); })
     162        forall( T | { int ?>?( T, T ); } )
     163        T max( T v1, T v2 ) { return v1 > v2 ? v1 : v2; }  // base case
     164
     165        forall(T, Ts... | { T max(T, T); T max(Ts); })  // recursive case
    124166        T max(T arg, Ts args) {
    125167                return max(arg, max(args));
    126168        }
    127169
    128 This introduces a type name into scope. It is used as a type but because the
    129 tuple is flattened, the second assertion "T max(Ts);" matches types with
    130 multiple parameters, although it is used as a tuple function inside the
    131 function body. For example, in the three-argument case (all three of the
    132 same type), both assertions can match the same function. Then "Ts args"
    133 introduces args as a tuple, where it is passed to max.
     170This feature introduces a type name into scope (Ts). It is used as a type but
     171because the tuple is flattened, the second assertion "T max(Ts);" matches types
     172with multiple parameters (the `...`), although it is used as a tuple function
     173inside the function body (max(args)).
     174
     175The first non-recursive max function is the polymorphic base-case for the
     176recursion, i.e., find the maximum of two identically typed values with a
     177greater-than (>) operator.  The second recursive max function takes two
     178parameters, a T and a Ts tuple, handling all argument lengths greater than two.
     179The recursive function computes the maximum for the first argument and the
     180maximum value of the rest of the tuple.  The call of max with one argument is
     181the recursive call, where the tuple is converted into two arguments by taking
     182the first value (lisp car) from the tuple pack as the first argument
     183(flattening) and the remaining pack becomes the second argument (lisp cdr).
     184The recursion stops when the tuple is empty.  For example, max( 2, 3, 4 )
     185matches with the recursive function, which performs return max( 2, max( [3, 4]
     186) ) and one more step yields return max( 2, max( 3, 4 ) ), so the tuple is
     187empty.
     188
    134189
    135190Issues with the Current State
    136191-----------------------------
    137 There are a variety of problems with the current implementation which we
    138 would like to fix.
     192There are a variety of problems with the current implementation which need to
     193be fixed.
    139194
    140195### Tuples are not Objects
    141196
    142 Spoilers, this proposal actually takes them further away from being objects.
    143 But this illustrates why the current version is not as useful is it could be.
    144 
    145 Tuples do not have the lifetime operators (copy construction, copy assignment
    146 and destructor) and cannot be passed in as a bundle to polymorphic functions.
    147 The multi-assignment operation is not a single function and is not passed
    148 in as an assertion.
    149 
    150 This prevents tuples from being interwoven with regular polymorphic code.
     197Spoilers: this proposal actually takes them even further away from being
     198objects, but illustrates why the current version is not as useful is it could
     199be.
     200
     201Because of the fluid nature of tuples (flattening/structuring), routines like
     202constructions, destructor, or assignment do not make sense, e.g. this
     203constructor matches multiple a tuple types:
     204
     205        void ?{} ( [int, int, int] ? this );
     206        [int, [int, int]] x; // all match constructor type by flattening
     207        [int,  int, int]  y;
     208        [[int, int], int] z;
     209
     210as could a similarly typed destructor or assignment operator.  This prevents
     211tuples from being interwoven with regular polymorphic code.
    151212
    152213### Providing TType Arguments is Inconsistent
    153214
    154 The syntax for ttype arguments is slightly inconsistent. It hasn't come up
    155 much yet because you do not directly provide ttype polymorphic arguments to
     215The syntax for ttype arguments is slightly inconsistent. It has not come up
     216much yet, because you do not directly provide ttype polymorphic arguments to
    156217functions and there are very few existing use-cases for ttype structures.
    157218
    158 Passing arguments to a function inlines the arguments,
     219Passing arguments to a function inlines the arguments
    159220while passing them to a polymorphic type requires them to be
    160221enclosed in a tuple. Compare `function(x, y, z)` with `Type(A, [B, C])`.
    161222
    162 This did not come up previously as there was little reason to explicity
     223This did not come up previously as there was little reason to explicitly
    163224provide ttype arguments. They are implicit for functions and there is very
    164225little use case for a ttype on a struct or union.
     
    166227### Syntax Conflict
    167228
    168 The tuple syntax conflicts with designators and the new attribute syntax.
    169 These conflicts break C compatibility goals of Cforall. Designators have had
    170 to their syntax change and Cforall cannot parse the new attributes.
    171 
    172 Although most of this redesign is about the semantics of tuples, but an
    173 update to tuple syntax that removes these conflicts that would improve the
    174 compatibility of Cforall going forward (and also open up the new attribute
    175 syntax for cforall features).
     229The tuple syntax conflicts with designators and the new C++-style attribute
     230syntax.
     231
     232        struct S { int a[10]; } = { [2] = 3 }; // [2] looks like a tuple
     233        [[ unused ]] [[3, 4]]; // look ahead problem
     234
     235These conflicts break C compatibility goals of Cforall. Designators had to
     236their syntax change and Cforall cannot parse the new attributes.
     237
     238Although most of this redesign is about the semantics of tuples, but an update
     239to tuple syntax that removes these conflicts would improve the compatibility of
     240Cforall going forward (and also open up the new attribute syntax for cforall
     241features).
    176242
    177243Change in Model
     
    181247struct tuple is added to cover those cases.
    182248
    183 The existing tuples will be even more "unstructured" than they are now.
    184 Tuples are considered a sequence of types or typed entities. These packs are
    185 then unpacked into the surrounding context. Put differently, tuples are now
    186 flattened as much as possible, with some places (like parameter lists) being
    187 treated as an implicit tuple and the tuple being flattened into that.
    188 
    189 Structured tuples are now a separate feature, a structure called "tuple".
    190 These are polymorphic structures; an instance should act as a structure,
    191 except that it uses indices instead of field names. These structures shouldn't
    192 have to be used often, but fill in the use cases that unstructured tuples
    193 no longer support.
     249The new tuples is even more "unstructured" than before.  New tuples are
     250considered a sequence of types or typed entities. These packs are then unpacked
     251into the surrounding context. Put differently, tuples are now flattened as much
     252as possible, with some places (like parameter lists) being treated as an
     253implicit tuple and the tuple being flattened into that.
     254
     255Structured tuples are now a separate feature: a structure called "tuple".
     256These are polymorphic structures; an instance should act as a structure, except
     257its fields are accessed using indices instead of field names. Experience so far
     258is that structured tuples are not used often, but fill in the use cases that
     259unstructured tuples no longer support.
    194260
    195261Note that the underlying implementation might not actually look like this.
     
    201267### Structured Tuple Type
    202268
    203 There are still use cases for a structured tuple type. The issues in
    204 supporting both were because there was one feature trying to support both
    205 uses. Hence, it is added back in as its own feature.
    206 
    207 There should be a standard library or built-in type named `tuple`, it doesn't
    208 need a special syntax to write types or instances. The type definition might
    209 use some primitive support, but if supported as a regular type would look
    210 something like this:
     269There is a standard library or built-in type named `tuple`, it does not need a
     270special syntax to write types or instances. The type definition might need some
     271primitive support, but if supported as a regular type would look something like
     272this:
    211273
    212274        forall(Ts...)
    213275        struct tuple {
    214                 inline Ts all;
     276                inline Ts all; // inline all specified fields
    215277        };
    216278
    217 This will be constructed the same way as most types, a list initializer with
    218 each tuple argument, and the lifetime functions (copy construction, copy
    219 assignment and destruction) work the same. Field access works two ways, the
    220 first is accessing the all field, effectively converting the structured
    221 "struct" tuple into an unstructured tuple, the other is to use tuple indexing
    222 directly on the structure as if it was an unstructured tuple.
    223 
    224 (If inline doesn't work, just rename all to `get`. It does make things a bit
    225 longer but has no change in functionality. If the all access doesn't work,
    226 that is a bit more of a problem, tuple slicing might provide a work around.)
     279This type is constructed the same way as most types, a list initializer with
     280each tuple argument, and the lifetime functions (construction, assignment and
     281destruction) work the same. Field access works two ways, the first is accessing
     282the `all` field, effectively converting the structured tuple into an
     283unstructured tuple, the other is to use tuple indexing directly on the
     284structure as if it is an unstructured tuple.
     285
     286(If `inline` does not work, just rename all to `get`. It does make things a bit
     287longer but has no change in functionality. If the `all` access does not work,
     288that is more problematic, and tuple slicing might provide a work around.)
    227289
    228290### Type Qualifier Distribution
     
    233295the tuple.
    234296
    235 Previously `[int, bool] &` would mean a reference to a tuple of an integer
    236 and a boolean. Now it would be an alias for `[int &, bool &]`, a tuple of a
    237 reference to an integer and a reference to a boolean. This also applies to
    238 polymorphic tuple type packs `Ts &` in polymorphic functions.
    239 
    240 This allows to specify restrictions on types as you would with a single
    241 type variable. For example, this can help replace the special cased
    242 tuple operations, multi-assignment (N-to-N) and mass-assignment (1-to-N).
     297Previously `const [int, bool] &` would mean a const reference to a tuple of an
     298integer and a boolean. Now it means an alias for `[const int &, const bool &]`,
     299a tuple of a reference to a constant integer and a reference to a constant
     300boolean. This also applies to polymorphic tuple type packs `Ts &` in
     301polymorphic functions.
     302
     303This new approach can specify restrictions on tuple variables as for a single
     304type variable. For example, this approach can replace the special cased tuple
     305operations multi-assignment (N-to-N) and mass-assignment (1-to-N).
    243306
    244307        // Multi-Assignment
     
    269332### Type Packs
    270333
    271 This is not a new feature, but a reframing/extension of existing tuple tuple
    272 polymorphic parameters as polymorphic type packs. The `Vars...` syntax
    273 introduces a pack of types into scope. It can be used in many of the same
    274 ways as a tuple, but in some new ways to.
    275 
    276 The primary existing use remains; you can use a polymorphic pack in a
    277 parameter list, both as part of an assertion and in the signature of the
    278 main function. The difference is that this is not an enclosed tuple, but
    279 a series of types. The only effective difference this makes is it doesn't
    280 prefer to match another tuple/pack.
     334This approach is not a new feature, but a reframing/extension of existing tuple
     335tuple polymorphic parameters as polymorphic type packs. The old `Vars...`
     336syntax introduces a pack of types into scope. It can be used in much the same
     337way as a tuple, but in some new ways to.
     338
     339The primary existing use remains: to use a polymorphic pack in a parameter
     340list, both as part of an assertion and in the signature of the main
     341function. The difference is that this is not an enclosed tuple, but a series of
     342types. The only effective difference this makes is it does not prefer to match
     343another tuple/pack.
    281344
    282345This pattern continues to a parameter defined with a pack of types, which
     
    287350        void function(Params values);
    288351
    289 New use cases include declarations of members and variables. For example,
    290 the creation the structured tuple structure:
     352New use cases include declarations of members and variables. For example, the
     353creation of a structured tuple structure:
    291354
    292355        forall(Fields...)
     
    320383
    321384Declaring a tuple acts as a pack of variable declarations. When this is done
    322 with written out type (as opposed to a polymorphic parameter above), then the
     385with a written out type (as opposed to a polymorphic parameter above), then the
    323386elements of the tuple can be named.
    324387
     
    333396no named to access it.
    334397
     398PAB: I do understand the point of this.
     399
    335400### Tuple Casts
    336401
     
    344409The unstructured tuple cannot represent all the types that the previous
    345410semi-structured tuple could. These cases still exist in various ways,
    346 special in the internals of a polymorphic type, but in general should be
     411specifically in the internals of a polymorphic type, but in general should be
    347412considered in their reduced form.
    348413
     
    350415conflicts that currently exist.
    351416
    352 Nullary, or 0 element tuples, are equivlent to void, the type that carries
     417Nullary, or 0 element tuples, are equivalent to void, the type that carries
    353418no data, because they do not either. It should either be replaced with void
    354419or removed entirely when it appears in a larger sequence.
    355420
    356421        // For example, this function:
    357         forall(Ts...) Ts example(int first
     422        forall(Ts...) Ts example(int first, ????)
    358423        // With Ts = [], should not be treated as:
    359424        [] example(int first, [] middle, int last);
     
    364429is to say a single type in an unstructured tuple is a no-op.
    365430
    366 Lastly, nested tuples are always flattened into to form a one-deep tuple.
    367 This means that `[bool, [char, int], float]` is resolved as
    368 `[bool, char, int, float]`, with the internal structure of the tuple ignored.
    369 
    370 The flatten into a large sequence rule mentioned above, is actually just an
    371 application of this. Unstructured tuples can already be restructured, even
    372 at the top level of an function call. This can be expressed by considering
    373 the argument list as a tuple:
     431Lastly, nested tuples are always flattened to a one-depth tuple.  This means
     432that `[bool, [char, int], float]` is resolved as `[bool, char, int, float]`,
     433with the internal structure of the tuple ignored.
     434
     435The flatten into a large sequence rule mentioned above is actually just an
     436application of this. Unstructured tuples can already be restructured, even at
     437the top level of an function call. This can be expressed by considering the
     438argument list as a tuple:
    374439
    375440        call(false, ['a', -7], 3.14)
     
    385450(Disclaimer: this is a bit more impulsive, see end for notes.)
    386451
    387 This is an extension to tuple indexing. Currently, you may index single
    388 location of a tuple, extracting the element at that location. By extending
    389 the index expression to be a range we can grab a slice of the existing tuple
    390 as another smaller tuple.
    391 
    392         [int_x, char_y] = [int_a, char_b, double_c].(0+~=1)
    393 
    394 To get the new tuple, the range has to be constructed and traversed at
    395 compile time. The size of the range is the size of the result tuple, with
    396 each element in the result tuple decided by the matching element of the
    397 range, which gives the index of the original tuple to place there.
    398 The type of the indices may be and integral type, but all indices must be in
    399 range, otherwise it is a compile time error.
     452This is an extension to tuple indexing. Currently, only single location of a
     453tuple can be index, extracting the element at that location. By extending the
     454index expression to be a list-range a multiple sub-tuples can be extracted.
     455
     456        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].0~2,5~9~2
     457
     458produces the tuple
     459
     460        [0, 1, 2, 5, 7, 9]
     461
     462(Note the position and values are the same to simplify the example.) That is,
     463index the first 3 tuple elements, and then indexes elements 5 to 9 in steps of
     4642. Not all selections are possible with this mechanism (e.g., index the
     465Fibonacci elements), but it covers many cases.
     466
     467To get the new tuple, the range has to be constructed and traversed at compile
     468time. The size of the range is the size of the result tuple, with each element
     469in the result tuple decided by the matching element of the range, which gives
     470the index of the original tuple to place there.  The type of the indices may be
     471an integral type, but all indices must be in range, otherwise it is a compile
     472time error.
    400473
    401474In terms of the existing range loops, if you could write this dynamically, it
     
    410483as indexing the single value in the range.
    411484
    412 Some closing notes, this is dependent on generalised range expressions.
     485Some closing notes, this is dependent on generalized range expressions.
    413486The iterators proposal has a section on some new range types, this feature
    414487is intended to be built on that feature. Not simply reuse some of the syntax
     
    416489need to be improved.
    417490
     491PAB, I don't understand this last part as the index range is compile time not
     492runtime.
     493
    418494Implementation
    419495--------------
     
    421497
    422498### Structured Tuple Implementation
    423 Under the hood, unstructured tuples will probably just be implemented as
    424 structured tuples, with the restructuring code inserted wherever needed.
    425 In short, the base implementation should stay mostly the same.
     499
     500Under the hood, unstructured tuples are implemented as structured tuples, with
     501the restructuring code inserted wherever needed.  In short, the base
     502implementation should stay mostly the same.
     503
     504PAB: The current implementation does not use convert unstructured tuples to
     505structured tuples. Look at the code generated for
     506
     507        int x, y;
     508        [x, y] = 3;
     509        [x, y] = [y, x];
     510
    426511
    427512Actually inlining tuples can be done in some cases, it may even help with
     
    431516
    432517### AST Updates
     518
    433519The current AST cannot represent all the new features. Particularly, an
    434520object declaration cannot name elements of the tuple. To this end a new
     
    438524This would act much like a `FunctionDecl` except for tuples, narrowing the
    439525possible types, to `TupleType` instances instead of `FunctionType` instances,
    440 and storing some additional information, in this case the names of the
     526and storing some additional information. In this case, the names of the
    441527elements of the tuples.
     528
     529PAB: the following parses:
     530
     531        [int x, int y] foo( int p );
     532
     533and discussed by Till.
    442534
    443535(I'm not actually going to decide the implementation now, but some early
     
    446538
    447539### Field Packs
    448 Field packs in structures will probably have to be written out in full by
    449 the specialization pass. If they are not, it could have some negative effects
    450 on layout, causing a structure to take up extra space. It may be able to
    451 reuse some of the specialization code for the existing tuples.
     540
     541Field packs in structures probably have to be written out in full by the
     542specialization pass. If not, it could have some negative effects on layout,
     543causing a structure to take up extra space. It may be able to reuse some of the
     544specialization code for the existing tuples.
    452545
    453546Related Features in Other Languages
     
    461554There are many languages with structured tuples. Usually just called tuples,
    462555but they usually follow the same rules as a polymorphic anonymous structures,
    463 that is to say you provide N types to create a new N-arity tuple. They also
     556that is to say N types are provided to create a new N-arity tuple. They also
    464557usually have some special syntax to index the tuples, because there are no
    465 field names to use.
     558field names.
    466559
    467560#### Rust
     561
    468562Rust has the standard tuples as a primitive in the language. Each arity of
    469563tuple is a different polymorphic type.
     
    483577
    484578Some tuple features only apply up to 12-arity tuples.
    485 It is not directly stated, but I believe the difference is the more limited
    486 features are implemented in the standard library, for each arity of tuple.
     579It is not directly stated, but I believe the difference in the more limited
     580features are implemented in the standard library, one for each arity of tuple.
    487581
    488582-   https://doc.rust-lang.org/std/primitive.tuple.html
     
    490584-   https://doc.rust-lang.org/reference/expressions/tuple-expr.html
    491585
    492 #### C++
     586#### C++ tuple
     587
    493588Implemented as a template type defined in the standard library. No special
    494589language features exist to support this, due to the power of C++'s template
     
    500595types. This is the standard notation for template type instances.
    501596
    502 There is no special syntax for member access of a tuple. You have to use a
    503 template function, for example `std::get<0>( tuple )`.
     597There is no special syntax for member access of a tuple. A template function is
     598used, e.g., `std::get<0>( tuple )`.
    504599
    505600C++ also has structured binding, a kind of limited pattern matching. In a
     
    511606-   https://en.cppreference.com/w/cpp/language/structured_binding
    512607
    513 #### Haskell
    514 Haskell has a special syntax for tuples, but otherwise they are completely
    515 normal polymorphic types. Because of this, tuples have a maximum size.
    516 Haskell (98) supports tuples of up to 15 elements and the standard library
    517 has functions for tuples of up to 7 elements.
    518 
    519 The syntax for tuples is a comma separated list of elements. Either element
    520 types to create a tuple type, or element values to create a tuple value. The
    521 context decides which one we are looking for. Such as `(6, "six")` or
    522 `(Bool, Char, Int)`.
    523 
    524 You can also remove all the elements, getting an expression like "(,)" or
    525 "(,,,)", which can be then be used as a function, for a type or expression.
    526 
    527 Haskell supports pattern matching as the main way to extract values from a
    528 tuple, although helper functions "fst" and "snd" are provided for field
    529 access on two element tuples.
    530 
    531 Haskell does not have 0 or 1-element tuples. The nil type, written "()" for
    532 both type and value, is effectively the 0 element tuple. There is also a type
    533 called "Solo" that is a polymorphic structure with one field and is used as
    534 the 1-element tuple, but has regular Haskell data type syntax.
    535 
    536 -   https://www.haskell.org/onlinereport/basic.html
    537 
    538 #### OCaml
    539 OCaml only supports multi-element (2 or more) tuples. Tuple types are written
    540 as a '*' separated list of types, tuple values are written as ',' separated
    541 list of expressions. Pattern matching tuples is supported and uses the same
    542 syntax as values. Parenthesizing these lists is only needed for grouping.
    543 
    544 OCaml does not support 0 or 1 element tuples. It does however have the `unit`
    545 type which has one value, written `()`.
    546 
    547 -   https://ocaml.org/docs/basic-data-types#tuples
    548 
    549 #### Swift
    550 Swift has tuple types that use the basic parenthesized, comma
    551 separated list of types or values. It only supports 0 and 2 or more element
    552 tuples (the `Void` type is an alias for the empty tuple type).
    553 
    554 Swift also supports named tuples. Names can be added to before the tuple
    555 element, both for the tuple type and value. The syntax is a name followed by
    556 a colon, for example `(first: int, second: int)`. These names are a fixed
    557 part of the type, and can be used as part of field access notation (otherwise
    558 numbers are used in-place of field names `tuple.0` vs. `tuple.first`).
    559 
    560 -   https://docs.swift.org/swift-book/documentation/the-swift-programming-language/types/#Tuple-Type
    561 
    562 #### Python
    563 In Python tuples are immutable lists. Because they are dynamically typed
    564 there is only one tuple type `tuple`.
    565 
    566 It also has various named tuples. The first, namedtuple, just allows you to
    567 add a name the elements of the tuple. The second, NamedTuple, is actually a
    568 way of creating a typed record in a normally untyped language.
    569 
    570 -   https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range
    571 -   https://docs.python.org/3/library/collections.html#collections.namedtuple
    572 -   https://docs.python.org/3/library/typing.html#typing.NamedTuple
    573 
    574 #### LISP
    575 As LISP is dynamically typed, its cons data type is an untyped pair and is
    576 (perhaps infamously) the main constructor of all compound data types.
    577 The function `cons` takes two arguments and builds a pair. Functions `car`
    578 and `cdr` get the first and second elements of the pair.
    579 
    580 ### Packs
    581 
    582 Packs (or unstructured tuples) are a much less common feature. In fact, there
    583 might just be one language, C++, that supports packs. The most common use
    584 case for unstructured tuples is returning multiple values, so there is a
    585 comparison to languages that have that as a special feature.
    586 
    587 #### Go
    588 Go does not have built in tuple types, but it has multi-return syntax that
    589 looks like the tuple syntax of many other languages.
    590 
    591 ```
    592 func main() {
    593         i, j := returnIntInt()
    594         ...
    595 }
    596 
    597 func returnIntInt() (int, int) {
    598         return 12, 34
    599 }
    600 ```
    601 
    602 -   https://golangdocs.com/functions-in-golang
    603 -   https://go.dev/src/go/types/tuple.go
    604 
    605 #### Lua
    606 Lua is a scripting language, is dynamically typed and stack based. Although
    607 the stack usually only directly visible in the C-API, it does allow any
    608 function to return any number of values. Even in a single return, if the
    609 return expression
    610 
    611 ```
    612 local funcion f()
    613         return 12, 34
    614 end
    615 
    616 local i, j = f()
    617 ```
    618 
    619 #### C++
     608PAB: I do not understand the syntax `auto [first, second]`. Where does it come
     609from?
     610
     611#### C++ template
     612
    620613C++ templates can take various types of parameters, including parameter
    621614packs. These contain series of values. These are used in pack expansion,
     
    659652-   https://en.cppreference.com/w/cpp/language/parameter_pack
    660653-   https://en.cppreference.com/w/cpp/language/fold
     654
     655#### Haskell
     656
     657Haskell has a special syntax for tuples, but otherwise they are completely
     658normal polymorphic types. Because of this, tuples have a maximum size.
     659Haskell (98) supports tuples of up to 15 elements and the standard library
     660has functions for tuples of up to 7 elements.
     661
     662The syntax for tuples is a comma separated list of elements. Either element
     663types to create a tuple type, or element values to create a tuple value. The
     664context decides among them, such as `(6, "six")` or `(Bool, Char, Int)`.
     665
     666Also all the elements can be removed, getting an expression like "(,)" or
     667"(,,,)", which can be then be used as a function, for a type, or an expression.
     668
     669Haskell supports pattern matching as the main way to extract values from a
     670tuple, although helper functions "fst" and "snd" are provided for field
     671access on two element tuples.
     672
     673Haskell does not have 0 or 1-element tuples. The nil type, written "()" for
     674both type and value, is effectively the 0 element tuple. There is also a type
     675called "Solo" that is a polymorphic structure with one field and is used as
     676the 1-element tuple, but has regular Haskell data-type syntax.
     677
     678-   https://www.haskell.org/onlinereport/basic.html
     679
     680#### OCaml
     681
     682OCaml only supports multi-element (2 or more) tuples.  It does have the `unit`
     683type, which has one value, written `()`. Tuple types are written as a '*'
     684separated list of types, tuple values are written as ',' separated list of
     685expressions. Pattern matching tuples is supported and uses the same syntax as
     686values. Parenthesizing these lists is only needed for grouping.
     687
     688-   https://ocaml.org/docs/basic-data-types#tuples
     689
     690#### Swift
     691
     692Swift has tuple types that use the basic parenthesized, comma separated list of
     693types or values. It only supports 0 and 2 or more element tuples (the `Void`
     694type is an alias for the empty tuple type).
     695
     696Swift also supports named tuples. Names can be added before the tuple element,
     697both for the tuple type and value. The syntax is a name followed by a colon,
     698e.g., `(first: int, second: int)`. These names are a fixed part of the type,
     699and can be used as part of field access notation (otherwise numbers are used
     700in-place of field names `tuple.0` vs. `tuple.first`).
     701
     702-   https://docs.swift.org/swift-book/documentation/the-swift-programming-language/types/#Tuple-Type
     703
     704#### Python
     705
     706In Python tuples are immutable lists. Because they are dynamically typed,
     707there is only one tuple type `tuple`.
     708
     709It also has various named tuples. The first, namedtuple, allows naming the
     710elements of the tuple. The second, NamedTuple, is actually a way of creating a
     711typed record in a normally untyped language.
     712
     713-   https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range
     714-   https://docs.python.org/3/library/collections.html#collections.namedtuple
     715-   https://docs.python.org/3/library/typing.html#typing.NamedTuple
     716
     717#### LISP
     718As LISP is dynamically typed, its `cons` data type is an untyped pair and is
     719(perhaps infamously) the main constructor of all compound data types.  The
     720function `cons` takes two arguments and builds a pair. Functions `car` and
     721`cdr` get the first and second elements of the pair.
     722
     723### Packs
     724Packs (or unstructured tuples) are a much less common feature. In fact, there
     725might just be one language, C++, that supports packs. The most common use
     726case for unstructured tuples is returning multiple values, so there is a
     727comparison to languages that have that as a special feature.
     728
     729#### Go
     730Go does not have built in tuple types, but it has multi-return syntax that
     731looks like the tuple syntax of many other languages.
     732
     733```
     734func main() {
     735        i, j := returnIntInt()
     736        ...
     737}
     738
     739func returnIntInt() (int, int) {
     740        return 12, 34
     741}
     742```
     743
     744-   https://golangdocs.com/functions-in-golang
     745-   https://go.dev/src/go/types/tuple.go
     746
     747#### Lua
     748Lua is a scripting language that is dynamically typed and stack based. Although
     749the stack is usually only directly visible in the C-API, it does allow any
     750function to return any number of values, even a single return, in the return
     751expression
     752
     753```
     754local funcion f()
     755        return 12, 34
     756end
     757
     758local i, j = f()
     759```
Note: See TracChangeset for help on using the changeset viewer.