I see mentions of "effect interpreters" all over the place, including the planned changes page of the Roc website, the Rust platform template, and countless references across Zulip going back nearly 2 years ago.
I know this is a team with finite time and resources so I'm definitely not throwing shade here, but I have to know: what is preventing this work from moving forward? From my very limited understanding, it seems like effect interpreters will have a significant impact on platform design and development. Writing a platform today is already difficult without documentation, and it's made even more daunting by the fact that a mysterious feature called "effect interpreters" with an unknown timeline will make whatever I'm learning right now obsolete. To be completely honest, it's a bit frustrating that something this fundamental to Roc itself hasn't settled and apparently isn't being prioritized, because we're spending lots of energy on arguably less important things like camelCase vs snake_case, function calls with spaces vs parens, etc.
Maybe Zulip chatter isn't representative of the real work that happens behind the scenes, but as an outsider, these priorities feel a bit out of wack. I apologize if my message comes across a bit strong here (although I do feel strongly about it). I'm happy to be told that I'm wrong, that effect interpreters won't actually impact platform development that much, and that syntax issues actually do matter more than effect interpreters (I have seen the quote from Louis Pilfold). I have massive respect for what you all do and there's no language that I'm more excited to use than Roc! I'm really just trying to make sense of this issue, and see if there's anything I could do to help solve it.
I have a mix of answers.... let me try and give a solid explanation
I apologize if this ends up being out of order....trying to congeal the best way and order to explain this is not obvious
Firstly, what are effect interpreters:
They are just state machines that enable async io. When you use async they generate stackless coroutines. This is a fancy way to say they automatically generate suspendable state machines. They run code on the main stack until they hit a await
. Once an await
is hit, the entire stack is washed away only leaving behind the minimal state to know what io operation to start and what continuation to run once io is complete.
From a platform perspection. effect interpreter just means that roc collapses all of its interface into a state machine like other async systems. This enables roc to play nice with other async systems.
If you look at basic webserver today, rust is async, but roc is not. As such, roc is constantly breaking the async model in ways that totally could ruin performance. If roc sleeps for 100ms, it blocks whatever thread it is on for 100ms. Effect intepretters are required to actually allow rocs io to run async. It would be a huge performance win for the current version of basic webserver. Especially when it comes to anything async that takes a while (like waiting 200ms for a web request).
Why don't we have them yet?
Well, I personally have pushed on them a few different times. So have a few other core roc contributors.
The real problem is that the run into some harsh edge cases in the type system that are non-trivial to fix.
Where these bugs happen are probably the most specialized part of the roc compiler that most people are not capable of diving into and fixing. I definitely don't have the time and energy to gain the expertise to fix these issues.
The core contributors to roc that would be most capable of fixing these issues have been really busy and have not contributed much code to roc in general for a while now (though they definitely continue to bless us with great insights into what would be required to fix these issues).
So the main issue is that no one currently is available with the expertise and time to fix these issues
On top of that, effect interpreters though important for unlocking async io just aren't that important at the current state of roc.
Most apps are not really doing anything super performance heavy today. Even basic webserver with the limitations around async runs ok.
What I do think is a failing on my part personally and something the core contributors could have done better as a whole is document and educate on the current platform interfaces.
I am probably the local expert on platform interfaces and building platforms....I have taught it to a ton of people and helped debug a ton, but I still have not documented any of it and have continued to push that off.
There is also a ton of very useful work that way more people could work on around glue generation. It could make platform development a ton easier, but it needs a lot of love. I work on platforms all the time, but roll my own glue cause glue just isnt good enough yet.
Yeah, if we as developers try to optimize for the majority of the parts of Roc that people will interface with, that's generally a good dev experience for writing simple tools (CLIs, webservers, websites, etc.) and understanding the shape of Roc. So though Roc is at a high level designed with platforms in mind, 99% of people will just be using basic-cli
.
I think roc is at the point that we really should promote and document a lot more of the platform development cycle. @Luke Boswell has done a great job at trying to make tons of examples in this domain.
Meaning it is more useful for us to work on the parts of Roc that people will interact with in the near future, and especially with the difficulties/opaqueness of implementation that Brendan laid out above, this isn't that high of a priority.
Now for the biggest kicker.... We may not need effect interpretters anymore.
That comes with a big caveat. The correct statement is more so: In the medium term, recent changes around purity inference and synchronous io have enabled alternatives to effect intepretters that can be similarly performant. While we may still want effect interpretters in the long run to better interface with async systems, we may not need it for the general case of platform development.
Essentially, we now have removed a lot of the state wrangling in roc and have direct synchronous io. This originally was thought to be invalid cause pure languages without side effects need to return effects which fundamentally requires building up async io. Turns out with purity inference, you can get the benefits of both purity and simple direct synchronous io.
As such, we could, for example, setup a platform that mirrors the goroutine system where all io is synchronous in api, but under the hood is running async io due to stackful coroutines.
More on this at #gatherings > Roc Online Meetup Nov 2024
Thanks for explaining all this Brendan :heart:
Thanks for this Brendan, this is very insightful. Still digesting it, but I have a few immediate questions:
I think hosted will stick around (though we still want to change how linking is done)
I think effect interpretters likely would be opt in
Last updated: Jul 05 2025 at 12:14 UTC