splitting this off from #ideas > platform specific data structures
Brendan Hansknecht said:
It is arbitrary CFFI, but only for platforms.
so I think this idea is worth discussing, but I definitely think this would have major ecosystem implications (some maybe positive, some maybe negative)
for example, we've talked before about demand for LAPACK bindings, which is ~1.5K linear algebra functions implemented in about 600K LoC of FORTRAN plus inline assembly
so here is a sequence of events that could plausibly happen if we add this feature:
basic-cli-lapack, basic-cli-lapack-v6.7, basic-cli-blas, basic-cli-blas-and-lapack, etc.so on the one hand, it would be cool to unlock those use cases
on the other hand, I don't like the idea of platforms forking just for the sake of exposing a different mix of non-I/O C FFI things
the nice thing about I/O is that it all boils down to a small, finite set of OS syscall wrappers, and everything else is a convenience wrapper around that - so I/O doesn't have that potential "ecosystem explosion" problem, and it also doesn't have the problem of side-effecting functions claiming to not be side-effecting
Couldn't this concern already happen just wrapped in tasks?
Push to implement the full set of lapack tasks
totally, but the downside of having to do all math using tasks creates an incentive to port those functions to pure Roc instead, even if they're not quite as fast due to missing out on inline assembly optimizations (but then again, the Task state machine probably has more overhead, so the pure Roc ones might actually be faster than that in practice)
the outcome I would want to see is that we end up with pure Roc linear algebra libraries that are fast enough in practice for the use cases where people would want LAPACK or BLAS
and I think it's healthy that the way FFI works today creates an incentive structure that rewards someone for doing that
I think that's fair, but I think it greatly hurts the ability to interface with and interact with many types.
so I have to admit, I don't totally understand why that would be
For example, say i have a c platform that already uses Blas or lapavk and i want to move some code into roc. I need that roc code to directly work on the Blas/lapack types. So I am stuck using tasks for everything and It makes things clunky enough that roc probably isn't work using.
I guess if I'm sending a data structure from the host to the platform which uses unions and/or pointer packing and/or needs to do unsafe pointer dereferencing a lot becuase bounds checks are too expensive?
In general think about any sort of embedding case where roc is not the main language, it is just a plugin language. The main project will not contort itself to use roc types. Roc needs to be able to use the host types.
No one is going to rewrite bevy to internally use roc types, but someone might enjoy writing a roc plugin that uses the existing bevy types.
yeah I appreciate that :thumbs_up:
That is the main use case we want to enable. I am not sure how to enable It without also enabling generic ffi.
I'm curious what your thoughts are on the LAPACK example concern
e.g. do you think it's a significant concern but worth it if it happens? or don't think it's a significant concern in practice? (like it would be fine if that happened)
or it would be bad, but worth it for the sake of enabling more use cases
another point to consider: a platform which offers (for example) functions for synchronous global mutable state access, and then that gets popular and a significant portion of the library ecosystem is built around requiring that
for example, someone would probably do that to get locale and also for synchronous random number generation
Hmm...yeah, i guess this plus module params makes everything a lot more concerning cause It enables Amy library to explicitly depend on many things that should be effects.
yeah
So I didn't want to fill this thread with my nooby questions or nooby suggestions, but I had an idea while DMing Brendan which is worth mentioning here:
What if we just prevented "FFI Modules" from being injected? Could we not just make an exception in the implementation of module params? And then later figure out how it could still be implemented while also mitigating abuse use cases, if people really want it. It might not come up as a requirement at all.
Brendan also mentioned that this "would need to be a recursive check. No function that calls and FFI function can be injected".
also module params are essentially syntax sugar
you can always have your functions take an extra argument, namely another function which the caller provides
(module params essentially do that for you behind the scenes)
so people could still implement side effecting functions, they'd just have to take an extra argument :sweat_smile:
For sure, but at least It would be a much bigger hassle which would hopefully reduce how often It happens
Like might be enough to avoid It becoming common, but yeah, not a true guarentee at all.
I don't know much about this topic, but how much code analysis could we do on the code that every C capable language compiles to? Like I could theoretically look at a Rust method or function and just say "if all these parameters are immutable, then this function is pure". We obviously don't want do that on a per language basis, but If you could do that on the bit code or generated C (maybe we can make sure certain opcodes are not present), then we could automatically enforce purity laws at compile time.
That'd be hard, and also the motivation for this idea is to allow platforms to use impure implementations as long as they provide a pure interface.
Sky Rose said:
That'd be hard, and also the motivation for this idea is to allow platforms to use impure implementations as long as they provide a pure interface.
Oh thats interesting, im not familiar with functional programming (Roc would be my first tbh) so what would a pure interface look like?
The lapack example, and the plausible sequence of events that @Richard Feldman listed, would suggest we would benefit from having some way to integrate with [pure] libraries without requiring support from the platform.
peeps said:
Oh thats interesting, im not familiar with functional programming (Roc would be my first tbh) so what would a pure interface look like?
Roughly put: pure functions can be memoized. If you (given enough memory) could implement the function as a table lookup, it's pure. A table lookup always returns the same value for the same parameter and it doesn't change the parameter.
Last updated: Jun 16 2026 at 16:19 UTC