8 hours ago
On Thursday, 23 January 2025 at 09:49:54 UTC, Richard (Rikki) Andrew Cattermole wrote:
>
> On 23/01/2025 10:00 PM, Sebastiaan Koppe wrote:
>> A good starting point would be the official reference https:// en.cppreference.com/w/cpp/language/coroutines
>
> I didn't seen anything worth adding. So I haven't.

I wouldn't dismiss it so easily. For one it explains the mechanism by which suspended coroutines can get scheduled again, whereas your DIP only mentioned the `WaitingOn` but doesn't go into detail how it actually works.
8 hours ago

On Thursday, 12 December 2024 at 10:36:50 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

Stackless coroutines

I might want to say, the term confused me quite a while. That’s because the coroutine does have a stack (its own stack). I thought it would somehow not have one, since it’s called “stackless,” but it just means its stack isn’t the caller’s stack. That fact was kind of obvious to me, since that’s what “coroutine” meant to me already. In my head I don’t see how a coroutine could even work otherwise.

Maybe it’s a good idea to call the proposal “Coroutines” and omit “stackless.”

7 hours ago

On Monday, 13 January 2025 at 17:59:35 UTC, Atila Neves wrote:

>

[…]
Why @async return instead of yield? Why have to add @async to the grammar if it looks like an attribute?

Agreed. My two cents: C# has yield return and yield break. The funny thing is, if D were open to contextual keywords, we could do the same. Then, yield wouldn’t even have to become a keyword. Alternatively, use yield_return and yield_break, which, yes, are valid identifiers, but have a near-zero probability being present in existing D code.

If anything, the proper way to make yield into a keyword is __yield, not @yield.

7 hours ago
On 24/01/2025 5:33 AM, Quirin Schroll wrote:
> On Thursday, 12 December 2024 at 10:36:50 UTC, Richard (Rikki) Andrew Cattermole wrote:
>> Stackless coroutines
> 
> I might want to say, the term confused me quite a while. That’s because the coroutine does have a stack (its own stack). I thought it would somehow not have one, since it’s called “stackless,” but it just means its stack isn’t the caller’s stack. That fact was kind of obvious to me, since that’s what “coroutine” meant to me already. In my head I don’t see how a coroutine could even work otherwise.
> 
> Maybe it’s a good idea to call the proposal “Coroutines” and omit “stackless.”

The term is correct.

A stackless coroutine, uses the thread stack, except for variables that cross a yield point in its function body. These get extracted on to the heap.

A stackful coroutine, uses its own stack, not the threads.
This is otherwise known in D as a fiber.

Over the last 20 years stackful coroutines have seen limited use, but stackless has only grown in implementations. If for no other reason than thread safety. Hence the association. But the word itself could mean either, which is why the DIP has to clarify which it is, although the spec may not add it.

7 hours ago
On 24/01/2025 4:55 AM, Sebastiaan Koppe wrote:
> On Thursday, 23 January 2025 at 09:49:54 UTC, Richard (Rikki) Andrew Cattermole wrote:
>>
>> On 23/01/2025 10:00 PM, Sebastiaan Koppe wrote:
>>> A good starting point would be the official reference https:// en.cppreference.com/w/cpp/language/coroutines
>>
>> I didn't seen anything worth adding. So I haven't.
> 
> I wouldn't dismiss it so easily. For one it explains the mechanism by which suspended coroutines can get scheduled again, whereas your DIP only mentioned the `WaitingOn` but doesn't go into detail how it actually works.

Ahhh ok, you are looking for a statement to the effect of: "A coroutine may only be executed if it is not complete and if it has a dependency for that to be complete or have a value."

The reason it is not in the DIP is because this a library behavior.

On the language side there is no such guarantee, you should be free to execute them repeatedly without error. There could be logic bugs, but the compiler cannot know that this is the case.

About the only time the compiler should prevent you from calling it is if there is no transition to execute (such as it is now complete).

4 hours ago

On Thursday, 23 January 2025 at 17:14:50 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

On 24/01/2025 4:55 AM, Sebastiaan Koppe wrote:

>

I wouldn't dismiss it so easily. For one it explains the mechanism by which suspended coroutines can get scheduled again, whereas your DIP only mentioned the WaitingOn but doesn't go into detail how it actually works.

Ahhh ok, you are looking for a statement to the effect of: "A coroutine may only be executed if it is not complete and if it has a dependency for that to be complete or have a value."

The reason it is not in the DIP is because this a library behavior.

On the language side there is no such guarantee, you should be free to execute them repeatedly without error. There could be logic bugs, but the compiler cannot know that this is the case.

About the only time the compiler should prevent you from calling it is if there is no transition to execute (such as it is now complete).

No, that is not what I mean.

Upon yielding a coroutine, say a socket read, you'll want to park the coroutine until the socket read has completed. This requires a signal on completion of the async operation to the execution context to resume the coroutine.

The execution context in this case could be the main thread, a pool, etc.

From that above mentioned C++ link:

>

The coroutine is suspended (its coroutine state is populated with local variables and current suspension point).
awaiter.await_suspend(handle) is called, where handle is the coroutine handle representing the current coroutine. Inside that function, the suspended coroutine state is observable via that handle, and it's this function's responsibility to schedule it to resume on some executor, or to be destroyed (returning false counts as scheduling)

