Jump to page: 1 2 3
Thread overview
Discussion Thread: DIP 1033--Implicit Conversion of Expressions to Delegates--Community Review Round 1
Apr 22, 2020
Mike Parker
Apr 22, 2020
Mike Parker
Apr 22, 2020
kinke
Apr 22, 2020
kinke
Apr 23, 2020
aliak
Apr 23, 2020
Patrick Schluter
Apr 23, 2020
Guillaume Piolat
Apr 23, 2020
Meta
Apr 23, 2020
aliak
Apr 23, 2020
aliak
Apr 23, 2020
Meta
Apr 22, 2020
Guillaume Piolat
Apr 22, 2020
kinke
Apr 22, 2020
kinke
April 22, 2020
This is the discussion thread for the first round of Community Review of DIP 1033, "Implicit Conversion of Expressions to Delegates":

https://github.com/dlang/DIPs/blob/7b61411cb6cf8db05d9b8e1df5d2d9bae53a5f1e/DIPs/DIP1033.md

The review period will end at 11:59 PM ET on May 6, or when I make a post declaring it complete. Discussion in this thread may continue beyond that point.

Here in the discussion thread, you are free to discuss anything and everything related to the DIP. Express your support or opposition, debate alternatives, argue the merits, etc.

However, if you have any specific feedback on how to improve the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary I write at the end of this review round. I will post a link to that thread immediately following this post. Just be sure to read and understand the Reviewer Guidelines before posting there:

https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md

And my blog post on the difference between the Discussion and Feedback threads:

https://dlang.org/blog/2020/01/26/dip-reviews-discussion-vs-feedback/

Please stay on topic here. I will delete posts that are completely off-topic.
April 22, 2020
On Wednesday, 22 April 2020 at 07:41:12 UTC, Mike Parker wrote:

> Here in the discussion thread, you are free to discuss anything and everything related to the DIP. Express your support or opposition, debate alternatives, argue the merits, etc.
>
> However, if you have any specific feedback on how to improve the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary I write at the end of this review round. I will post a link to that thread immediately following this post.

The Feedback Thread is here:

https://forum.dlang.org/post/nxahrsukobybkezibcsm@forum.dlang.org

April 22, 2020
I don't think this is a good idea. One of the problems with `lazy` IMO is that one needs good IDE support to somehow highlight that the argument expression isn't evaluated before the call, and might not be evaluated at all:

// in some other module:
void foo(lazy int i) {}

void main()
{
    int i = 1;
    foo(++i);
    assert(i == 1); // what? not incremented above? ah yeah, lazy and not evaluated at all by foo
}

The proposal would extend that problem to regular delegate params too. So I find the explicit version (`() => ++i`) better to make that clear. I don't think the 'overhead' of putting an additional `() =>` in front of the expression justifies introducing the proposed implicit convertibility.
April 22, 2020
On 4/22/20 7:56 AM, kinke wrote:
> I don't think this is a good idea. One of the problems with `lazy` IMO is that one needs good IDE support to somehow highlight that the argument expression isn't evaluated before the call, and might not be evaluated at all:
> 
> // in some other module:
> void foo(lazy int i) {}
> 
> void main()
> {
>      int i = 1;
>      foo(++i);
>      assert(i == 1); // what? not incremented above? ah yeah, lazy and not evaluated at all by foo
> }

This is more of a problem of lazy parameters that mutate something. Most of the time, that isn't the use case of lazy -- it's to prevent calling some expensive thing when it's not needed. Most definitely this DIP would make that problem worse.

What could be something that helps is enforcing that expressions to delegate implicit conversions require no mutation. I'm not sure how that could be enforced, but possibly requiring only pure function calls on const data (including the context).

It wouldn't be a breaking change, because currently expressions don't bind to delegates, so we can enforce that rule there, then deprecate mutating expressions on lazy parameters, and finally remove lazy.

> 
> The proposal would extend that problem to regular delegate params too. So I find the explicit version (`() => ++i`) better to make that clear. I don't think the 'overhead' of putting an additional `() =>` in front of the expression justifies introducing the proposed implicit convertibility.

I've never had much of an issue with the verbosity of delegates, especially since the () => form came about.

What I HAVE had an issue with is not being able to pass a delegate into a lazy parameter. e.g.:

void foo(lazy int x);

foo(() {some; large; calculation; return result; }); // no good.
foo(() {...}()); // works but, is a delegate that calls a delegate, ugh.

To that end, would it be possible to add lazy binding to a delegate in the same DIP? The more we make lazy behave like a delegate, the easier it will be to remove lazy.

-Steve
April 22, 2020
On Wednesday, 22 April 2020 at 12:30:52 UTC, Steven Schveighoffer wrote:
> This is more of a problem of lazy parameters that mutate something. Most of the time, that isn't the use case of lazy -- it's to prevent calling some expensive thing when it's not needed.

I disagree - `foo(myData.recomputeFromScratch())` has the same problem, it's not obvious from the call site alone that the expensive operation is deferred and might be skipped.

> To that end, would it be possible to add lazy binding to a delegate in the same DIP? The more we make lazy behave like a delegate, the easier it will be to remove lazy.

That might be a migration path towards removing lazy, so that the call sites can switch to delegates already, and the lazy params transformed to explicit delegates in a 2nd step. No idea if such a two-step approach would be worth it though.
April 22, 2020
On 4/22/20 10:04 AM, kinke wrote:
> On Wednesday, 22 April 2020 at 12:30:52 UTC, Steven Schveighoffer wrote:
>> This is more of a problem of lazy parameters that mutate something. Most of the time, that isn't the use case of lazy -- it's to prevent calling some expensive thing when it's not needed.
> 
> I disagree - `foo(myData.recomputeFromScratch())` has the same problem, it's not obvious from the call site alone that the expensive operation is deferred and might be skipped.

But if myData.recomputeFromScratch() has no side effects, what does it matter if not used or called?

For example, if you have:

auto foo(T)(bool cond, T trueValue, T falseValue)
{
   return cond ? trueValue : falseValue;
}

And you call like:

auto x = foo(cond, val, expensivePureCalc());

A sufficiently intelligent compiler is going to avoid calling expensivePureCalc when cond is false. Is that a problem?

Really the only use of lazy I use is in enforce. The lazy message might do GC allocations to generate a string that is thrown away if not used. But the string generation doesn't mutate anything, so it's not going to have an effect on the operation of the program if not called.

What I'm saying is if the DIP *enforced* that expression-to-delegate happens only for these cases, then there is no worry about whether the expression is evaluated or not.

-Steve
April 22, 2020
On 4/22/20 11:15 AM, Steven Schveighoffer wrote:
> A sufficiently intelligent compiler is going to avoid calling expensivePureCalc when cond is false. Is that a problem?

ugh, when cond is *true* obviously ;)

-Steve
April 22, 2020
On Wednesday, 22 April 2020 at 07:41:12 UTC, Mike Parker wrote:
>
> Here in the discussion thread, you are free to discuss anything and everything related to the DIP. Express your support or opposition, debate alternatives, argue the merits, etc.
>

I don't like it. I'm actively avoiding lazy, and delegates are generally not very usable in nothrow @nogc -betterC modes. More easy syntax for delegates sounds not that desirable to me. I'd prefer if lazy was removed.
April 22, 2020
On Wednesday, 22 April 2020 at 15:15:24 UTC, Steven Schveighoffer wrote:
>
> Really the only use of lazy I use is in enforce.

I'd say that object.d has some pretty good use cases in addition to enforce:

inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue):
https://github.com/dlang/druntime/blob/v2.091.0/src/object.d#L2576

ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init):
https://github.com/dlang/druntime/blob/v2.091.0/src/object.d#L2605



April 22, 2020
On Wednesday, 22 April 2020 at 16:37:28 UTC, Guillaume Piolat wrote:
> On Wednesday, 22 April 2020 at 07:41:12 UTC, Mike Parker wrote:
>>
>> Here in the discussion thread, you are free to discuss anything and everything related to the DIP. Express your support or opposition, debate alternatives, argue the merits, etc.
>>
>
> I don't like it. I'm actively avoiding lazy, and delegates are generally not very usable in nothrow @nogc -betterC modes. More easy syntax for delegates sounds not that desirable to me. I'd prefer if lazy was removed.

If this DIP is accepted, `lazy` could be deprecated, as it could be fully replaced by scope delegates, which are nothrow @nogc -betterC compatible.
« First   ‹ Prev
1 2 3