www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How does laziness and UFCS interact?

reply "Logan Capaldo" <logancapaldo gmail.com> writes:
I just became aware of 
http://dlang.org/phobos/std_exception.html#.ifThrown . It's neat, 
but it seems non-obvious to me how lazy + UFCS should work in 
general.

consider


void lazily(T)(lazy T expression)
{
    expression();
}

It's clear when saying lazily(a.b().c()); that the whole of 
"a.b().c()" is going to be evaluated lazily. With UFCS though, 
I'm more unsure:

is a.b().c().lazily() -> lazily(a.b().c()) or is it more akin to

auto tmp = a.b();
lazily(tmp.c());

If the later is it possible to force the former while still using 
UFCS, ie is (a.b().c()).lazily() different than 
a.b().c().lazily()?
Mar 09 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/09/2015 03:03 PM, Logan Capaldo wrote:
 I just became aware of
 http://dlang.org/phobos/std_exception.html#.ifThrown . It's neat, but it
 seems non-obvious to me how lazy + UFCS should work in general.

 consider


 void lazily(T)(lazy T expression)
 {
     expression();
 }

 It's clear when saying lazily(a.b().c()); that the whole of "a.b().c()"
 is going to be evaluated lazily. With UFCS though, I'm more unsure:

 is a.b().c().lazily() -> lazily(a.b().c()) or is it more akin to

 auto tmp = a.b();
 lazily(tmp.c());

 If the later is it possible to force the former while still using UFCS,
 ie is (a.b().c()).lazily() different than a.b().c().lazily()?
You are right. I had the same observation at minute 11:27 below, where I warn against UFCS with assumeWontThrow: http://www.youtube.com/watch?feature=player_detailpage&v=oF8K4-bieaw#t=687 Ali
Mar 09 2015
parent reply "Logan Capaldo" <logancapaldo gmail.com> writes:
On Monday, 9 March 2015 at 22:15:43 UTC, Ali Çehreli wrote:
 You are right. I had the same observation at minute 11:27 
 below, where I warn against UFCS with assumeWontThrow:


 http://www.youtube.com/watch?feature=player_detailpage&v=oF8K4-bieaw#t=687

 Ali
Sorry, which is right? I know ifThrown is lazy, I'm curious about the "amount" of the expression that is evaluated lazily. a.b().c().assumeWontThrow vs. a.b().c().assumeWontThrow ^--+----^ ^-^ | | +- lazy? +- lazy? The video seems to say "don't use lazy functions with UFCS because you might think the lazy part gets evaluated first, when it does not". Seems reasonable, although I don't know it's any different than assumeWontThrow(f()).
Mar 10 2015
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 10 March 2015 at 14:41:00 UTC, Logan Capaldo wrote:
 On Monday, 9 March 2015 at 22:15:43 UTC, Ali Çehreli wrote:
 You are right. I had the same observation at minute 11:27 
 below, where I warn against UFCS with assumeWontThrow:


 http://www.youtube.com/watch?feature=player_detailpage&v=oF8K4-bieaw#t=687

 Ali
Sorry, which is right? I know ifThrown is lazy, I'm curious about the "amount" of the expression that is evaluated lazily. a.b().c().assumeWontThrow vs. a.b().c().assumeWontThrow ^--+----^ ^-^ | | +- lazy? +- lazy? The video seems to say "don't use lazy functions with UFCS because you might think the lazy part gets evaluated first, when it does not". Seems reasonable, although I don't know it's any different than assumeWontThrow(f()).
a.b().c().assumeWontThrow is rewritten as assumeWontThrow(a.b().c()) and therefore the whole chain is lazy.
Mar 10 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/10/2015 08:00 AM, John Colvin wrote:

 On Tuesday, 10 March 2015 at 14:41:00 UTC, Logan Capaldo wrote:
 On Monday, 9 March 2015 at 22:15:43 UTC, Ali Çehreli wrote:
 You are right. I had the same observation at minute 11:27 below,
 where I warn against UFCS with assumeWontThrow:


 
http://www.youtube.com/watch?feature=player_detailpage&v=oF8K4-bieaw#t=687
 Ali
Sorry, which is right?
You are right that it is confusing. :)
 I know ifThrown is lazy, I'm curious about the
 "amount" of the expression that is evaluated lazily.


   a.b().c().assumeWontThrow     vs.  a.b().c().assumeWontThrow
   ^--+----^                                ^-^
      |                                      |
      +- lazy?                               +- lazy?
As John Colvin said, the first one is right. A test: import std.stdio; struct S {} S a(S s) { writeln("entered a"); return s; } S b(S s) { writeln("entered b"); return s; } void lazily(T)(lazy T expression) { writeln("entered lazily"); expression(); } void main() { S().a.b.lazily; } Outputs entered lazily entered a entered b
 The video seems to say "don't use lazy functions with UFCS because you
 might think the lazy part gets evaluated first, when it does not".
 Seems reasonable, although I don't know it's any different than
 assumeWontThrow(f()).
You are right again. :) However, putting the lazy-taking function "outside" the whole expression makes it visible right away, making easy for me to realize that the execution order may be different from common chains. Ali
Mar 10 2015
parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Tuesday, 10 March 2015 at 17:42:37 UTC, Ali Çehreli wrote:
 You are right again. :) However, putting the lazy-taking 
 function "outside" the whole expression makes it visible right 
 away, making easy for me to realize that the execution order 
 may be different from common chains.
"lazy" aka "named parameters" semantically works just like macros using textual substitution. Just imagine that it is inlined in situ and it becomes clear what is happening. I believe it was the common parameter transfer mode in Algol, but programmers found it terribly confusing, so just about all languages that followed have avoided it. So if anyone gets confused, then find some comfort in knowing that people found it confusing 50 years ago too. :^)
Mar 10 2015