4 hours ago
On 24/01/2025 9:12 AM, Sebastiaan Koppe wrote:
> On Thursday, 23 January 2025 at 17:14:50 UTC, Richard (Rikki) Andrew Cattermole wrote:
>> On 24/01/2025 4:55 AM, Sebastiaan Koppe wrote:
>>> I wouldn't dismiss it so easily. For one it explains the mechanism by which suspended coroutines can get scheduled again, whereas your DIP only mentioned the `WaitingOn` but doesn't go into detail how it actually works.
>>
>> Ahhh ok, you are looking for a statement to the effect of: "A coroutine may only be executed if it is not complete and if it has a dependency for that to be complete or have a value."
>>
>> The reason it is not in the DIP is because this a library behavior.
>>
>> On the language side there is no such guarantee, you should be free to execute them repeatedly without error. There could be logic bugs, but the compiler cannot know that this is the case.
>>
>> About the only time the compiler should prevent you from calling it is if there is no transition to execute (such as it is now complete).
> 
> No, that is not what I mean.
> 
> Upon yielding a coroutine, say a socket read, you'll want to park the coroutine until the socket read has completed. This requires a signal on completion of the async operation to the execution context to resume the coroutine.
> 
> The execution context in this case could be the main thread, a pool, etc.
> 
>  From that above mentioned C++ link:
> 
>> The coroutine is suspended (its coroutine state is populated with local variables and current suspension point).
>> awaiter.await_suspend(handle) is called, where handle is the coroutine handle representing the current coroutine. Inside that function, the suspended coroutine state is observable via that handle, and __it's this function's responsibility to schedule it to resume on some executor__, or to be destroyed (returning false counts as scheduling)

Right, I handle this as part of my scheduler and worker pool.

The language has no knowledge, nor need to know any of this which is why it is not in the DIP.

How scheduling works, can only lead to confusion if it is described in a language only proposal (I've had Walter attach on to such descriptions in the past and was not helpful).

3 hours ago
On Thursday, 23 January 2025 at 20:37:59 UTC, Richard (Rikki) Andrew Cattermole wrote:
>
> On 24/01/2025 9:12 AM, Sebastiaan Koppe wrote:
>> Upon yielding a coroutine, say a socket read, you'll want to park the coroutine until the socket read has completed. This requires a signal on completion of the async operation to the execution context to resume the coroutine.
>
> Right, I handle this as part of my scheduler and worker pool.
>
> The language has no knowledge, nor need to know any of this which is why it is not in the DIP.

Without having a notion on how this might work I can't reasonably comment on this DIP.

> How scheduling works, can only lead to confusion if it is described in a language only proposal (I've had Walter attach on to such descriptions in the past and was not helpful).

You don't need to describe how scheduling works, just the mechanism by which a scheduler gets notified when a coroutine is ready for resumption.

Rust has a Waker, C++ has the await_suspend function, etc.
1 hour ago
On 24/01/2025 10:17 AM, Sebastiaan Koppe wrote:
> On Thursday, 23 January 2025 at 20:37:59 UTC, Richard (Rikki) Andrew Cattermole wrote:
>>
>> On 24/01/2025 9:12 AM, Sebastiaan Koppe wrote:
>>> Upon yielding a coroutine, say a socket read, you'll want to park the coroutine until the socket read has completed. This requires a signal on completion of the async operation to the execution context to resume the coroutine.
>>
>> Right, I handle this as part of my scheduler and worker pool.
>>
>> The language has no knowledge, nor need to know any of this which is why it is not in the DIP.
> 
> Without having a notion on how this might work I can't reasonably comment on this DIP.
> 
>> How scheduling works, can only lead to confusion if it is described in a language only proposal (I've had Walter attach on to such descriptions in the past and was not helpful).
> 
> You don't need to describe how scheduling works, just the mechanism by which a scheduler gets notified when a coroutine is ready for resumption.
> 
> Rust has a Waker, C++ has the await_suspend function, etc.

Are you wanting this snippet?

```d
// if any dependents unblock them and schedule their execution.
void onComplete(GenericCoroutine);

// Depender depends upon dependency, when dependency has value or completes unblock depender.
// May need to handle dependency for scheduling.
void seeDependency(GenericCoroutine dependency, GenericCoroutine depender);

// Reschedule coroutine for execution
void reschedule(GenericCoroutine);

void execute(COState)(GenericCoroutine us, COState* coState) {
    if (coState.tag >= 0) {
        coState.execute();

        coState.waitingOnCoroutine.match{
            (:None) {};

            (GenericCoroutine dependency) {
                seeDependency(dependency, us);
            };

            // Others? Future's ext.
        };
    }

    if (coState.tag < 0)
        onComplete(us);
    else
        reschedule(us);
}
```

Where ``COState`` is the generated struct as per Description -> State heading.

Where ``GenericCoroutine`` is the parent struct to ``Future`` as described by the DIP, that is not templated.

Due to this depending on sumtypes I can't put it in as-is.

Every library will do this a bit differently, but it does give the general idea of it. For example you could return the dependency and have it immediately executed rather than let the scheduler handle it.

1 2
Next ›   Last »