<div dir="ltr"><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Wed, 11 Dec 2024 at 08:25, Timon Gehr via Digitalmars-d <<a href="mailto:digitalmars-d@puremagic.com">digitalmars-d@puremagic.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 12/9/24 07:47, Manu wrote:<br>
> On Mon, 9 Dec 2024 at 01:51, Timon Gehr via Digitalmars-d <digitalmars- <br>
> <a href="mailto:d@puremagic.com" target="_blank">d@puremagic.com</a> <mailto:<a href="mailto:digitalmars-d@puremagic.com" target="_blank">digitalmars-d@puremagic.com</a>>> wrote:<br>
> <br>
> On 12/8/24 06:54, Manu wrote:<br>
> > Here's the stupidest idea ever: expand inout to take an argument...<br>
> ><br>
> > void parseThings(string s, void delegate(Thing) inout(nothrow)<br>
> > inout(@nogc) sink) inout(nothrow) inout(@nogc)<br>
> > {<br>
> > //...<br>
> > sink(Thing());<br>
> > //...<br>
> > }<br>
> > ...<br>
> <br>
> Issue with this is you will still not know which `inout`s match up.<br>
> This<br>
> is already an issue with the existing `inout`, which just arbitrarily<br>
> selects a convention. In particular, it does not really work with<br>
> higher-order functions the way you'd need it to here.<br>
> <br>
> <br>
> Yes, this is obviously an issue, and we have it in D comprehensively; <br>
> it's the main issue with our 'safe' stuff too; where rust has explicit <br>
> lifetime attribution... it's essentially the same problem all round; it <br>
> needs tags that specify things which are associated.<br>
> In lieu of that though, I would say, if there are multiple things marked <br>
> inout(...) in the way I proposed, you would assume the most pessimistic <br>
> from the set of possibilities is supplied.<br>
> <br>
> void inheritAttribs(string s, void delegate() inout(nothrow) <br>
> inout(@nogc) fun_1, void delegate() inout(nothrow) inout(@nogc) fun_2) <br>
> inout(nothrow) inout(@nogc)<br>
> {<br>
> //...<br>
> fun_1();<br>
> fun_2();<br>
> //...<br>
> }<br>
> <br>
> In this case, `inheritAttribs` would only be nothrow in the event BOTH <br>
> fun_1 and fun_2 are nothrow, likewise for nogc...<br>
> ...<br>
<br>
Well, this is one limitation, but the `inout` on the delegate does not <br>
even match up with the `inout` on `inheritAttribs` those are already <br>
different.<br>
<br>
This does not compile;<br>
<br>
```d<br>
inout(int)* foo(inout(int)* delegate()inout dg,inout(int)* x){<br>
return x;<br>
}<br>
<br>
void main(){<br>
const(int)* delegate()const dg;<br>
const(int)* x;<br>
foo(dg,x); // error<br>
}<br>
```<br>
<br>
It seems at least this would need to work.<br>
<br>
`inout` is very confusing because different `inout` annotations can get <br>
conflated or not conflated. It's also the main reason why the <br>
implementation is unsound, it's not done consistently during type checking.<br></blockquote><div><br></div><div>I agree that's a problem. It's classic D though where things are non-uniform that way.</div><div>The resolution would probably be to always conflate all inouts; since we can't tag them individually, we have to assume they're all uniformly tagged; and they all take on the most restrictive state from the call.<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> <br>
> > Surely people have had better ideas? But you get the point, and<br>
> this is<br>
> > basically essential to make the 'sink' pattern work at all in D.<br>
> ><br>
> > No, no templates; it's not right to generate multiple copies of<br>
> identical functions just because something it CALLS would transfer<br>
> an attribute. The function itself is identical no matter the state<br>
> of any attribute transference, and so this isn't a template problem;<br>
> it's a pattern matching problem.<br>
> <br>
> Well, it can be seen as a homogeneous vs heterogeneous compilation<br>
> problem. The attributes can still act a bit like template parameters,<br>
> but only one instance must be created that works for all of them. It's<br>
> sometimes called parametric polymorphism.<br>
> <br>
> <br>
> Right. Do you have examples of this from other languages and how it's <br>
> expressed? Lifetime's in Rust are the obvious benchmark, but I don't see <br>
> any evidence that D has a taste for this sort of thing.<br>
> ...<br>
<br>
Well, Java, C#, Scala support homogeneous compilation in their generics.<br>
<br>
In Haskell everything is polymorphic by default with implicit universal <br>
quantification over lower-case type parameters.<br>
<br>
> I do think that inout could work for all attributes the same as inout <br>
> does for const (with the same limitations).<br>
<br>
Well, as I showed above, those limitations are kind of fatal for your <br>
use case.<br></blockquote><div><br></div><div>Sorry, I didn't follow what makes them fatal?<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> You could see `inout` as <br>
> shorthand for `inout(const)` under my suggestion.<br>
> Obviously it must enforce the most restrictive implementation inside the <br>
> code; my function `inheritAttribs` above must be nothrow and nogc <br>
> internally, but externally it would allow a mapping from one of the <br>
> 'input' attributes to the 'output' attribute in a non-templated way.<br>
<br>
`inout` also interacts with `immutable`, not only `const`.<br></blockquote><div><br></div><div>The way I saw it was that at compile time, `inout` is presumed to be equivalent to const. You can't pass an inout(int)* to an immutable(int)*, but you can pass to a const(int)*... but yeah, in terms of conceptual precision, I see your point.<br></div></div></div>