View mode: basic / threaded / horizontal-split · Log in · Help
May 11, 2012
Assigning value to a lazy parameter in a function call
Wasn't easy to find a short good description of the issue in the 
subject, but here's some code to illustrate my "concern":
---
import std.stdio;
void log(T...)(lazy string message, lazy T t) {
        debug writefln(message, t);
}
void main() {
        int a = 42;
        writefln("The meaning of life is %s", a);
        log("Incrementing the meaning of life: %s", ++a);
        writefln("The meaning of life is now %s", a);
}
---

I often call functions where one of the parameters may be an integer 
which i post/pre increment/decrement. However, that can be quite risky 
if the parameter is defined as "lazy" as shown above.
The value of "a" above after calling "log" depends on whether you've 
compiled with "-debug" or not, this may not be very obvious and may take 
some by surprise.

Perhaps the compiler should print out a warning when you're assigning a 
value to a lazy parameter in a function call?
May 11, 2012
Re: Assigning value to a lazy parameter in a function call
On Friday, 11 May 2012 at 20:45:53 UTC, Vidar Wahlberg wrote:
> I often call functions where one of the parameters may be an 
> integer which i post/pre increment/decrement. However, that can 
> be quite risky if the parameter is defined as "lazy" as shown 
> above.
> The value of "a" above after calling "log" depends on whether 
> you've compiled with "-debug" or not, this may not be very 
> obvious and may take some by surprise.
>
> Perhaps the compiler should print out a warning when you're 
> assigning a value to a lazy parameter in a function call?

The entire point of a lazy parameter is to not be
calculated/processed until it's actually necessary. This is
normal behavior for lazy. Most actual use cases for lazy would be 
made impractical if the compiler bombarded the programmer with 
warnings.
May 11, 2012
Re: Assigning value to a lazy parameter in a function call
On 2012-05-11 23:03, Chris Cain wrote:
> On Friday, 11 May 2012 at 20:45:53 UTC, Vidar Wahlberg wrote:
>> Perhaps the compiler should print out a warning when you're assigning
>> a value to a lazy parameter in a function call?
>
> The entire point of a lazy parameter is to not be
> calculated/processed until it's actually necessary. This is
> normal behavior for lazy. Most actual use cases for lazy would be made
> impractical if the compiler bombarded the programmer with warnings.

I'm not suggesting that the compiler should print a warning if you're 
doing a calculation in the function call, I'm suggesting it should give 
you a warning if you're assigning the result of the calculation to a 
variable in the function call.
In other words, «log("%s", a + 1);» would give no warning, while 
«log("%s", ++a);» and «log("%s", (a = a + 1));» would.

(Sorry if this is a duplicate, got an error upon sending, it appears 
like the message never was sent)
May 11, 2012
Re: Assigning value to a lazy parameter in a function call
On Friday, 11 May 2012 at 21:39:57 UTC, Vidar Wahlberg wrote:
> I'm not suggesting that the compiler should print a warning if 
> you're doing a calculation in the function call, I'm suggesting 
> it should give you a warning if you're assigning the result of 
> the calculation to a variable in the function call.
> In other words, «log("%s", a + 1);» would give no warning, 
> while «log("%s", ++a);» and «log("%s", (a = a + 1));» would.

The thing is, ++a != (a = a + 1). And even if it were, it's 
perfectly legitimate for a lazy parameter to change the state of 
things outside the scope of the function. Really, lazy is just 
syntactic sugar for a delegate.

void log(lazy string message, lazy int t)
is just the same as
void log(lazy string message, int delegate() t)

the latter must be called like

log("Incrementing the meaning of life: %s", (){return ++a;});
or
log("Incrementing the meaning of life: %s", () => ++a);

while the former can appear like:
log("Incrementing the meaning of life: %s", ++a);

In this case, I'd say that the "correct" thing to do is not have 
the t parameter be a lazy parameter. Generally, lazy is better 
used for things like the enforce provided by std.exception ... it 
looks something like this (I haven't seen it before, so this is 
an approximation based on my observations):

void enforce(bool condition, lazy string msg) {
   if(condition) throw new EnforceException(msg);
}

enforce(someCondition, "Well, it looks like " ~ 
obj.getNameFromDatabase() ~ " is in an invalid state ... here's a 
helpful representation: " ~ obj.expensiveFunction());

In this case, lazy is used to prevent the expensive calls to get 
the name from a database and computing a hash function unless 
it's absolutely necessary. And obj's state might very well be 
changed when getNameFromDatabase is called or when 
expensiveFunction is run.

> (Sorry if this is a duplicate, got an error upon sending, it 
> appears like the message never was sent)

It's okay. It's a known bug right now due to the mass influx of 
users. It happens to all of us :)
May 11, 2012
Re: Assigning value to a lazy parameter in a function call
On 2012-05-12 00:27, Chris Cain wrote:
> [...]

Thank you for the detailed answer.
I still suspect this can fool some people, and (in my ignorance) I 
couldn't (and still can't, to be honest) really see when you would want 
to assign a variable in a lazy parameter, I would expect that to be far 
more often an error from the coder rather than intended behavior. I'm 
not here to argue though, I just wanted to express my thoughts on the 
issue :)

> It's okay. It's a known bug right now due to the mass influx of users.

Which is good, the language is really interesting, I hope more people 
will look into it.
May 11, 2012
Re: Assigning value to a lazy parameter in a function call
On Friday, 11 May 2012 at 23:07:31 UTC, Vidar Wahlberg wrote:
> Thank you for the detailed answer.
> I still suspect this can fool some people, and (in my 
> ignorance) I couldn't (and still can't, to be honest) really 
> see when you would want to assign a variable in a lazy 
> parameter, I would expect that to be far more often an error 
> from the coder rather than intended behavior. I'm not here to 
> argue though, I just wanted to express my thoughts on the issue 
> :)

No problem. I hope it's become a bit more clear what lazy is for.

++a isn't assigning a. It's causing a to mutate in place (which, 
is just changing state). And lazy parameters are all about 
holding the change of state off until it's necessary.

The biggest "gotcha" about lazy parameters isn't going to be 
that, though... it'll be something like this:

-=-=-
void funct(lazy int x) {
    writeln(x, " ", x);
}

void main() {
    int a = 0;
    funct(++a); // prints 1, 2
    // a is now 2, even though there's only one ++a
}
-=-=-

But keeping in mind that lazy is just convenient syntax sugar for 
a delegate function, the reason why this behaves like this is 
clearer.
Top | Discussion index | About this forum | D home