www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - let (x,y) = ...

reply "thedeemon" <dlang thedeemon.com> writes:
Creating tuples and returning them from functions is trivial in D:

auto getTuple() { return tuple("Bob", 42); }

but using them afterwards can be confusing and error prone

auto t = getTuple();
writeln("name is ", t[0], " age is ", t[1]);

I really missed the ML syntax to write

let (name, age) = getTuple();

Turns out this is ridiculously easy to implement in D, so here's 
my very tiny module for this:

https://bitbucket.org/infognition/dstuff/src (scroll down to 
letassign.d)

It allows you to write:

int x, y, z, age;
string name;

let (name, age) = getTuple();           // tuple
let (x,y,z) = argv[1..4].map!(to!int);  // lazy range
let (x,y,z) = [1,2,3];                  // array

SomeStruct s;
let (s.a, s.b) = tuple(3, "piggies");

If a range or array doesn't have enough elements, this thing will 
throw, and if it's not desired there's
let (x,y,z)[] = ...
variant that uses just the available data and keeps the rest 
variables unchanged.
Feb 18 2015
next sibling parent reply "ponce" <contact gam3sfrommars.fr> writes:
On Thursday, 19 February 2015 at 04:38:32 UTC, thedeemon wrote:
 Creating tuples and returning them from functions is trivial in 
 D:

 auto getTuple() { return tuple("Bob", 42); }

 but using them afterwards can be confusing and error prone

 auto t = getTuple();
 writeln("name is ", t[0], " age is ", t[1]);

 I really missed the ML syntax to write

 let (name, age) = getTuple();

 Turns out this is ridiculously easy to implement in D, so 
 here's my very tiny module for this:

 https://bitbucket.org/infognition/dstuff/src (scroll down to 
 letassign.d)

 It allows you to write:

 int x, y, z, age;
 string name;

 let (name, age) = getTuple();           // tuple
 let (x,y,z) = argv[1..4].map!(to!int);  // lazy range
 let (x,y,z) = [1,2,3];                  // array

 SomeStruct s;
 let (s.a, s.b) = tuple(3, "piggies");

 If a range or array doesn't have enough elements, this thing 
 will throw, and if it's not desired there's
 let (x,y,z)[] = ...
 variant that uses just the available data and keeps the rest 
 variables unchanged.
That's pretty neat! May I turn this code into a d-idioms? Name and link will be kept of course.
Feb 19 2015
parent "thedeemon" <dlang thedeemon.com> writes:
On Thursday, 19 February 2015 at 09:31:59 UTC, ponce wrote:

 That's pretty neat! May I turn this code into a d-idioms? Name 
 and link will be kept of course.
Sure, if you wish. There was just one person using this thing until today, so I dunno whether it deserves to be in that list.
Feb 19 2015
prev sibling next sibling parent reply "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Thursday, 19 February 2015 at 04:38:32 UTC, thedeemon wrote:
 let (name, age) = getTuple();
Maybe change the name to tie: http://www.cplusplus.com/reference/tuple/tie/ ?
Feb 19 2015
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Ola Fosheim Grøstad:

 Maybe change the name to tie:

 http://www.cplusplus.com/reference/tuple/tie/

 ?
I prefer "let", it's much more traditional and descriptive. C++ standard library is often a bad example to follow... Bye, bearophile
Feb 19 2015
parent reply "Kagamin" <spam here.lot> writes:
On Thursday, 19 February 2015 at 09:50:25 UTC, bearophile wrote:
 I prefer "let", it's much more traditional and descriptive. C++ 
 standard library is often a bad example to follow...
Doesn't "let" normally declare a new variable?
Feb 19 2015
next sibling parent "Kagamin" <spam here.lot> writes:
On Thursday, 19 February 2015 at 10:52:40 UTC, Kagamin wrote:
 On Thursday, 19 February 2015 at 09:50:25 UTC, bearophile wrote:
 I prefer "let", it's much more traditional and descriptive. 
 C++ standard library is often a bad example to follow...
Doesn't "let" normally declare a new variable?
http://ideone.com/iBzuiG - how "let" works in javascript.
Feb 19 2015
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Kagamin:

 Doesn't "let" normally declare a new variable?
You are right, yours is a valid point... So "tie" could be a better name after all. Bye, bearophile
Feb 19 2015
next sibling parent reply "Kagamin" <spam here.lot> writes:
Or even more obvious (VBA,TSQL):

