-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Relationship of Component YAML vs. external implementation #5
Comments
I'll hazard a guess, maybe this will illuminate my (mis)understanding or at least give another context within which to actually answer. Answer?One way to enable libraries/modules/components written one language to be used by another is to force them to interact with each other via a common-denominator language. Probably C. But C is hard, and especially when trying to wrap a language that isn't already compiled to a traditional "object file" (say wrapping JS or Lua, vs. wrapping C/Go/Rust) the wrapper is pretty much just tons and tons of ugly boilerplate (e.g. "extern C" functions wrapping C++ method calls manipulating V8 API representations of state/logic in the actual JS context). So rather than making Lua/Lisp/Verilog programmers also learn to write C, and that in the most painful of circumstances, we will have everyone write Component YAML instead. And then Fractal will generate the underlying common-denominator wrapper implementation for us. Doing this "only as simple as possible" results in the apparent complexity of the situation described above, where some snippets of the native/wrapped language must necessarily leak out into the meta-binding artifact. Is that the situation? Could a different model avoid the "leakiness" of the current approach? |
Your guess is about right. The overarching framework is language-agnostic, but you want to bind it to code written in C (substitute any other language in this paragraph), you eventually want to call C code. Well, there's this existing syntax for making C calls, and a tool that already knows how to compile it, known as C and a C compiler, so just embed snippets of C, and YAML's block quotes make it look somewhat reasonable. The intention of YAML was that it's not "yet another language to learn". Not super common in JS circles (JSON would be ugly here), but they've probably heard of it, and rubyists are more likely to know it. However, once we go this far putting semantics on top of YAML, it almost is a new language, and one with suboptimal syntax, at that. So I've been coming up with alternatives. One is to be able to do Rust has strong support for macros, including procedural macros, which are compiler plugins of with Rust code that transforms the token tree. These macros could define an interface, with Rust code embedded, all in a To use a component in JS we'd want to leverage the JS-native APIs like EventEmitter, DuplexStreams, and plain callbacks as much as possible, but defining components in JS needs something declaring the component interfaces that can be processed at compile time without executing the JS in order to generate the C-callable function stubs for the other components to link to. Going beyond just macros, an academic project that did similar componentization invented a dialect of C called nesC for this purpose. That scares some people off, and since we want to support many languages, it's even tougher, because we really don't want to also have and maintain compilers for nesJS, nesRust, and nesLua too. |
Note that the definition of the interface and the implementation are mixed together. I've thought about splitting that -- "Here's the interface any SPI controller offers in abstract form; here's a C implementation of that for the LPC1830 SPI peripheral; here's a Rust implementation for SAMD21". One problem there is when we don't actually care if an implementation covers the whole interface; just the parts that are used. If we come across a bad SPI controller that doesn't support SPI mode 2, that should only be an error if you stack a component on top that uses that mode. If we can check all this at compile time, it's effectively compile-time duck typing. |
I'm confused by why in the SPI example component there are code snippets like
on_begin: enable_spi(self)
andconfigure: self->SPI->CDIV = calculate_clock(clock_speed);
.Or perhaps at a higher level my question is/are/s/he:
The text was updated successfully, but these errors were encountered: