www.digitalmars.com         C & C++   DMDScript  

D - Imagining lazy evaluation of function arguments

reply "Richard Krehbiel" <rich kastle.com> writes:
"Lazy evaluation" is when the value of a function argument isn't actually
computed until the called function uses it.

For example, I've got a diagnostic logging function roughly like this:

void diag_log(int level, char *string)
{
   if(level <= diag_level)
   {
      fputs(string, logfile);
   }
}

...and this program listens on a socket port where I can connect up and give
it "change diag_level" commands.  So no compile-time tricks will help.

Now, each time my program calls diag_log, it evaluates the argument, and
that might include some pretty hairy computations (network traffic, database
retrievals).  And it will *probably* be thrown away, because diag_level
isn't high enough to print.

In C I dealt with this by using a macro that inserts a test of diag_level
before calling diag_log.  Oops - D has no macros; and an inline function be
obliged to evaluate unused arguments anyway, for their side-effects.

To do something like this in C, you might pass a function pointer, so the
callee can evaluate the argument at it's leisure, and as often as it likes.
But setting up the function (a callback) is a bit more tedious than just
coding arguments.

Perhaps D can just do this stuff itself when the caller says "lazy."

int diag_log(int level, lazy char *string) { ... }

And, well, okay, applying the "lazy" term to the programmer himself is
probably appropriate. :-)

In the caller, the compiler sets up a hidden function containing the code to
evaluate the argument, and passes it's address for "string".  In diag_log,
reference to "string" invokes this function to obtain the value, as if you
had coded the function call "(*string)()".

Further details left as an exercise to the, um, implementor...

(Oh, just wait until I write up "threaded function arguments."  I don't want
much, do I?)

--
Richard Krehbiel, Arlington, VA, USA
rich kastle.com (work) or krehbiel3 home.com (personal)
Feb 13 2002
next sibling parent reply "Martin York" <Martin.York veritas.com> writes:
Is this not what interfaces are for?

void diag_log(int level,messageInterface *data)
{
    if (level <= diag_level)
    {
        fputs(data->getString(),logfile);
    }
}




"Richard Krehbiel" <rich kastle.com> wrote in message
news:a4dto2$2abh$1 digitaldaemon.com...
 "Lazy evaluation" is when the value of a function argument isn't actually
 computed until the called function uses it.

 For example, I've got a diagnostic logging function roughly like this:

 void diag_log(int level, char *string)
 {
    if(level <= diag_level)
    {
       fputs(string, logfile);
    }
 }

 ...and this program listens on a socket port where I can connect up and

 it "change diag_level" commands.  So no compile-time tricks will help.

 Now, each time my program calls diag_log, it evaluates the argument, and
 that might include some pretty hairy computations (network traffic,

 retrievals).  And it will *probably* be thrown away, because diag_level
 isn't high enough to print.

 In C I dealt with this by using a macro that inserts a test of diag_level
 before calling diag_log.  Oops - D has no macros; and an inline function

 obliged to evaluate unused arguments anyway, for their side-effects.

 To do something like this in C, you might pass a function pointer, so the
 callee can evaluate the argument at it's leisure, and as often as it

 But setting up the function (a callback) is a bit more tedious than just
 coding arguments.

 Perhaps D can just do this stuff itself when the caller says "lazy."

 int diag_log(int level, lazy char *string) { ... }

 And, well, okay, applying the "lazy" term to the programmer himself is
 probably appropriate. :-)

 In the caller, the compiler sets up a hidden function containing the code

 evaluate the argument, and passes it's address for "string".  In diag_log,
 reference to "string" invokes this function to obtain the value, as if you
 had coded the function call "(*string)()".

 Further details left as an exercise to the, um, implementor...

 (Oh, just wait until I write up "threaded function arguments."  I don't

 much, do I?)

 --
 Richard Krehbiel, Arlington, VA, USA
 rich kastle.com (work) or krehbiel3 home.com (personal)