set (x,y,z) = [1,2,3];
Feb 19 2015
parent "bearophile" <bearophileHUGS lycos.com> writes:
Kagamin:

 Or even more obvious (VBA,TSQL):

 set (x,y,z) = [1,2,3];
I prefer to use "set" as in Python, to define sets:
 s = set([1, 2, 3])
 2 in s
True Bye, bearophile
Feb 19 2015
prev sibling parent Rory McGuire via Digitalmars-d-announce writes:
"let" reads better either way I think.

"let this and that equal this other thing".

On Thu, Feb 19, 2015 at 2:00 PM, bearophile via Digitalmars-d-announce <
digitalmars-d-announce puremagic.com> wrote:

 Kagamin:

  Doesn't "let" normally declare a new variable?

 You are right, yours is a valid point... So "tie" could be a better name
 after all.

 Bye,
 bearophile
Feb 19 2015
prev sibling parent reply "thedeemon" <dlang thedeemon.com> writes:
On Thursday, 19 February 2015 at 09:46:13 UTC, Ola Fosheim 
Grøstad wrote:
 On Thursday, 19 February 2015 at 04:38:32 UTC, thedeemon wrote:
 let (name, age) = getTuple();
Maybe change the name to tie: http://www.cplusplus.com/reference/tuple/tie/ ?
"let" keyword, so personally I'd prefer continuing that tradition.
Feb 19 2015
parent Martin Nowak <code+news.digitalmars dawg.eu> writes:
On 02/19/2015 11:04 AM, thedeemon wrote:

 keyword, so personally I'd prefer continuing that tradition.
It's semantically different though because it doesn't declare the variables.
Feb 19 2015
prev sibling next sibling parent reply "Mengu" <mengukagan gmail.com> writes:
On Thursday, 19 February 2015 at 04:38:32 UTC, thedeemon wrote:
 Creating tuples and returning them from functions is trivial in 
 D:

 auto getTuple() { return tuple("Bob", 42); }

 but using them afterwards can be confusing and error prone

 auto t = getTuple();
 writeln("name is ", t[0], " age is ", t[1]);

 I really missed the ML syntax to write

 let (name, age) = getTuple();

 Turns out this is ridiculously easy to implement in D, so 
 here's my very tiny module for this:

 https://bitbucket.org/infognition/dstuff/src (scroll down to 
 letassign.d)

 It allows you to write:

 int x, y, z, age;
 string name;

 let (name, age) = getTuple();           // tuple
 let (x,y,z) = argv[1..4].map!(to!int);  // lazy range
 let (x,y,z) = [1,2,3];                  // array

 SomeStruct s;
 let (s.a, s.b) = tuple(3, "piggies");

 If a range or array doesn't have enough elements, this thing 
 will throw, and if it's not desired there's
 let (x,y,z)[] = ...
 variant that uses just the available data and keeps the rest 
 variables unchanged.
that's a great example to show d's strength. thank you.
Feb 19 2015
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Mengu:

 that's a great example to show d's strength. thank you.
It's also a great way to show what's missing in D syntax. Bye, bearophile
Feb 19 2015
parent Martin Nowak <code+news.digitalmars dawg.eu> writes:
On 02/19/2015 12:59 PM, bearophile wrote:
 It's also a great way to show what's missing in D syntax.
True that.
Feb 19 2015
prev sibling next sibling parent reply Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On 19/02/2015 04:38, thedeemon wrote:
 int x, y, z, age;
 string name;

 let (name, age) = getTuple();           // tuple
 let (x,y,z) = argv[1..4].map!(to!int);  // lazy range
 let (x,y,z) = [1,2,3];                  // array

 SomeStruct s;
 let (s.a, s.b) = tuple(3, "piggies");
Alternatively std.typetuple.TypeTuple can be used instead of let: http://forum.dlang.org/post/op.wa4vn6lgsqugbd localhost
 If a range or array doesn't have enough elements, this thing will throw,
 and if it's not desired there's
 let (x,y,z)[] = ...
 variant that uses just the available data and keeps the rest variables
 unchanged.
