proposal: Add coroutines #21

Open Jookia opened this issue on 5 Jul - 0 comments

@Jookia Jookia commented on 5 Jul

Yesterday I posted a proposal for adding continuations to NewLang and at the time I was writing I found it wasn't a really convincing case. Furthermore when asking Xogium about it they didn't really get it. So here's an alternative: Coroutines!

What are coroutines?

Coroutines are basically easy to use subprocesses that don't necessarily use operating system resources. You can spawn a coroutine to run some code. If they don't use operating system resources then there can be thousands of them running within a single process. They are implemented basically how a RTOS implements threads of execution: Stack switching.

In this case my proposal is to add a new keyword to NewLang: Spawn. Spawn will start a new coroutine and run a function in it. The coroutine is returned as a variable and can be used to communicate and manage the coroutine.

Coroutines have a global variable, ParentProcess. This can be used to talk to the process that created it.

Example: Exceptions

Let's say you're writing some code and you want to do error handling in one place. In most languages this is done through exceptions: You register a place to 'catch' an exception and code you run might 'throw' the exception. When throwing the catcher is immediately run, bypassing intermediate code.

We can do this using coroutines as follows:

  • Spawn a new process that runs some code
  • That code will message the parent process with an error
  • The parent process will respond to the error and kill the process

Here's an example using hypothetical syntax:

Function DoThing1 Do
  System Print StartText Doing some things... EndText
  ParentProcess Send StartText Big Error! EndText
  System Print StartText Things done! EndText
EndFunction
Function DoStuff Do
  StartNote All these might error, but it's ok, MyRunner will handle it EndNote
  DoThing1
  DoThing2
  DoThing3
EndFunction
Function MyRunner Do
  Set Child To Spawn DoStuff EndSet
  Set Error To Child Receive EndSet
  If Error Equals StartText Big Error! EndText
  Then Child Kill
  Else System Print StartText All good! EndText
  EndIf

In this case this program will execute MyRunner by:

  • Spawning a process named Child that will run DoStuff
  • Waiting for a message from Child
  • The runtime sees MyRunner is waiting so it switches to Child
  • Runs DoThing1
  • Prints "Doing some things..."
  • Sends the message "Big Error!" to ParentProcess which is MyRunner
  • The runtime switches back to MyRunner now that there's a message for it
  • MyRunner reads the message to a variable named Error
  • MyRunner checks if Error is "Big Error!"
  • It is, so MyRunner kills the Child process
  • Any cleanup need to be done by Child is done
  • MyRunner then continues on running

Other uses

I don't want to overcomplicate things by writing more examples, but here's some other cases this is useful:

  • Streams and pipelines that join together, like with Bash and Unix
  • Having some other code do tasks for you, such as opening a file
  • Writing code that waits for user input and having another process handle that logic

Here's some things it can't do compared to continuations:

  • Go back in time

Other solutions considered

For error handling, continuation passing style and things like monads could work instead.

@Jookia Jookia referenced the issue 9 days ago
Labels

Priority
default
Milestone
No milestone
Assignee
No one
1 participant
@Jookia