Issue 24030 - A `lazy` parameter shouldn't be allowed to be "called" twice
Summary: A `lazy` parameter shouldn't be allowed to be "called" twice
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P1 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-07-04 12:35 UTC by Bolpat
Modified: 2023-07-04 12:35 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Bolpat 2023-07-04 12:35:34 UTC
It’s quite straightforward: The intended use for `lazy` is to defer evaluation; everyone seeing this for the first time expects that. The fact that a function taking a `lazy` parameter may evaluate the underlying delegate more than once is surprising. Only once a programmer learns that there is a delegate underlying, it makes some sense.

This is a breaking change, but there’s a simple transition path: Use a delegate explicitly, and you’ll surprise nobody.

Checking that a `lazy` parameter is evaluated at most once only needs a very limited form of control-flow analysis. In `@system` code, this could be ignored and calling a `lazy` parameter more than once becomes Undefined Behavior.

If desired, on non-release builds, the only-call-once rule can be asserted by introducing a hidden `bool` variable on the caller’s side:

```d
int f(lazy int);

1 + f(1);
```

is lowered to:

```d
int f(int delegate());

bool called; // unique name
1 + f({
    assert(!called);
    called = true;
    return 1;
});
```

What about `lazy` `void` parameters?

They’re no different. You’re after the side-effect, but again, getting it more than once will be surprising; use a delegate.