Feb 13 2002
next sibling parent "Richard Krehbiel" <rich kastle.com> writes:
Sure, that'll work, and it means the caller of diag_log must prepare an
object with the given interface before calling diag_log.

If it's that cumbersome, the programmer won't do it.

"Martin York" <Martin.York veritas.com> wrote in message
news:a4duot$2aoj$1 digitaldaemon.com...
 Is this not what interfaces are for?

 void diag_log(int level,messageInterface *data)
 {
     if (level <= diag_level)
     {
         fputs(data->getString(),logfile);
     }
 }




 "Richard Krehbiel" <rich kastle.com> wrote in message
 news:a4dto2$2abh$1 digitaldaemon.com...
 "Lazy evaluation" is when the value of a function argument isn't


 computed until the called function uses it.

 For example, I've got a diagnostic logging function roughly like this:

 void diag_log(int level, char *string)
 {
    if(level <= diag_level)
    {
       fputs(string, logfile);
    }
 }

 ...and this program listens on a socket port where I can connect up and

 it "change diag_level" commands.  So no compile-time tricks will help.

 Now, each time my program calls diag_log, it evaluates the argument, and
 that might include some pretty hairy computations (network traffic,

 retrievals).  And it will *probably* be thrown away, because diag_level
 isn't high enough to print.

 In C I dealt with this by using a macro that inserts a test of


 before calling diag_log.  Oops - D has no macros; and an inline function

 obliged to evaluate unused arguments anyway, for their side-effects.

 To do something like this in C, you might pass a function pointer, so


 callee can evaluate the argument at it's leisure, and as often as it

 But setting up the function (a callback) is a bit more tedious than just
 coding arguments.

 Perhaps D can just do this stuff itself when the caller says "lazy."

 int diag_log(int level, lazy char *string) { ... }

 And, well, okay, applying the "lazy" term to the programmer himself is
 probably appropriate. :-)

 In the caller, the compiler sets up a hidden function containing the


 to
 evaluate the argument, and passes it's address for "string".  In


 reference to "string" invokes this function to obtain the value, as if


 had coded the function call "(*string)()".

 Further details left as an exercise to the, um, implementor...

 (Oh, just wait until I write up "threaded function arguments."  I don't

 much, do I?)


-- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 home.com (personal)
Feb 13 2002
prev sibling parent reply "Juan Carlos Arevalo Baeza" <jcab JCABs-Rumblings.com> writes:
"Martin York" <Martin.York veritas.com> wrote in message
news:a4duot$2aoj$1 digitaldaemon.com...
 Is this not what interfaces are for?

 void diag_log(int level,messageInterface *data)
 {
     if (level <= diag_level)
     {
         fputs(data->getString(),logfile);
     }
 }