With these functions you can skip certain elements: http://forum.dlang.org/post/jjnmh2$27o5$1 digitalmars.com
Feb 19 2015
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 19 February 2015 at 13:52:29 UTC, Nick Treleaven 
wrote:
 On 19/02/2015 04:38, thedeemon wrote:
 int x, y, z, age;
 string name;

 let (name, age) = getTuple();           // tuple
 let (x,y,z) = argv[1..4].map!(to!int);  // lazy range
 let (x,y,z) = [1,2,3];                  // array

 SomeStruct s;
 let (s.a, s.b) = tuple(3, "piggies");
Alternatively std.typetuple.TypeTuple can be used instead of let
not for ranges and arrays though
Feb 19 2015
parent reply Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On 19/02/2015 14:59, John Colvin wrote:
 On Thursday, 19 February 2015 at 13:52:29 UTC, Nick Treleaven wrote:
 On 19/02/2015 04:38, thedeemon wrote:
 int x, y, z, age;
 string name;

 let (name, age) = getTuple();           // tuple
 let (x,y,z) = argv[1..4].map!(to!int);  // lazy range
 let (x,y,z) = [1,2,3];                  // array

 SomeStruct s;
 let (s.a, s.b) = tuple(3, "piggies");
Alternatively std.typetuple.TypeTuple can be used instead of let
not for ranges and arrays though
Yes, but `tuple` overloads could be added for those. Tuple already supports construction from a static array: int a, b; TypeTuple!(a, b) = Tuple!(int, int)([3, 4]);
Feb 19 2015
parent reply Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On 19/02/2015 17:00, Nick Treleaven wrote:
 Alternatively std.typetuple.TypeTuple can be used instead of let
not for ranges and arrays though
Yes, but `tuple` overloads could be added for those.
Or not - the length isn't known at compile-time.
 Tuple already
 supports construction from a static array:

      int a, b;
      TypeTuple!(a, b) = Tuple!(int, int)([3, 4]);
I'm hacking std.typecons so this does work: TypeTuple!(a, b) = [4, 5].tuple;
Feb 19 2015
parent Leandro Lucarella <luca llucax.com.ar> writes:
Nick Treleaven, el 19 de February a las 17:25 me escribiste:
 On 19/02/2015 17:00, Nick Treleaven wrote:
Alternatively std.typetuple.TypeTuple can be used instead of let
not for ranges and arrays though
Yes, but `tuple` overloads could be added for those.
Or not - the length isn't known at compile-time.
Tuple already
supports construction from a static array:

     int a, b;
     TypeTuple!(a, b) = Tuple!(int, int)([3, 4]);
I'm hacking std.typecons so this does work: TypeTuple!(a, b) = [4, 5].tuple;
Why not to integrate this "let" to phobos, that seems to be a lot of syntactic noise compared to : let (a, b) = [4, 5]; -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- You can try the best you can If you try the best you can The best you can is good enough
Feb 24 2015
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2015-02-19 05:38, thedeemon wrote:
 Creating tuples and returning them from functions is trivial in D:

 auto getTuple() { return tuple("Bob", 42); }

 but using them afterwards can be confusing and error prone

 auto t = getTuple();
 writeln("name is ", t[0], " age is ", t[1]);

 I really missed the ML syntax to write

 let (name, age) = getTuple();
Didn't someone create a pull request for something like: auto(name, age) = getTuple(); Or was it a DIP? -- /Jacob Carlborg
Feb 20 2015
next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 20 February 2015 at 09:12:26 UTC, Jacob Carlborg wrote:
 On 2015-02-19 05:38, thedeemon wrote:
 Creating tuples and returning them from functions is trivial 
 in D:

 auto getTuple() { return tuple("Bob", 42); }

 but using them afterwards can be confusing and error prone

 auto t = getTuple();
 writeln("name is ", t[0], " age is ", t[1]);

 I really missed the ML syntax to write

 let (name, age) = getTuple();
Didn't someone create a pull request for something like: auto(name, age) = getTuple(); Or was it a DIP?
This one, by Kenji? http://wiki.dlang.org/DIP32
Feb 20 2015
prev sibling parent karabuta <karabutaworld gmail.com> writes:
On Friday, 20 February 2015 at 09:12:26 UTC, Jacob Carlborg wrote:
 On 2015-02-19 05:38, thedeemon wrote:
 Creating tuples and returning them from functions is trivial 
 in D:

 auto getTuple() { return tuple("Bob", 42); }

 but using them afterwards can be confusing and error prone

 auto t = getTuple();
 writeln("name is ", t[0], " age is ", t[1]);

 I really missed the ML syntax to write

 let (name, age) = getTuple();
