Thread overview
idea for Native D Tuple Syntax, packing and unpacking
June 23
// idea for Native D Tuple Syntax, packing and unpacking
// (for simplicty of compiler internals and identifiable language construct)
/+
... for your kind consideration and peaceful inspiration.
--->> from an IT veteran of 43 years and 30+ programming languages
+/

// #() = #();
#(a, b, c, d) = #(1, 'strval', [1,2,3], true);

// myTuple = #(values); #(values) = myTuple;
auto y = #(1, 'strval', [1,2,3], true);
#(a, b, c, d) = y;

// Optional unpack assignment
#(a) =  #(1, 'strval', [1,2,3], true); // a = 1
#(, b, , d) =  #(1, 'strval', [1,2,3], true); // b = 'strval, d = true

// Embedded Tuple Syntax
#(a, b, c, d, eee) = #(1, 'strval', [1,2,3], true, #(5, 'str2'));
#(f, g) = eee; // f = 5, g = 'str2'

June 24

On Sunday, 23 June 2024 at 04:10:35 UTC, Kindly Doright wrote:

>

Idea for Native D Tuple Syntax, packing and unpacking (for simplicty of compiler internals and identifiable language construct)

// #() = #();
#(a, b, c, d) = #(1, 'strval', [1,2,3], true);

// myTuple = #(values); #(values) = myTuple;
auto y = #(1, 'strval', [1,2,3], true);
#(a, b, c, d) = y;

Makes sense so far.

>
// Optional unpack assignment
#(a) =  #(1, 'strval', [1,2,3], true); // a = 1

Hard no to this one, but can be fixed easily:

#(a, ...) = #(1, 'strval', [1,2,3], true); // a = 1
>
#(, b, , d) =  #(1, 'strval', [1,2,3], true); // b = 'strval, d = true

Making the absence of something meaningful is generally not wise. I’d rather have _ have special meaning in matching to mean discard.

Years ago, I implemented tie[] using opIndex and opIndexAssign which used typeof(null) as a discard and you can use enum typeof(null) _ to just use _ for discarding. A cut-down proof-of-concept implementation is below.

What my implementation can’t do because it would require first-class language support is tuple-rest unpacking. It also can’t declare variables. Borrowing your syntax:

#(_, b, _, d) = #(1, "strval", [1,2,3], true); // b = 'strval, d = true
>
// Embedded Tuple Syntax
#(a, b, c, d, eee) = #(1, 'strval', [1,2,3], true, #(5, 'str2'));
#(f, g) = eee; // f = 5, g = 'str2'

What about:

#(a, b, c, d, #(e, f)) = #(1, 'strval', [1,2,3], true, #(5, 'str2'));

What about:

#(a, b, cd..., e, f) = #(1, "strval", [1,2,3], true, 5, "str2");
#(c, d) = cd; // c == [1,2,3], d == true

If it were up to me, I’d use […]t syntax for tuples and […]s for static arrays.

Unpacking would be:

[x, y]t = rhs; // for `x` and `y` already defined
auto [x, y]t = rhs; // Declares `x` and `y`.
[x, auto y]t = rhs; // for `x` already defined; declares `y`.

// sets `x`, `y`, and `zs` where `zs` must be a type such that `zs[0]`, …, `zs[n-1]` work, where `n` is `rhs.length - 2` if it is already declared:
[x, y, zs...]t = rhs; // for `x`, `y`, and `zs` already defined
auto [x, y, zs...]t = rhs; // / Declares `x`, `y`, and `zs`.
[auto x, y, auto zs...]t = rhs; // for `y` already defined; declares `x` and `zs`.

Static arrays would also work, but require/produce same-type values, possibly using common-type inference.


struct tie
{
    import core.lifetime;
    import std.typecons : tuple;
    static opIndex(Ts...)(auto ref Ts args) => tuple(forward!args);

    alias opIndexAssign = opIndexOpAssign!"";
    template opIndexOpAssign(string op)
    {
        static void opIndexOpAssign(R, Ts...)(R rhs, auto ref Ts lhs)
        {
            static foreach (i; 0 .. Ts.length)
            {
                static if (!is(Ts[i] : const(typeof(null))))
                {
                    static assert(__traits(isRef, lhs[i]));
            		mixin("lhs[i] ", op,"= rhs[i];");
                }
            }
        }
    }
}

