Thread overview
Attribute transference from callbacks?
19 hours ago
Manu
9 hours ago
Timon Gehr
9 hours ago
Timon Gehr
7 hours ago
Monkyyy
19 hours ago
I've been trying out an API strategy to use sink functions a lot more to hoist the item allocation/management logic to the user and out from the work routines. This idea has received a lot of attention, and I heard a lot of people saying this was a planned direction to move in phobos and friends.

void parseThings(string s, void delegate(Thing) sink)
{
  //...
  sink(Thing());
  //...
}

We have a serious problem though; a function that receives a sink function
must transfer the attributes from the sink function to itself, and we have
no language to do that...
What are the leading strategies that have been discussed to date? Is there
a general 'plan'?
Restriction attributes like pure/nothrow/@nogc/safe, etc need some
expression to operate in a similar way to; where the attribute-ness of
function matches the attributes of its delegate argument(/s).

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());
  //...
}

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.


19 hours ago
My solution I have proposed plenty, is attribute invalidation.

So the caller sees a more restricted set, depending upon the callback passed in.

However Timon didn't like that, thought it wasn't good enough.

9 hours ago
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.

> 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.
9 hours ago
On 12/8/24 06:57, Richard (Rikki) Andrew Cattermole wrote:
> My solution I have proposed plenty, is attribute invalidation.
> 
> So the caller sees a more restricted set, depending upon the callback passed in.
> 
> However Timon didn't like that, thought it wasn't good enough.
> 

It is not.

Completeness: This proposal cannot express even one of the simplest forms of composition, function composition. It also will not compose in practice.

Soundness: This proposal changes the meaning of qualified delegates everywhere in the language and invalidates a lot of existing type system invariants. It will be very tricky to maintain both backwards-compatibility with plain attributes and soundness.

In practice, it will be complicated, very incomplete, and unsound, like `inout`.
7 hours ago
On Sunday, 8 December 2024 at 05:54:40 UTC, Manu wrote:
>
> Surely people have had better ideas? No, no templates;

I'm pretty sure this only could work with templates and with templates it would just happen.

Or better yet, be inlined by the optimizer using function litteralls

"How do I get rid of this bruise on my head, no without stopping hitting my head with the hammer, surely someone with medical skills could actually help me"

6 hours ago

On Sunday, 8 December 2024 at 05:54:40 UTC, Manu wrote:

>

I've been trying out an API strategy to use sink functions a lot more to hoist the item allocation/management logic to the user and out from the work routines. This idea has received a lot of attention, and I heard a lot of people saying this was a planned direction to move in phobos and friends.

void parseThings(string s, void delegate(Thing) sink)
{
  //...
  sink(Thing());
  //...
}

We have a serious problem though; a function that receives a sink function
must transfer the attributes from the sink function to itself, and we have
no language to do that...
What are the leading strategies that have been discussed to date? Is there
a general 'plan'?

I've proposed something like the following in the past, but I don't know how much appetite there is for it:

// assuming Thing() is @nogc nothrow @safe, but not pure
void parseThings(string s, @called void delegate(Thing) sink) @nogc nothrow @safe
{
   sink(Thing());
}

Essentially, how this would work is that the compiler would consider all code inside the function except the call of the delegate to be attributed with the provided attributes. However, the delegate call will always work. All that will happen is that the call to parseThings will have any restrictions removed that aren't on the delegate.

So e.g. a delegate of @nogc pure but not nothrow or @safe will mean parseThings(dg) will be treated like it's @nogc.

Because the list of attributes @nogc nothrow @safe is logic-anded with @nogc pure.

No recompile is necessary.

If you want to insist that some attribute must be on the delegate, you can add the attribute to the delegate parameter. So if I wanted to insist that you must pass in at least a @safe delegate:

void parseThings(string s, @called void delegate(Thing) @safe sink) { ... }

As far as I know, there is no plan to make something like this happen.

-Steve