digitalmars.D.learn - How to unpack a tuple into multiple variables?
- Gary Chike (27/27) Feb 05 I hope all is well with everyone. I have come to an impasse. What
- TTK Ciar (14/14) Feb 05 I've been using AliasSeq for that (and aliasing it to "put" for
- Gary Chike (65/67) Feb 05 Very clever mnemonic TTK Ciar! :) After reviewing the various
- Sergey (14/17) Feb 05 ### TL;DR
- Gary Chike (3/5) Feb 05 Thank you Sergey! Still reading through the different 'solutions'
- Profunctor (35/36) Feb 05 In addition to the methods hitherto provided:
- Gary Chike (35/39) Feb 06 Thank you Profunctor! This gives me a lot to chew on. :)
- Menjanahary R. R. (35/38) Feb 07 Refactored it a bit to have a ready to run and easy to grasp code.
- Gary Chike (4/7) Feb 09 Thank you Menjanahary R.! I've saved the code to review and learn
- zjh (6/9) Feb 06 Officially, there should be an unpacking solution, like
- Gary Chike (3/8) Feb 06 Wouldn't that be nice? I hope a clean and terse
- ryuukk_ (3/11) Feb 07 There was a DIP for native tuples in D, hopefully we'll get it
- Gary Chike (7/9) Feb 07 I just wanted to define DIP for newbs since we're in a new users
I hope all is well with everyone. I have come to an impasse. What is the best way to unpack a tuple into multiple variables in D similar to this Python code? Thank you! ```python my_tuple = (2010, 10, 2, 11, 4, 0, 2, 41, 0) year, month, day, hour, minute, second, _, _, _ = my_tuple print(f"Year: {year}, Month: {month}, Day: {day}") print(f"Time: {hour}:{minute}:{second}") ``` My simple D code: ```d module tupleUnpack2; import std.stdio; import std.typecons : tuple; void main() { auto fruits = tuple("apple", "banana", "cherry"); writeln(fruits[0]); // "apple" writeln(fruits[1]); // "banana" writeln(fruits[2]); // "cherry" syntax) //or auto(a, b ,c) = fruits.expand; } ```
Feb 05
I've been using AliasSeq for that (and aliasing it to "put" for easier use): ```d import std.meta; alias put = AliasSeq; auto foo() { return tuple(1, 2, 3); } int main(string[] args) { int x, y, z; put!(x, y, z) = foo(); writeln(x, y, z); return 0; } ``` My mnemonic: "put" is "tup" backwards, and undoes what tuple does.
Feb 05
On Monday, 5 February 2024 at 21:21:33 UTC, TTK Ciar wrote:My mnemonic: "put" is "tup" backwards, and undoes what tuple does.Very clever mnemonic TTK Ciar! :) After reviewing the various solutions, the one I seem to gravitate towards is based on the one you presented, well, at least for now until a direct implementation is implemented (crossing my fingers!). I really appreciate everyone's help! :-) ```d import std.stdio; import std.meta; // AliasSeq! import std.typecons : tuple; void main() { // Create a tuple auto myTuple = tuple(10, "hello", [1, 2]); auto myTuple1 = tuple(42, "bye", [3, 4]); // Declare some variables to unpack into int myInt, myInt1; string myString, myString1; int[] myArray, myArray1; // Use AliasSeq to unpack the tuple AliasSeq!(myInt1, myString1, myArray1) = myTuple1; // Now the variables contain the tuple contents writeln(myInt1); // 42 writeln(myString1); // "bye" writeln(myArray1); // [3, 4] // using an alias to make more descriptive & possibly shorter alias unpack = AliasSeq; unpack!(myInt, myString, myArray) = myTuple; // Now the variables contain the tuple contents writeln(myInt); // 10 writeln(myString); // "hello" writeln(myArray); // [1, 2] // Can also unpack directly: writeln(myTuple[0]); // 10 } ``` I really didn't know AliasSeq!, so I had Claude2 explain it to me. Perhaps the explanation below will help other newbies: --- The `AliasSeq!(myInt, myString, myArray) = myTuple;` line is using AliasSeq to unpack the tuple into the individual variables. Here is what happens in more detail: 1. AliasSeq takes a list of symbols as template arguments - in this case the variables we declared before (myInt, myString, myArray) 2. It generates aliases to match each tuple element to the variables passed in. So the first alias will refer to myTuple[0], the second to myTuple[1], etc. 3. The assignment then takes the value on the right (myTuple) and copies each tuple element over to the variable the alias refers to. So for example, something like this is generated internally: ```d __alias1 = myTuple[0]; // alias for first element __alias2 = myTuple[1]; // alias for second element // Assign aliases to variables myInt = __alias1; myString = __alias2; myArray = __alias3; ``` The key thing AliasSeq does behind the scenes is generate those positional aliases to each tuple element, and match them up to the variables we want to unpack into. The assignment then copies the tuple elements over using the aliases.
Feb 05
On Monday, 5 February 2024 at 21:12:58 UTC, Gary Chike wrote:I hope all is well with everyone. I have come to an impasse. What is the best way to unpack a tuple into multiple variables in D similar to this Python code? Thank you!The direct implementation still not presented. But there are other ways to have similar functionality, as with AliasSeq example. * https://forum.dlang.org/post/rlrnhyaxcetaczjpdoem forum.dlang.org * https://forum.dlang.org/thread/xaejpgrhjzccnllcvxbl forum.dlang.org * https://forum.dlang.org/thread/kvvvidfkasezljfhkebm forum.dlang.org In those posts you can find other "solutions", Tuple DIP description and other useful ideas.
Feb 05
On Monday, 5 February 2024 at 21:30:15 UTC, Sergey wrote:In those posts you can find other "solutions", Tuple DIP description and other useful ideas.Thank you Sergey! Still reading through the different 'solutions' - very informative.
Feb 05
On Monday, 5 February 2024 at 21:12:58 UTC, Gary Chike wrote:[ ... ]In addition to the methods hitherto provided: ```d auto getUser() => tuple("John Doe", 32); // Name a Tuple's fields post hoc by copying the original's fields into a new Tuple. template named(names...) { auto named(T)(ref auto T t) if (names.length <= T.Types.length) => tuple!names(t.expand[0..names.length]); } { auto u = getUser().named!("name", "age"); writeln(u.name, " (", u.age, ")"); // John Doe (32) // You could also do this. If only `with` were an expression! with (getUser().named!("name", "age")) writeln(name, " (", age, ")"); // John Doe (32) } // Define variables corresponding to a Tuple's fields in the current scope, whose // identifiers are given by `names`. mixin template Unpack(alias t, names...) if (names.length <= t.Types.length) { static foreach (i, n; names) mixin("auto ", n, " = t[i];"); } { auto u = getUser(); mixin Unpack!(u, "name", "age"); writeln(name, " (", age, ")"); // John Doe (32) } ``` For either of these, one can "unpack" some or none of a Tuple's fields, and both can be modified to ignore any field to simulate `val (name, _, prof) = ("John Doe", 32, "Chemist")`.
Feb 05
On Tuesday, 6 February 2024 at 07:17:34 UTC, Profunctor wrote:On Monday, 5 February 2024 at 21:12:58 UTC, Gary Chike wrote:For either of these, one can "unpack" some or none of a Tuple's fields, and both can be modified to ignore any field to simulate `val (name, _, prof) = ("John Doe", 32, "Chemist")`.Thank you Profunctor! This gives me a lot to chew on. :) I had to ask [Anthropic Claude2](https://www.anthropic.com/news/claude-2) to help me understand what's going on. I placed the response below for other newbs to the D language: --- This is a very clever alternative approach to tuple unpacking in D suggested on the forums! Here is how it works: 1. Define a `named` template that takes a tuple and field names. It returns a new tuple with those field names applied to the original tuple's values. 2. Access the new named tuple naturally with dot notation ```d auto user = getUser(); auto namedUser = user.named!("name", "age"); writeln(namedUser.name); ``` Similarly, the `Unpack` mixin template defines variables in the current scope matching the tuple by name: ```d mixin Unpack!(user, "name", "age"); writeln(name); // accessed naturally now ``` So both work by naming the anonymous tuple fields, allowing clean access without indexes. The pros of this approach: - No AliasSeq, very straightforward - Custom field names - Clean syntax after setup The cons: - More verbose initial setup - Doesn't modify original tuple But overall it's an elegant way to indirectly add names to tuples in D for ergonomic access. Nice find!
Feb 06
On Wednesday, 7 February 2024 at 05:03:09 UTC, Gary Chike wrote:... But overall it's an elegant way to indirectly add names to tuples in D for ergonomic access. Nice find! ---Refactored it a bit to have a ready to run and easy to grasp code. Enjoy! ```d import std.stdio : writefln; import std.typecons: tuple; // Name a Tuple's fields post hoc by copying the original's fields into a new Tuple. template named(names...) { auto named(T)(ref auto T t) if (names.length <= T.Types.length) => tuple!names(t.expand[0..names.length]); } // Define variables corresponding to a Tuple's fields in the current scope, // whose identifiers are given by `names`. mixin template Unpack(alias t, names...) if (names.length <= t.Types.length) { static foreach (i, n; names) mixin("auto ", n, " = t[i];"); } void main() { auto getUser() => tuple("John Doe", 32); // auto u = getUser().named!("name", "age"); writefln("%s (%d)", u.name, u.age); // John Doe (32) // You could also do this. with (getUser().named!("name", "age")) writefln("%s (%d)", name, age); // John Doe (32) // mixin Unpack!(u, "name", "age"); writefln("%s (%d)", name, age); // John Doe (32) } ```
Feb 07
On Thursday, 8 February 2024 at 06:09:29 UTC, Menjanahary R. R. wrote:Refactored it a bit to have a ready to run and easy to grasp code. Enjoy!Thank you Menjanahary R.! I've saved the code to review and learn from! :>
Feb 09
On Monday, 5 February 2024 at 21:12:58 UTC, Gary Chike wrote:I hope all is well with everyone. I have come to an impasse. What is the best way to unpack a tuple into multiple variables in D similar to this Python code? Thank you!Officially, there should be an unpacking solution, like ```d //C++ auto[a,b,c]=tuple. ```
Feb 06
On Wednesday, 7 February 2024 at 01:17:33 UTC, zjh wrote:Officially, there should be an unpacking solution, like ```d //C++ auto[a,b,c]=tuple. ```Wouldn't that be nice? I hope a clean and terse direct-implementation comes in the near future. :)
Feb 06
On Wednesday, 7 February 2024 at 05:29:45 UTC, Gary Chike wrote:On Wednesday, 7 February 2024 at 01:17:33 UTC, zjh wrote:There was a DIP for native tuples in D, hopefully we'll get it soonOfficially, there should be an unpacking solution, like ```d //C++ auto[a,b,c]=tuple. ```Wouldn't that be nice? I hope a clean and terse direct-implementation comes in the near future. :)
Feb 07
On Wednesday, 7 February 2024 at 13:18:00 UTC, ryuukk_ wrote:There was a DIP for native tuples in D, hopefully we'll get it soonI just wanted to define DIP for newbs since we're in a new users thread. If they look it up, they will see: Dependency Inversion Principle, Dip programming language, etc.. In the D language context, DIP means: [D Improvement Proposal (DIP)](https://github.com/dlang/DIPs) which is a formal document that details a potential feature or enhancement to the language,
Feb 07