void main()
{
    int x;
    double y;
    tie[x, y] = tie[2, 3.14];
    assert(x == 2);
    assert(y == 3.14);
    tie[x, y] += tie[3, 2.71];
    assert(x == 5);
    assert(y == 3.14 + 2.71);
    int z;
    enum _ = null;
    tie[z, _] = tie[x, y];
    assert(z == x);
}
June 25

On Sunday, 23 June 2024 at 04:10:35 UTC, Kindly Doright wrote:

>

// idea for Native D Tuple Syntax, packing and unpacking

// idea for Native D Tuple Syntax, revision A.1
// (strictly for packing and unpacking a single-layer grouping of items)

/+
Purpose: to pass or return a group of unsimilar items
(without the need for designing and implementing a data structure)

GOAL: to reduce cognitive load, to simplify coding effort

Other: simplify compiler implementation and provide a distinct language construct
Concept Synonyms: pack/unpack, group/ungroup, marshall/unmarshall
+/

// Pack & unpack a single-layer grouping
// #() = #();
#(a, b, c, d) = #(1, 'strval', [1,2,3], true);

// myTuple = #(values); #(values) = myTuple;
auto y = #(1, 'strval', [1,2,3], true);
#(a, b, c, d) = y;

// As a single-layer unpack, auto can be specified
auto #(a, b, c, d) = #(1, 'strval', [1,2,3], true);
#(a, b, auto c, d) = #(1, 'strval', [1,2,3], true);
// Optional unpack: skip value assignment (D-style)
#(a, ...) =  #(1, 'strval', [1,2,3], true); // a = 1
#(_, b, _, d) =  #(1, 'strval', [1,2,3], true); // b = 'strval', d = true
auto #(_, b, _, d) =  #(1, 'strval', [1,2,3], true);

#(_, b, ...) =  #(1, 'strval', [1,2,3], true); // b = 'strval'
#(_, auto b, ...) =  #(1, 'strval', [1,2,3], true);

// **Invalid Syntax** for optional unpack assignment
// reason: unnecessary complexity
#(a, ..., d) =  #(1, 'strval', [1,2,3], true);
// **Invalid Syntax** embedded pack Tuple Syntax (i.e. multi-layer)
// reason: multi-layer pack --- #(5, 'str2')
#(a, b, c, d, eee) = #(1, 'strval', [1,2,3], true, #(5, 'str2')); // has *multi*-layer pack

// Valid Syntax (single-layer pack)
auto myTuple = #(5, 'str2');
#(a, b, c, d, eee) = #(1, 'strval', [1,2,3], true, myTuple); // single-layer
#(f, g) = eee; // f = 5, g = 'str2'

// **Invalid Syntax** embedded unpack Tuple Syntax
// reason: multi-layer unpack --- #(f, g))
auto myTuple = #(5, 'str2');
#(a, b, c, d, #(f, g)) = #(1, 'strval', [1,2,3], true, myTuple); // has *multi*-layer unpack