Didn't someone create a pull request for something like: auto(name, age) = getTuple(); Or was it a DIP?
Waw! auto(name, age) = getTuple(); looks better :)
Nov 23 2015
prev sibling parent reply visitor <visitor gmail.com> writes:
hello,
Learning here, hope i don"t excavate unnecessarily an old post

What is the reason for using pointers (alias pointerOf(T) = T*  
etc...)
it works without ! what am i missing ?

Thanks
Nov 22 2015
parent reply thedeemon <dlang thedeemon.com> writes:
On Sunday, 22 November 2015 at 18:47:34 UTC, visitor wrote:

 What is the reason for using pointers (alias pointerOf(T) = T*  
 etc...)
 it works without ! what am i missing ?
What and how exactly works without? My original solution remembers in the constructor addresses of variables to fill, then does the filling in opAssign operator, so I needed a way to store the references and used pointers for that.
Nov 23 2015
parent reply visitor <visitor gmail.com> writes:
On Monday, 23 November 2015 at 10:28:53 UTC, thedeemon wrote:
 On Sunday, 22 November 2015 at 18:47:34 UTC, visitor wrote:

 What is the reason for using pointers (alias pointerOf(T) = T*
  etc...)
 it works without ! what am i missing ?
What and how exactly works without? My original solution remembers in the constructor addresses of variables to fill, then does the filling in opAssign operator, so I needed a way to store the references and used pointers for that.
yes, but you are using ref : "auto let(Ts...)(ref Ts vars)" so vars are changed, no need to store anything, no? i was wondering if there is some subtleties or efficiency reasons for using pointers this work fine with your unittest : auto let(Ts...)(ref Ts vars) { struct Let { void opAssign( Tuple!Ts xs ) { foreach(i, t; Ts) vars[i] = xs[i]; } static if (sameTypes!Ts) { import std.conv : text; void opAssign(Ts[0][] xs) { // redundant but more effective enforce(xs.length == Ts.length, "let (...) = ...: array must have " ~ Ts.length.text ~ " elements."); foreach(i, t; Ts) vars[i] = xs[i]; } void opAssign(R)(R xs) if (isInputRange!R && is(ElementType!R == Ts[0])) { static if (hasLength!R) { enforce(xs.length >= Ts.length, "let (...) = ...: range must have at least " ~ Ts.length.text ~ " elements."); } foreach(i, t; Ts) { enforce(!xs.empty, "let (...) = ...: range must have at least " ~ Ts.length.text ~ " elements."); vars[i] = xs.front; xs.popFront(); } } void opIndexAssign(R)(R xs) if (isInputRange!R && is(ElementType!R == Ts[0])) { foreach(i, t; Ts) { if(xs.empty) return; vars[i] = xs.front; xs.popFront(); } } } } return Let(); }
Nov 23 2015
next sibling parent reply thedeemon <dlang thedeemon.com> writes:
On Monday, 23 November 2015 at 11:12:33 UTC, visitor wrote:

 My original solution remembers in the constructor addresses of 
 variables to fill, then does the filling in opAssign operator, 
 so I needed a way to store the references and used pointers 
 for that.
yes, but you are using ref : "auto let(Ts...)(ref Ts vars)" so vars are changed, no need to store anything, no? i was wondering if there is some subtleties or efficiency reasons for using pointers
Thanks for the code! Yep, this way it works too, by capturing input vars in a closure. So the main difference is that your variant allocates GC memory while original variant does not allocate anything in the heap (only on stack).
Nov 23 2015
parent visitor <visitor gmail.com> writes:
On Monday, 23 November 2015 at 14:54:15 UTC, thedeemon wrote:
 Yep, this way it works too, by capturing input vars in a 
 closure. So the main difference is that your variant allocates 
 GC memory while original variant does not allocate anything in 
 the heap (only on stack).
Thanks for clarifying :-) hope this will end into the language ! great work.
Nov 23 2015
prev sibling parent reply Andrea Fontana <nospam example.com> writes:
On Monday, 23 November 2015 at 11:12:33 UTC, visitor wrote:
 this work fine with your unittest :
 auto let(Ts...)(ref Ts vars) {
     struct Let
     {
         void opAssign( Tuple!Ts xs ) {
             foreach(i, t; Ts)
                 vars[i] = xs[i];
         }

         static if (sameTypes!Ts) {
             import std.conv : text;
             void opAssign(Ts[0][] xs) { // redundant but more 
 effective
                 enforce(xs.length == Ts.length, "let (...) = 
 ...: array must have " ~ Ts.length.text ~ " elements.");
                 foreach(i, t; Ts)
                     vars[i] = xs[i];
             }

             void opAssign(R)(R xs) if (isInputRange!R && 
 is(ElementType!R == Ts[0])) {
                 static if (hasLength!R) {					
                     enforce(xs.length >= Ts.length, "let (...) 
 = ...: range must have at least " ~ Ts.length.text ~ " 
 elements.");
                 }
                 foreach(i, t; Ts) {
                     enforce(!xs.empty, "let (...) = ...: range 
 must have at least " ~ Ts.length.text ~ " elements.");
                     vars[i] = xs.front;
                     xs.popFront();
                 }
             }

             void opIndexAssign(R)(R xs) if (isInputRange!R && 
 is(ElementType!R == Ts[0])) {
                 foreach(i, t; Ts) {
                     if(xs.empty) return;
                     vars[i] = xs.front;
                     xs.popFront();
                 }
             }
         }
     }
     return Let();
 }
Nice. Why first enforce is "==" rather than ">=" ? This prevents something like: auto arr = ["hello", "world", "!"]; string hello; string world; let (hello, world) = arr;
Nov 23 2015
next sibling parent visitor <visitor gmail.com> writes:
On Monday, 23 November 2015 at 16:58:43 UTC, Andrea Fontana wrote:
 Nice. Why first enforce is "==" rather than ">=" ? This 
 prevents something like:

 auto arr = ["hello", "world", "!"];
 string hello;
 string world;

 let (hello, world) = arr;
note that this is thedeemon's work ! (sorry couldn't resist) anyway, yes indeed !
Nov 23 2015
prev sibling parent reply thedeemon <dlang thedeemon.com> writes:
On Monday, 23 November 2015 at 16:58:43 UTC, Andrea Fontana wrote:
 Nice. Why first enforce is "==" rather than ">=" ? This 
 prevents something like:
 auto arr = ["hello", "world", "!"];
 let (hello, world) = arr;
The very first post of this thread should have answered this. Two options are available: one requires exact number of elements and so catches more errors, the other requires there to be "enough" data, for cases where you want that. To get behavior you described just use let (hello, world)[] = arr;
Nov 23 2015
parent reply visitor <visitor gmail.com> writes:
On Monday, 23 November 2015 at 18:38:45 UTC, thedeemon wrote:
 let (hello, world)[] = arr;
i think what Andrea Fontana is talking is the other way around your solution allows let (hello, world)[] = ["hi"]; Andrea Fontana(s allows let (hello, world) = ["hi", "there", "!"];
Nov 23 2015
parent reply visitor <visitor gmail.com> writes:
On Monday, 23 November 2015 at 20:10:49 UTC, visitor wrote:
 Andrea Fontana(s allows
 let (hello, world) = ["hi", "there", "!"];
of course in your version let (hello, world)[] = ["hi", "there", "!"] works but for consistency with range, i think Fontana's note is relevant
Nov 23 2015
parent reply thedeemon <dlang thedeemon.com> writes:
On Monday, 23 November 2015 at 22:32:57 UTC, visitor wrote:
 On Monday, 23 November 2015 at 20:10:49 UTC, visitor wrote:
 Andrea Fontana(s allows
 let (hello, world) = ["hi", "there", "!"];
of course in your version let (hello, world)[] = ["hi", "there", "!"] works but for consistency with range, i think Fontana's note is relevant
Well, I believe it's a matter of taste. By allowing different number of elements there you allow more errors to sink in without gaining anything at all. You lose the choice between strict and loose operators, erase the difference. It's not the "consistency" I would like to have.
Nov 23 2015
parent visitor <visitor gmail.com> writes:
On Tuesday, 24 November 2015 at 05:45:55 UTC, thedeemon wrote:
 Well, I believe it's a matter of taste. By allowing different 
 number of elements there you allow more errors to sink in 
 without gaining anything at all. You lose the choice between 
 strict and loose operators, erase the difference. It's not the 
 "consistency" I would like to have.
ok, always curious about strategic choices, thanks :-)
Nov 24 2015