And then comes the call: diag_log(3, new messageInterface(new concatStrings("Hello ", "World!")); That's the implementation. He was asking for a better syntax for this: diag_log(3, "Hello " + "World!"); Salutaciones, JCAB http://www.JCABs-Rumblings.com
Feb 14 2002
parent "Richard Krehbiel" <rich kastle.com> writes:
"Juan Carlos Arevalo Baeza" <jcab JCABs-Rumblings.com> wrote in message
news:a4i8h3$19mk$1 digitaldaemon.com...
 "Martin York" <Martin.York veritas.com> wrote in message
 news:a4duot$2aoj$1 digitaldaemon.com...
 Is this not what interfaces are for?

 void diag_log(int level,messageInterface *data)
 {
     if (level <= diag_level)
     {
         fputs(data->getString(),logfile);
     }
 }

And then comes the call: diag_log(3, new messageInterface(new concatStrings("Hello ", "World!"));

...and before each call to diag_log, there's a call to "new concatStrings", whose result is passed to "new messageInterface", and *then* diag_log gets called with that result. I want those other calls *not* *to* *happen* unless diag_log tells them to.
    That's the implementation. He was asking for a better syntax for this:

 diag_log(3, "Hello " + "World!");

And yes, a simpler interface is better. (That's why printf still exists - despite being type-dangrous, it has a simple interface.)
Feb 15 2002
prev sibling parent reply DrWhat? <DrWhat nospam.madscientist.co.uk> writes:
Richard Krehbiel wrote:

 "Lazy evaluation" is when the value of a function argument isn't actually
 computed until the called function uses it.
 
 For example, I've got a diagnostic logging function roughly like this:
 
 void diag_log(int level, char *string)
 {
    if(level <= diag_level)
    {
       fputs(string, logfile);
    }
 }

Why not just do a wrapper function ie. void diag_log(int level, char*string) { if( level <= diag_level ) { diag_log_wrapped(level,string) ;}} void diag_log_wrapped(int level,char*string) { /* hairy stuff */ ; fputs(string,logfile) ;} D should see the first function as "good to inline" and inline it in the calling procedure, that is if I read the specifications correctly. [Is there a way to tell D to always inline?] C 2002/2/15 [If the garbage collector truely worked then it would throw out most of my programmes!]
Feb 14 2002
next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"DrWhat?" <DrWhat nospam.madscientist.co.uk> wrote in message
news:a4htc9$12he$1 digitaldaemon.com...

 [Is there a way to tell D to always inline?]

No. I believe it's because the compiler can determine whether to inline function or not better than programmer... just like the register variables in C that used to work in good old days but now mean nothing...
 [If the garbage collector truely worked then it
 would throw out most of my programmes!]

Why? =)
Feb 14 2002
parent reply "Juan Carlos Arevalo Baeza" <jcab JCABs-Rumblings.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a4i436$17ts$1 digitaldaemon.com...
 "DrWhat?" <DrWhat nospam.madscientist.co.uk> wrote in message
 news:a4htc9$12he$1 digitaldaemon.com...

 [Is there a way to tell D to always inline?]

No. I believe it's because the compiler can determine whether to inline function or not better than programmer... just like the register variables in C that used to work in good old days but now mean nothing...

That's, again, my old rant. I want (I need) to be able to let the compiler know that it has no choice in the matter, and that if it can't for any reason, it should halt compilation with an error. It doesn't change anything at the back-end at all. It just affects the decision of wether to inline or not and such.
Feb 14 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Juan Carlos Arevalo Baeza" <jcab JCABs-Rumblings.com> wrote in message
news:a4i8bu$19m3$1 digitaldaemon.com...

    That's, again, my old rant. I want (I need) to be able to let the
 compiler know that it has no choice in the matter, and that if it can't

 any reason, it should halt compilation with an error.

A compiler switch (inline all functions, or inline function with name x) can be used for this purpose. In general, for you as a programmer, there's no difference. Program will work absolutely the same in both cases - output won't change. It's just the matter of speed. The language doesn't cover that, however - it is courtesy of the compiler.
Feb 15 2002
prev sibling parent "Richard Krehbiel" <rich kastle.com> writes:
"DrWhat?" <DrWhat nospam.madscientist.co.uk> wrote in message
news:a4htc9$12he$1 digitaldaemon.com...
 Why not just do a wrapper function ie.

 void diag_log(int level, char*string)
 {       if( level <= diag_level )
  {      diag_log_wrapped(level,string)
 ;}}

 void diag_log_wrapped(int level,char*string)
 {       /* hairy stuff */
  ;      fputs(string,logfile)
 ;}

 D should see the first function as "good to inline"
 and inline it in the calling procedure,  that is if
 I read the specifications correctly.

No help. Function may or may not be inlined, and the program had better work exactly the same either way. Since it may have side-effects, then even if inlined, the string argument must be computed, even if it doesn't get used. I want it not to get computed if it's not used. -- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 comcast.net (personal)
Feb 15 2002