Hacker News new | past | comments | ask | show | jobs | submit login
Mu: Sketching out a minimal system programming language (akkartik.name)
102 points by signa11 on Nov 22, 2019 | hide | past | favorite | 17 comments

> Performance is not a priority.

I like your outlines so far. It is very interesting -- even if it probably will fail eventually.

I am only concerned with this quoted guideline. Performance should always be a priority. Your other guidelines -- keeping the translation simple and transparent -- already put a constraint on the aesthetic. You can't allure users by hiding complexity beneath something. So if you also don't promise users performance, what good is your language to a user (unless he is a poet)?

I feel that you are adding this guideline only because you are thinking about taking the dynamic approach to memory safety rather than the Rust approach. That is fine as long as either approach is only an add-on rather than the permanent infrastructure of your language. If they are, then I am afraid your language will just reduce back to one of the language that is hardly worth to checkout.

My suggestion is always to put performance as your priority. Always start with solutions that performs, then work on enhancing your language to express the same solution easier.

You seem to be assuming everybody in the world always wants the same things, which is demonstrably false. There were excited communities of people using Lisp in 1962 and Java in 1997. Both were significantly slower than mainstream platforms of the time. There are many platforms today that provide performance, and people who need performance will use them. I can't compete with them. Mu is for people who don't need performance quite so badly, and who are willing to trade performance for other benefits.

Also, the word "priority" means relative importance. Too many priorities are equivalent to no priorities. Performance not being a priority just means other aspects are more important, not that performance will be glacial. Indeed, a lot of performance stems from doing less, and I fully expect fewer layers of abstraction to keep Mu quite competitive for many tasks. But that will happen naturally without me needing to push on it.

Ages ago I wrote "type safe macro assembler" on a postit note, and then never did anything with this idea. It looks like someone has taken it a lot further.

Reminds me a bit of LLVM-IR.

One major issue that causes C compiler optimizations to be necessary are impedance mismatches between the architecture and the language. bulitin/intrsinsic functions are the "work around" for this, but they tend to be very non-portable (between compilers, and even sometimes between backends on the same compiler).

If you do this in C, most compilers will optimize into a 64-bit rotate:

    (n << d)|(n >> (64 - d))
But that requires an optimizer.

Many compiler vendors have an extension that will compile to a rotate instruction, but they tend to differ from one compiler to another.

Author here. You didn't really ask a question, but I thought I'd mention a few things that may be related.

1. Mu isn't intended to be portable. There are no other backends, not even other processor families. Though you still have to put up with other processors within the same family, if it's a new instruction that older processors don't have. So far it just focuses on lowest-common-denominator 32-bit instructions.

2. The whole goal with Mu is to eliminate impedance mismatch with the architecture. It's relatively straightforward to add another instruction at the Mu level called 'rotate', and have it code-generate the appropriate x86 instruction. That seems less convoluted than assuming a fixed language and compiler and expressing a rotation out of 4 binary operators.

3. Finally, there's also the option of writing some functions in the 'machine code' level called SubX. Functions generated by Mu and SubX will freely inter-operate, though SubX functions lack safety guarantees.

Thanks for the clarifications!

I'm surprised by the assertion that you can't use expression syntax because you would then be forced to implement common subexpression elimination. You don't: Just run your C compiler with -O0 and you should get expressions without CSE.

What you do give up if you use expression syntax is control over register allocation, unless you specify that expressions are evaluated via the stack and a designated accumulator. Or you could annotate every single subexpression with the register to put it in. I'd agree that this might not be a good fit for the overall design of this language, but I don't think CSE is to blame.

Besides that, the description of the calling convention could use a few more details. Are all registers except the stack pointer and the return value(s) callee-saved? Can you return multiple values? Can each function choose where to return its results, or is eax fixed as the return register? The "may be just documentation" comment confuses me.

As I reread that passage now, there's some redundancy in my prose. The first time I mention CSE I'm talking specifically about optimization and the need to avoid the temptation to build an optimizer over time. The second time I don't, but I'm still implicitly assuming the need to optimize. I should clean that up.

Calling convention: yes, all registers are callee-saved. Multiple values can be returned. (Up to 6, I guess?) Since the callee saves registers, any returned registers are just not saved and restored. A function can return in any register, though I use `eax` by convention. Since miscommunication between caller and callee about what registers are clobbered can lead to subtle bugs, I require the caller to also show the correct register being written to. Does that help? I'll work this in. Thanks!

Yes, that's great, thanks!

I wonder what Mu will offer that Rust does not.

It sounds much, much simpler than Rust- it's leaving register management to the programmer:

"Mu will be a manually register-allocated language. It will still check your register allocation and flag an error if multiple variables overlap on the same register. But it's up to the programmer to manage registers and spill to memory when necessary."

It looks like it's shooting to be a lot lower level than Rust, probably Zig is a more apt comparison.

It looks like it's shooting to be even a lot lower level than Zig.

Yeah. (Author here.)

The goal is not a specific level, just to do as much as possible with local rewrite rules. That gets some surprisingly high-level features, but the result overall will still seem fairly low-level.

(And then there's all the runtime overheads. Mu isn't trying to compete on performance.)

Any real thing to show or just poor dream?

Please don't post dismissive comments like this to HN. Maybe you don't mean to be a jerk, but on the internet that's how it resonates. As the site guidelines say: "Please don't post shallow dismissals, especially of other people's work. A good critical comment teaches us something."


This post was a design document for soliciting feedback. You can see the progress on the implementation at https://github.com/akkartik/mu/blob/master/apps/mu.subx (colorized version: http://akkartik.github.io/mu/html/apps/mu.subx.html)

So far I've made some progress with code-generation. Next I plan to switch gears and work on the parser. I try to post updates on Mastodon: https://mastodon.social/@akkartik/103052146965158614

Applications are open for YC Summer 2023

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact