On Mon, 9 Dec 2024 at 01:51, Timon Gehr via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
On 12/8/24 06:54, Manu wrote:
> Here's the stupidest idea ever: expand inout to take an argument...
>
> void parseThings(string s, void delegate(Thing) inout(nothrow)
> inout(@nogc) sink) inout(nothrow) inout(@nogc)
> {
>    //...
>    sink(Thing());
>    //...
> }
> ...

Issue with this is you will still not know which `inout`s match up. This
is already an issue with the existing `inout`, which just arbitrarily
selects a convention. In particular, it does not really work with
higher-order functions the way you'd need it to here.

Yes, this is obviously an issue, and we have it in D comprehensively; it's the main issue with our 'safe' stuff too; where rust has explicit lifetime attribution... it's essentially the same problem all round; it needs tags that specify things which are associated.
In lieu of that though, I would say, if there are multiple things marked inout(...) in the way I proposed, you would assume the most pessimistic from the set of possibilities is supplied.

void inheritAttribs(string s, void delegate() inout(nothrow) inout(@nogc) fun_1, void delegate() inout(nothrow) inout(@nogc) fun_2) inout(nothrow) inout(@nogc)
{
  //...
  fun_1();
  fun_2();
  //...
}

In this case, `inheritAttribs` would only be nothrow in the event BOTH fun_1 and fun_2 are nothrow, likewise for nogc...


> Surely people have had better ideas? But you get the point, and this is
> basically essential to make the 'sink' pattern work at all in D.
>
> No, no templates; it's not right to generate multiple copies of identical functions just because something it CALLS would transfer an attribute. The function itself is identical no matter the state of any attribute transference, and so this isn't a template problem; it's a pattern matching problem.

Well, it can be seen as a homogeneous vs heterogeneous compilation
problem. The attributes can still act a bit like template parameters,
but only one instance must be created that works for all of them. It's
sometimes called parametric polymorphism.

Right. Do you have examples of this from other languages and how it's expressed? Lifetime's in Rust are the obvious benchmark, but I don't see any evidence that D has a taste for this sort of thing.

I do think that inout could work for all attributes the same as inout does for const (with the same limitations). You could see `inout` as shorthand for `inout(const)` under my suggestion.
Obviously it must enforce the most restrictive implementation inside the code; my function `inheritAttribs` above must be nothrow and nogc internally, but externally it would allow a mapping from one of the 'input' attributes to the 'output' attribute in a non-templated way.