October 13, 2021
On 2021-10-13 9:20, Paul Backus wrote:
> On Wednesday, 13 October 2021 at 13:16:36 UTC, Basile B. wrote:
>> I think that the point of proposal 1 is to have something like, after lowering to common AST constructs:
>>
>> ```d
>> {
>>   {
>>     auto xpath = ....;
>>     scope (exit) destroy(xpath)
>>     // stuff
>>   }
>>   // destroy(xpath) really happens here
>> }
>> ```
> 
> Destructors are already called automatically at the end of a block scope.

The point is that with keeps the entire expression live, even if you only care about a part of it:

struct S { int x; ... }

with (auto y = S().x)
{
   ...
}

In this case the S() temporary will be destroyed only at the end of with's scope.

This enables idioms such as "I want to create a temporary string and mess with it".
October 13, 2021
On 2021-10-13 9:05, Adam D Ruppe wrote:
> On Wednesday, 13 October 2021 at 11:13:32 UTC, Andrei Alexandrescu wrote:
>> 1. Accept named `with`:
>>
>> with (auto xpath = extendPath(name)) {
>>     // the only name injected here is xpath
>> }
> 
> I've wanted this before, but not the "only name injected" thing, since that defeats the whole point of `with`.
> 
> I'd want it to be a standard with statement, just with a name given for the overall thing so you can refer to it as a whole in that scope too.
> 
>> with (auto xpath = extendPath(name).str) {
>>     // the only name injected here is xpath
>>     // assume str has type wstring, then xpath
>>     // also has type string
>> }
> 
> What's the difference between this and `if(auto xpath = ...)` ? It wouldn't be null anyway.

Not generalizable.

> Or between it and
> 
> ---
> {
>    auto xpath = ....;
>    // stuff
> }
> ---
> 
> ?

In cases such as toStringz we don't care about the temporary (it's just a shell meant to ensure resource reclamation), we only care about using the slice within.

> That's why I think the with needs to keep its with behavior even if you give it a name.

That would mess things up.
October 13, 2021
On 2021-10-13 8:45, MrSmith wrote:
> On Wednesday, 13 October 2021 at 11:13:32 UTC, Andrei Alexandrescu wrote:
>> 3. Accept `with` with colon:
>>
>> with (auto xpath = extendPath(name).str):
>>
>> The meaning is like a scoped `with` that extends though the end of the scope.
> 
> Isn't this equivalent to:
> 
> ```d
> auto xpath = extendPath(name).str;
> ```
> 

Sadly no:

https://run.dlang.io/is/Ja1uVk


October 13, 2021
On Wednesday, 13 October 2021 at 19:18:55 UTC, Andrei Alexandrescu wrote:
> The point is that with keeps the entire expression live, even if you only care about a part of it:

OK, that explains things now. I see what you're going for.

Not in love with it being `with` that works differently than the other `with`s but it kinda makes sense anyway.

The lambda pattern though does have a few other advantages... I think it is generally easier to use... but gotta chew on it a bit.
October 13, 2021
On 2021-10-13 15:28, Adam D Ruppe wrote:
> On Wednesday, 13 October 2021 at 19:18:55 UTC, Andrei Alexandrescu wrote:
>> The point is that with keeps the entire expression live, even if you only care about a part of it:
> 
> OK, that explains things now. I see what you're going for.
> 
> Not in love with it being `with` that works differently than the other `with`s but it kinda makes sense anyway.
> 
> The lambda pattern though does have a few other advantages... I think it is generally easier to use... but gotta chew on it a bit.

One major issue with the lambda pattern is composition. Every layer of composition introduces yet another scope AND parenthesis level. That doesn't scale well at all.
October 13, 2021
On 10/13/21 1:13 PM, Andrei Alexandrescu wrote:
> We can improve the `with` statement as follows:

I don't think this is an "improvement" of the `with` statement. It's a completely novel feature that happens to be syntactically very close to the existing `with` statement. There's an obvious meaning for the new syntax as an extension of the existing feature, but it is not what you propose. Not great. Maybe there is a better way to address this problem?
October 13, 2021
On Wednesday, 13 October 2021 at 19:18:55 UTC, Andrei Alexandrescu wrote:
> The point is that with keeps the entire expression live, even if you only care about a part of it:
>
> struct S { int x; ... }
>
> with (auto y = S().x)
> {
>    ...
> }
>
> In this case the S() temporary will be destroyed only at the end of with's scope.

Not a fan. It uses the same syntax as `if (auto y = S().x)` but has subtly different semantics, in a way that's likely to go unnoticed in common usage.

It's also not obvious which sub-expressions get kept alive. For example:

    // What's kept alive--S(1), S(2), or both?
    bool b = /* ... */;
    with (auto y = (b ? S(1) : S(2)).x)

    // Are S(1) and S(2) kept alive?
    S fun(S a, S b) { /* ... */ }
    with (auto y = fun(S(1), S(2)).x)

Of course one could work out a set of rules for this and add them to the language spec, but it seems like a lot of effort and complexity for not much benefit, especially when we can already get the desired behavior with normal block scopes:

    {
        S temporary = S();
        with(auto y = temporary.x)
        {
            /* ... */
        }
    } // temporary's lifetime ends here

> This enables idioms such as "I want to create a temporary string and mess with it".

You can already do this by wrapping the string in a struct that owns its memory:

    struct OwnedString
    {
        string[] payload;
        ~this() { free(payload.ptr); }
        // etc.
    }

That way, D's existing scoping rules will ensure that the resources are released at the correct time, and you do not have to worry about keeping some unrelated temporary alive via obscure special-case language rules.
October 13, 2021
On Wednesday, 13 October 2021 at 20:41:11 UTC, Paul Backus wrote:
> Of course one could work out a set of rules for this and add them to the language spec, but it seems like a lot of effort and complexity for not much benefit, especially when we can already get the desired behavior with normal block scopes:
>

This.

If the concern is that the temporary's destruction will destroy the variable, it's a general problem that is tackled by ownership.
October 14, 2021

On Wednesday, 13 October 2021 at 19:30:43 UTC, Andrei Alexandrescu wrote:

>

On 2021-10-13 15:28, Adam D Ruppe wrote:

>

On Wednesday, 13 October 2021 at 19:18:55 UTC, Andrei Alexandrescu wrote:

>

The point is that with keeps the entire expression live, even if you only care about a part of it:

OK, that explains things now. I see what you're going for.

Not in love with it being with that works differently than the other withs but it kinda makes sense anyway.

The lambda pattern though does have a few other advantages... I think it is generally easier to use... but gotta chew on it a bit.

One major issue with the lambda pattern is composition. Every layer of composition introduces yet another scope AND parenthesis level. That doesn't scale well at all.

The lack of composability is annoying, but how often is it practically a problem ? Those functions are used for D to C string conversion, so in practice they are always at the end of the pipeline (just like each is). I don't really see how those could justify a new language feature.

October 13, 2021
On 10/13/21 10:30 PM, Mathias LANG wrote:
> On Wednesday, 13 October 2021 at 19:30:43 UTC, Andrei Alexandrescu wrote:
>> On 2021-10-13 15:28, Adam D Ruppe wrote:
>>> On Wednesday, 13 October 2021 at 19:18:55 UTC, Andrei Alexandrescu wrote:
>>>> The point is that with keeps the entire expression live, even if you only care about a part of it:
>>>
>>> OK, that explains things now. I see what you're going for.
>>>
>>> Not in love with it being `with` that works differently than the other `with`s but it kinda makes sense anyway.
>>>
>>> The lambda pattern though does have a few other advantages... I think it is generally easier to use... but gotta chew on it a bit.
>>
>> One major issue with the lambda pattern is composition. Every layer of composition introduces yet another scope AND parenthesis level. That doesn't scale well at all.
> 
> The lack of composability is annoying, but how often is it practically a problem ? Those functions are used for D to C string conversion, so in practice they are always at the end of the pipeline (just like `each` is). I don't really see how those could justify a new language feature.

Well extendedPathThen uses toStringz :o).