I would really like if the language reference[1] had a "rationale" or "principles" section describing the decisions at a high level. At the moment it dives straight into the minutiae of syntax, built-in types, etc.
The language marketing insists it is "data-oriented", even in the footer of every page. But I couldn't find any more detail on this.
My favourite example of this is Austral, which has a detailed rationale[2] that justifies the choices made and the tradeoffs. It really helped me decide whether I was interested in the language.
Odin, cited in the blog post, has a shallow rationale on its FAQ page[3], but seems to have had more time/maturity to document specific "data-oriented" features like built-in SoA[4].
Thanks for the feedback! I agree my documentation is very lacking in that department. I hope in the next few days to have a page in the documentation that describes my rationale, and the tradeoffs made during development.
Roc also is a great site on how to present a "new" language. Specially the sections that explain what they mean by being "fast", "friendly" and "functional".
Austral rational documentation is indeed really interesting. My preference goes into another direction (notably toward expression-based languages), but it's refreshing to read well explained design decisions.
The section about linear types is also a gem to this regard.
I would even consider this as a reference source to introduce the motivations and principles behind the Rust type system and borrow checker. Only the syntax would have to be made a bit more rusty.
> For many people, semicolons represent the distinction between an old and crusty language and a modern one, in which case the semicolon serves a function similar to the use of Comic Sans by the OpenBSD project.
That's a delightful sentence, and in context of how the design makes opinionated choices based on its goals entirely reasonable.
(I don't know if I'll agree with all of those choices after I've thought about them sufficiently to be comfortable having an opinion, but I do very much appreciate that they're explicit, deliberate, and explained)
It seemed inevitable that a new language would choose WASM as a runtime.
We get a bytecode runtime to rival JVM and CLR, but with a diversity of stake holders (no single vendor trying to push a language or enterprise offering), it's JITed even on Apple devices and on the damn web! Pretty amazing.
What makes me excited about this: Getting to poke around, at runtime, my compiled .NET C# code using PowerShell (in Snoop) was pretty eye-opening to me. The "standard" interoperability between PowerShell (Core?) and .NET objects as well, of course.
It feels great to have a common runtime making calling out to other languages so seamless. Yet it seems to me like it never reached the popularity it deserved, but maybe it will get another try, with a lot more enthusiasm (no more Oracle/MS brake-foot).
Wrong, Google drove NaCl for a long time (portable LLVM bytecode) but then Mozilla countered with asm.js which kickstarted and heavily influenced the development of Webassembly.
Exactly. Three things that should be on the front page of any new language: 1) examples of syntax (check), 2) quick start instructions (check), 3) short description of motivation/rationale including what other languages were considered and why do they fall short?
Those are all great questions. I will add to the docs to explain more details later, but for now:
1. It is value based, like C. There is obviously passing by pointer, but you do that explcitly.
2/3. Memory is manually managed. To make this easier, like Zig and Odin, everything that allocates should take an allocator as a parameter. This allocator can be the general purpose heap allocator, or it can be an arena, ring buffer, or even tracked allocations that can be freed all at once. More details on that to follow in the documentation.
4. It does have multi-threading support, thanks to the atomics WASM proposal. The standard library currently has support for basic multi-threaded primitives like mutexes, semaphores, and condition variables. Note, there is currently not async/await or any kind of concurrent execution.
5/6. It does have modern type features like sum types. It has Optional(T) and Result(Ok, Err) out of the box. That is the preferred method of error handling.
7. It is mostly statement oriented, but there are features like Elixir's pipe operator (|>) and if/else (value if condition else otherwise) expressions.
About 2/3, does the compiler / language somehow help me remember to free memory I've allocated, or avoid double frees? Are there smart pointers or sth like that? (I've been coding lots of C/C++ :-))
The largest project I have in Onyx is currently around 30000 lines (not all that large I know). That project on my Intel i7-1165G7 laptop compiles in about 80ms.
There are currently no large Onyx projects that can really test how this number scales, but I would guess the growth is not linear. So for an off the cuff estimated, I would say a million line project could compile in about 4-5 seconds.
Also worth noting that the entire compiler is currently single-threaded. So that number could get much better.
Clearly Wasmer wants to do WebAssembly. But for a whole new, general-purpose programming language, what's the case for that target, versus, say, LLVM intermediate representation?
Onyx is entirely independent from Wasmer. It is a separate project developed by me, over the past 3 years. It does however use Wasmer for running on Windows, MacOS, and optionally on Linux.
I started making Onyx because I simply wanted to create my own programming language for the fun of it. I choose WebAssembly as the target for my compiler because it was relatively easy to write my own full-stack solution, instead of relying on something like LLVM. That language evolved over the years until I had something I felt was worth sharing. When the Wasmer team reached out to see if I wanted to do a collaboration blog post, I said yes.
The main reason I didn't go with LLVM was simply because I wanted to write everything myself (for fun) and to have a super-fast compiler. LLVM is not the fastest backend, but it is understandable for all the optimizations that it does.
Well it's Friday and i have some time to kill. Before i start, creating a language is hard and i am just making random comment on the internet.
From the "why webassembly" section :
> When making a programming language, you need to decide how your programs will actually be executed.
In abstract maybe, and obviously some language features might make an interpreter or a compiler harder/easier to make. But in general and in practice the language semantic and the "execution mode" can be treated independently. Some of the languages mentioned even have multiple style of execution (AOT, JIT, interpretation , compilation etc...)
> Onyx does not rely on libraries like LLVM to generate its code, because WASM is so simple to target.
In term of correctness maybe. It will be interesting to see what happens as performance and more complex code pattern need to be supported. Most language evolve some type of high level representation between the AST and they target of choices for language specific transformation and error reporting (SIL,clangIR and HIR? not sure about that last one).
>My strategy was to wrap libwasmer.a, the standalone library version of Wasmer, into my own custom WASM loader, to allow imported functions to be linked against native libraries
Doesn't this both limit the portability and introduce potential security risk (and thus negating the whole point of wasm) ?
I think the inter reaction with the outside world is what WASI and the other is trying to address.
The most interesting part of this language to me is that it's streamlined for WASM compilation, and I think that should be put up front more than it is
When I see "powered by WebAssembly", I take it as a sign that the language is going to be designed around WebAssembly's VM interface rather than the implicit standard of the C memory model and POSIX-like API which basically all popular programming languages are designed for. Even languages like Python have the concepts of stdin/stdout/stderr, a filesystem, threads, and a single globally accessible heap baked into their design. It would take a lot of work to amend Python's design to be able to easily use features that are somewhat unique to WebAssembly like the various things a .wasm file can import or export. As it stands, languages like Python can be run on WASM, but they use inelegant hacks in order to be able to replicate the execution environment features that their interpreters require such as malloc, and usually it is assumed that the target will be WASI. A language that is designed for WASM from the ground up would make it so that WASM can be used to its fullest potential as a lightweight execution environment that makes extremely minimal assumptions about what interfaces are going to be provided to the program.
While Onyx does have core library support for doing standard POSIX things like stdin/stdout/stderr, file operations, and networking, Onyx can be used in an entirely different environment without any of these things. In fact, the standard libraries are (almost) entirely separate from the compiler (i.e. the compiler makes no assumptions about what the standard library is), so if the standard library does not suite your use case for one reason or another, you can write your own. It will be a bit of work, but there would be nothing in your way.
I don't think i fully agree. Yes it might be possible to design a programming language that have a better synergy with wasm than the one we currently have, but IMO this won't have a particularly big impact on dev prod or performance.
wasm was design to be the target of current languages, so in a sense it does capture a lot of things that already exists or can be mapped easily to existing languages. Designing against wasm might create a case of overfiting. But only the future will tell.
In the "on top of WASM" case, I imagine that the advantage of Python and JS will be exactly the same as the "not on top of WASM case". Namely, mainly development convenience at the cost of performance.
I quite like its syntax. I also don’t think the target audience is beginners, this seems like a passion project someone is making for themselves and people who have a similar taste to them.
The language marketing insists it is "data-oriented", even in the footer of every page. But I couldn't find any more detail on this.
My favourite example of this is Austral, which has a detailed rationale[2] that justifies the choices made and the tradeoffs. It really helped me decide whether I was interested in the language.
Odin, cited in the blog post, has a shallow rationale on its FAQ page[3], but seems to have had more time/maturity to document specific "data-oriented" features like built-in SoA[4].
[1] https://docs.onyxlang.io/book/Overview.html
[2] https://austral-lang.org/spec/spec.html#rationale
[3] https://odin-lang.org/docs/faq/
[4] https://odin-lang.org/docs/overview/#soa-data-types
https://www.roc-lang.org/
Austral rational documentation is indeed really interesting. My preference goes into another direction (notably toward expression-based languages), but it's refreshing to read well explained design decisions.
The section about linear types is also a gem to this regard. I would even consider this as a reference source to introduce the motivations and principles behind the Rust type system and borrow checker. Only the syntax would have to be made a bit more rusty.
[1] https://austral-lang.org/spec/spec.html#rationale-linear-typ...
That's a delightful sentence, and in context of how the design makes opinionated choices based on its goals entirely reasonable.
(I don't know if I'll agree with all of those choices after I've thought about them sufficiently to be comfortable having an opinion, but I do very much appreciate that they're explicit, deliberate, and explained)
Similar to what you are suggesting.
We get a bytecode runtime to rival JVM and CLR, but with a diversity of stake holders (no single vendor trying to push a language or enterprise offering), it's JITed even on Apple devices and on the damn web! Pretty amazing.
What makes me excited about this: Getting to poke around, at runtime, my compiled .NET C# code using PowerShell (in Snoop) was pretty eye-opening to me. The "standard" interoperability between PowerShell (Core?) and .NET objects as well, of course.
It feels great to have a common runtime making calling out to other languages so seamless. Yet it seems to me like it never reached the popularity it deserved, but maybe it will get another try, with a lot more enthusiasm (no more Oracle/MS brake-foot).
What problems does this uniquely solve that other languages & environments don't?
Basically, it's really all about certain WASM use cases, and everything right down to its memory management strategy is optimized for those cases.
It looks like it fits pretty squarely in the "if you want to do C level programming but you'd also like nice lambdas, sum types, and type inference"
>A modern language for WebAssembly.
[0] https://github.com/onyx-lang/onyx
1. Is it value based (C++, Rust, Go, TCL) or reference based (basically everything else).
2. How is memory freed? GC?
3. If GC how do you deal with the fact that Wasm GC is still in progress?
4. What about concurrency? Is it single threaded?
5. How does error handling work?
6. Does it support modern type features - Option<>, sum types, etc.
7. It's imperative, does that mean things that should be expressions (e.g. if/else) are statements?
1. It is value based, like C. There is obviously passing by pointer, but you do that explcitly.
2/3. Memory is manually managed. To make this easier, like Zig and Odin, everything that allocates should take an allocator as a parameter. This allocator can be the general purpose heap allocator, or it can be an arena, ring buffer, or even tracked allocations that can be freed all at once. More details on that to follow in the documentation.
4. It does have multi-threading support, thanks to the atomics WASM proposal. The standard library currently has support for basic multi-threaded primitives like mutexes, semaphores, and condition variables. Note, there is currently not async/await or any kind of concurrent execution.
5/6. It does have modern type features like sum types. It has Optional(T) and Result(Ok, Err) out of the box. That is the preferred method of error handling.
7. It is mostly statement oriented, but there are features like Elixir's pipe operator (|>) and if/else (value if condition else otherwise) expressions.
There are currently no large Onyx projects that can really test how this number scales, but I would guess the growth is not linear. So for an off the cuff estimated, I would say a million line project could compile in about 4-5 seconds.
Also worth noting that the entire compiler is currently single-threaded. So that number could get much better.
I started making Onyx because I simply wanted to create my own programming language for the fun of it. I choose WebAssembly as the target for my compiler because it was relatively easy to write my own full-stack solution, instead of relying on something like LLVM. That language evolved over the years until I had something I felt was worth sharing. When the Wasmer team reached out to see if I wanted to do a collaboration blog post, I said yes.
The main reason I didn't go with LLVM was simply because I wanted to write everything myself (for fun) and to have a super-fast compiler. LLVM is not the fastest backend, but it is understandable for all the optimizations that it does.
From the "why webassembly" section :
> When making a programming language, you need to decide how your programs will actually be executed.
In abstract maybe, and obviously some language features might make an interpreter or a compiler harder/easier to make. But in general and in practice the language semantic and the "execution mode" can be treated independently. Some of the languages mentioned even have multiple style of execution (AOT, JIT, interpretation , compilation etc...)
> Onyx does not rely on libraries like LLVM to generate its code, because WASM is so simple to target.
In term of correctness maybe. It will be interesting to see what happens as performance and more complex code pattern need to be supported. Most language evolve some type of high level representation between the AST and they target of choices for language specific transformation and error reporting (SIL,clangIR and HIR? not sure about that last one).
>My strategy was to wrap libwasmer.a, the standalone library version of Wasmer, into my own custom WASM loader, to allow imported functions to be linked against native libraries
Doesn't this both limit the portability and introduce potential security risk (and thus negating the whole point of wasm) ?
I think the inter reaction with the outside world is what WASI and the other is trying to address.
(Great work on that front btw Onyx Team)
But! When I see powered by WebAssembly. I can't see a good reason to choosing a unique language when any language in theory can target WASM/WASI.
In other words Javascript/Python is looking at your lunch and is very hungry.
While Onyx does have core library support for doing standard POSIX things like stdin/stdout/stderr, file operations, and networking, Onyx can be used in an entirely different environment without any of these things. In fact, the standard libraries are (almost) entirely separate from the compiler (i.e. the compiler makes no assumptions about what the standard library is), so if the standard library does not suite your use case for one reason or another, you can write your own. It will be a bit of work, but there would be nothing in your way.
Any time I see a language that compiles directly to WASM my instinct is that it will compete with Zig, Rust or C/C++/emscripten.