www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - lazy variables

reply aliak <something something.com> writes:
Hi,

Is there any notion of lazy vars in D (i see that there're 
parameters)?

i.e:

struct S {
   //...
   int y;
   //...
}

lazy S x = () {
     // do some heavy stuff
}();

if (condition) {
   func(x.y); // heavy stuff evaluated here
}

Cheers,
- Ali
Oct 17 2018
next sibling parent Chris Katko <ckatko gmail.com> writes:
On Wednesday, 17 October 2018 at 07:32:37 UTC, aliak wrote:
 Hi,

 Is there any notion of lazy vars in D (i see that there're 
 parameters)?

 i.e:

 struct S {
   //...
   int y;
   //...
 }

 lazy S x = () {
     // do some heavy stuff
 }();

 if (condition) {
   func(x.y); // heavy stuff evaluated here
 }

 Cheers,
 - Ali
This might be helpful: https://dlang.org/articles/lazy-evaluation.html
Oct 17 2018
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/17/2018 12:32 AM, aliak wrote:
 Hi,
 
 Is there any notion of lazy vars in D (i see that there're parameters)?
 
 i.e:
 
 struct S {
    //...
    int y;
    //...
 }
 
 lazy S x = () {
      // do some heavy stuff
 }();
 
 if (condition) {
    func(x.y); // heavy stuff evaluated here
 }
 
 Cheers,
 - Ali
 
 
 
 
Not very clean but something like this: import std.stdio; struct LazyVar(alias exp) { alias T = typeof(exp()); T value() { static bool initialized = false; static T val; if (!initialized) { val = exp(); initialized = true; } return val; } alias value this; } LazyVar!(() { writeln("Doing heavy stuff"); return 42; }) a; void main() { auto b = a.value; // Must specify .value or int c = a; // must specify type of value (int). // Otherwise, b and c have type LazyVar!(...) // Some more usage b = c = a; assert(b == 42); assert(c == 42); } Ali
Oct 17 2018
parent aliak <something something.com> writes:
On Wednesday, 17 October 2018 at 20:32:40 UTC, Ali Çehreli wrote:
 On 10/17/2018 12:32 AM, aliak wrote:
 [...]
Not very clean but something like this: import std.stdio; struct LazyVar(alias exp) { alias T = typeof(exp()); T value() { static bool initialized = false; static T val; if (!initialized) { val = exp(); initialized = true; } return val; } alias value this; } LazyVar!(() { writeln("Doing heavy stuff"); return 42; }) a; void main() { auto b = a.value; // Must specify .value or int c = a; // must specify type of value (int). // Otherwise, b and c have type LazyVar!(...) // Some more usage b = c = a; assert(b == 42); assert(c == 42); } Ali
Well I guess that's certainly a way to go about it :) Not very clean indeed though.
Oct 18 2018
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 17 October 2018 at 07:32:37 UTC, aliak wrote:
 lazy S x = () {
     // do some heavy stuff
 }();

 if (condition) {
   func(x.y); // heavy stuff evaluated here
 }
auto x = () { // do some heavy stuff }; if (condition) { func(x().y); // heavy stuff evaluated here } If you want to make it a little prettier, you could define a couple helper functions: T delegate() delay(lazy T expr) { return () => expr; } T force(T delegate() thunk) { return thunk(); }
Oct 17 2018
parent reply aliak <something something.com> writes:
On Wednesday, 17 October 2018 at 23:34:55 UTC, Paul Backus wrote:
 On Wednesday, 17 October 2018 at 07:32:37 UTC, aliak wrote:
 lazy S x = () {
     // do some heavy stuff
 }();

 if (condition) {
   func(x.y); // heavy stuff evaluated here
 }
auto x = () { // do some heavy stuff }; if (condition) { func(x().y); // heavy stuff evaluated here }
That would do heavy stuff everytime i wanted to get y though right?
Oct 18 2018
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 10/18/18 10:08 AM, aliak wrote:
 On Wednesday, 17 October 2018 at 23:34:55 UTC, Paul Backus wrote:
 On Wednesday, 17 October 2018 at 07:32:37 UTC, aliak wrote:
 lazy S x = () {
     // do some heavy stuff
 }();

 if (condition) {
   func(x.y); // heavy stuff evaluated here
 }
auto x = () {     // do some heavy stuff }; if (condition) {     func(x().y); // heavy stuff evaluated here }
That would do heavy stuff everytime i wanted to get y though right?
Yes, but that's what lazy variables do. -Steve
Oct 18 2018
parent reply aliak <something something.com> writes:
On Thursday, 18 October 2018 at 14:11:36 UTC, Steven 
Schveighoffer wrote:
 Yes, but that's what lazy variables do.

 -Steve
Not in Swift at least...
Oct 18 2018
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 10/18/18 12:11 PM, aliak wrote:
 On Thursday, 18 October 2018 at 14:11:36 UTC, Steven Schveighoffer wrote:
 Yes, but that's what lazy variables do.
Not in Swift at least...
Apparently so (I have not used them before), but this is D! So you should be aware that lazy parameters work that way (the expression is evaluated each time the variable is used). In any case, you can certainly create a Swift-like lazy variable and I think the other responses probably show you the way. -Steve
Oct 18 2018
prev sibling parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 18 October 2018 at 14:08:11 UTC, aliak wrote:
 On Wednesday, 17 October 2018 at 23:34:55 UTC, Paul Backus 
 wrote:
 auto x = () {
     // do some heavy stuff
 };

 if (condition) {
     func(x().y); // heavy stuff evaluated here
 }
That would do heavy stuff everytime i wanted to get y though right?
Yes. If that's a problem, you could use `std.functional.memoize`, or Ali's solution.
Oct 18 2018
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 10/17/18 3:32 AM, aliak wrote:
 Hi,
 
 Is there any notion of lazy vars in D (i see that there're parameters)?
 
 i.e:
 
 struct S {
    //...
    int y;
    //...
 }
/*
 lazy S x = () {
      // do some heavy stuff
 }();
*/ auto x() { // do some heavy stuff }
 
 if (condition) {
    func(x.y); // heavy stuff evaluated here
 }
 
-Steve
Oct 18 2018
prev sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Wednesday, 17 October 2018 at 07:32:37 UTC, aliak wrote:
 Hi,

 Is there any notion of lazy vars in D (i see that there're 
 parameters)?
What the language doesn't provide, it generally provides the tools to make: struct Lazy(T) { T delegate() _payload; this(lazy T t) { _payload = () => t; } T get() { return _payload(); } alias get this; } int fun() { n++; return 2; } int n; unittest { Lazy!int a = 1 + fun(); assert(n == 0); // Ensure fun hasn't been called. auto b = a + 2; assert(b == 5); // Ensure calculation is correct. assert(n == 1); // Ensure fun has been called. } -- Simen
Oct 18 2018
parent reply aliak <something something.com> writes:
On Thursday, 18 October 2018 at 14:16:56 UTC, Simen Kjærås wrote:
 On Wednesday, 17 October 2018 at 07:32:37 UTC, aliak wrote:
 Hi,

 Is there any notion of lazy vars in D (i see that there're 
 parameters)?
What the language doesn't provide, it generally provides the tools to make: struct Lazy(T) { T delegate() _payload; this(lazy T t) { _payload = () => t; } T get() { return _payload(); } alias get this; } int fun() { n++; return 2; } int n; unittest { Lazy!int a = 1 + fun(); assert(n == 0); // Ensure fun hasn't been called. auto b = a + 2; assert(b == 5); // Ensure calculation is correct. assert(n == 1); // Ensure fun has been called. } -- Simen
yes! perfect! Thank you
Oct 18 2018
parent aliak <something something.com> writes:
On Thursday, 18 October 2018 at 16:10:04 UTC, aliak wrote:
 On Thursday, 18 October 2018 at 14:16:56 UTC, Simen Kjærås 
 wrote:
 On Wednesday, 17 October 2018 at 07:32:37 UTC, aliak wrote:
 Hi,

 Is there any notion of lazy vars in D (i see that there're 
 parameters)?
What the language doesn't provide, it generally provides the tools to make: struct Lazy(T) { T delegate() _payload; this(lazy T t) { _payload = () => t; } T get() { return _payload(); } alias get this; } int fun() { n++; return 2; } int n; unittest { Lazy!int a = 1 + fun(); assert(n == 0); // Ensure fun hasn't been called. auto b = a + 2; assert(b == 5); // Ensure calculation is correct. assert(n == 1); // Ensure fun has been called. } -- Simen
yes! perfect! Thank you
With single eval: struct Lazy(T) { private T delegate() _payload; private T _value; private bool set = false; this(lazy T t) { _payload = () { writeln("evaled"); return t; }; } property T value() { if (!set) _value = _payload(); set = true; return _value; } property void value(T newValue) { if (!set) _value = _payload(); set = true; _value = newValue; } alias value this; }
Oct 18 2018