// **Invalid Syntax** misuse of pack Tuple Syntax
// reason: the packing syntax does not function as a Tuple variable
// (the pack syntax does not function as an intermediate Tuple value; it is strictly for assignment)
auto y = #(1, 'strval') + #([1,2,3], true); // **misuse of syntax**
y += #(5, 'str2'); // **misuse of syntax**
foreach (int item; #(1, 'strval')) { writeln(item); } // **misuse of syntax**

// Valid use of Packing Syntax
#(a, b) = #(1, 'strval');
auto y = #(1, 'strval');
return #(1, 'strval');

// **Invalid Syntax** misuse of pack Tuple Syntax
// reason: use of Packing Syntax as a function parameter
myfuncCall('staticParam', #(1, 'strval'));

// Valid use
auto y=#(1, 'strval');
myfuncCall('staticParam', y);

June 25
On Sunday, 23 June 2024 at 04:10:35 UTC, Kindly Doright wrote:
> // idea for Native D Tuple Syntax, packing and unpacking

Just to mention, there is a DIP draft from 2018:
https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
June 26

On Tuesday, 25 June 2024 at 10:40:18 UTC, Kindly Doright wrote:

>

On Sunday, 23 June 2024 at 04:10:35 UTC, Kindly Doright wrote:

>

// idea for Native D Tuple Syntax, packing and unpacking

Hi Kindly,

it seems your proposed syntax bears similarity to smalltalk.
Are you a smalltalker by any chance?

June 26

On Wednesday, 26 June 2024 at 09:04:28 UTC, Stefan Koch wrote:

>

On Tuesday, 25 June 2024 at 10:40:18 UTC, Kindly Doright wrote:

>

On Sunday, 23 June 2024 at 04:10:35 UTC, Kindly Doright wrote:

>

// idea for Native D Tuple Syntax, packing and unpacking

Hi Kindly,

it seems your proposed syntax bears similarity to smalltalk.
Are you a smalltalker by any chance?

I've not used smalltalk. I have been watching many of the D language videos and D conference videos.

I saw a recent video describing the prolonged effort to bring tuple unpacking to the D language (what syntax to use and its intended purpose). In that video, Walter approved (via chat) the use of parenthesis syntax for tuple unpacking. And I had already observed the pros and cons expressed earlier online of using other D syntax (arrays, scopes, etc).

With my prior use of a vast array of languages and DSLs, I immediately recognized that the use of parenthesis (the right choice of syntax pair for D, btw) and its further context overloading...
...was going to be a compiler context nightmare and an extensive maintenance issue for years. (Not to mention the increased obscurity in glancing at D code and discern what was occurring.)

The next morning, I awoke suddenly at 4:30am with this syntax in mind "#() = #()". It was a distinct language construct, clear of purpose, and reasonably simple to implement and maintain in a compiler. And yet, due to online communities eschewing outside ideas, I mentally tabled it.

By 11:00am, the concept kept niggling at me (almost harassing me). I sighed as I relented, and I took the deep dive to assess whether the syntax was actually compatible and viable with D (across the entire language scope). I also considered a few syntax variations, but they proved to be incompatible or syntactically misleading.

By 1:30pm, I had proven to myself that "#()" packing and unpacking was viable for tuples.

By 2:00pm, I again shelved the whole concept and went back to my own tasks.

Around 5:00pm, I became convicted of conscience that I should share the idea. And yet, modern online communities... so, again I replied to self, "No, thank you kindly."

Late evening arrives and I'm awakened by conscience (a conviction of kindness for this generation of developers, and especially D). So I search the D forums for the most appropriate place. Lo and behold, "DIP Ideas." I prepared a succinct example, something to concisely share, and then to be quietly done.

I was so deeply pleased that I didn't have to create an online account, and that I could share politely and anonymously. T h a n k - y o u for that!


The current '2018' draft for tuple unpacking is highly complex, solving for every possible generic use case of the syntax.

The concept that I offer as an inspiration... is simplicity of scope and implementation, and an ease of reading and writing.

Anything that reduces cognitive load is considered an Advanced Feature in most industries. And packing and unpacking tuples solves an immediate coding need... when already undertaking a complex task.
(that is, I suddenly have the need to return unsimilar values from a function or process, or to access only a portion of a result set. ALL WITHOUT creating an ad-hoc struct to ferry them about.)

Quirin Schroll's response revealed to me my implementation flaw of a multi-layer pack/unpack. In short, "#()" syntactically should never be allowed inside of other parentheses.

As an inspirational idea, be inspired to explore it... and then utilize and adapt whatever beneficially good portions of it there may be.

Thank you kindly,
-- Kindly


Stefan,
Thank you for saying hello.
-- Kindly

June 26

On Wednesday, 26 June 2024 at 11:08:49 UTC, Kindly Doright wrote:

>

...
By 1:30pm, I had proven to myself that "#()" packing and unpacking was viable for tuples.


I also considered that "#[ ]" might be useful for unpacking arrays. Now, after reviewing the particular '2018' draft again, I observed that its "()" unpacking syntax was also being used generically to unpack arrays.

Therefore, I present the idea of using "#()" for tuple unpacking syntax and "#[ ]" for array unpacking syntax.

(( and let the compiler maintainers rejoice! (if applicable) ))