*Update on the Mu computer's memory-safe language*

Progress has been slow over the holiday season because I've been working on a paper about Mu for 2020.programming-conference.or

But functions can now return outputs.

```
fn foo a: int -> result/eax: int {
result <- copy a
increment result
}
```

Project page: github.com/akkartik/mu#readme

Sources for the memory-safe language, now at 5kLoC: akkartik.github.io/mu/html/app

Caveats: no checking yet, only int types supported.

*Update on the Mu computer's memory-safe language*

Still no type-checking or memory-safety, but we can now write any programs with int variables.

There's still no 'var' keyword, so we can't define local variables yet. But that's not insurmountable; just pass in extra arguments for any space you want on the stack πŸ˜€

```
result <- factorial n 0 0 0
```

Show thread

*Update on the Mu computer's memory-safe language*

Basic language is done! Here's factorial. (Compare mastodon.social/@akkartik/1027.)

Still todo:
- user-defined types
- type checking and memory-safety

In other words, I'm about a third of the way there πŸ˜‚ More detailed todo list: lobste.rs/s/pv8jpr/what_are_yo

(More details on the Mu project: akkartik.name/post/mu-2019-1. Repo: github.com/akkartik/mu)

Show thread

A brief timeline of the Mu computing stack

Jul 6, 2014: commit 0, tree-based interpreter for a statement-oriented language (github.com/akkartik/mu)

Jul 19, 2017: commit 3930, start of SubX machine code (akkartik.name/post/mu-2019-1)

Sep 20, 2018: started building SubX in SubX (mastodon.social/@akkartik/1007)

Jul 24, 2019: SubX in SubX done, commit 5461 (mastodon.social/@akkartik/1024)

Oct 2, 2019: started designing the Mu memory-safe language (akkartik.name/post/mu-2019-2)

Oct 29: started akkartik.github.io/mu/html/app

Show thread

I'll be in Porto, Portugal on Mar 24 to present a paper on Mu at the Convivial Computing Salon: 2020.programming-conference.or

Hoping for some great conversation and disagreements.

Show thread

*Update on the Mu computer's memory-safe language*

Mu just got its first couple of non-integer types: addresses and arrays. As a result, the factorial app can _finally_ run its tests based on command-line args.

akkartik.github.io/mu/html/app

Addresses are accessed using a '*' operator. Arrays are accessed using an 'index' instruction that takes an address (addr array T) and returns an address (addr T).

Literal indexes aren't supported yet.

Open q: indexing arrays of non-power-of-2 element sizes.

Show thread

*Update on the Mu computer's memory-safe language*

Still no type-checking or memory-safety, but we have partial support for arrays and product types. Still several sharp edges:

- can't index an array with a literal
- can't index an array with non-power-of-2-sized elements
- can allocate but not use arrays/records on the stack

My todo list is growing. But work per item is shrinking. Hopefully there's an asymptote.

(More details: akkartik.name/post/mu-2019-1. Repo: github.com/akkartik/mu)

Show thread

*Update on the Mu computer's memory-safe language*

Arrays and product types are now done. Any remaining rough edges are working as intended πŸ˜„ Only hex literals, for example.

What's left? Actually making it safe.

Complexity outlay so far: 16k lines of code, but only 6.5k if you exclude tests. Tests get _very_ repetitive in machine code. Hopefully we won't need another 15k LoC.

Example program: akkartik.github.io/mu/html/app

(More details: akkartik.name/post/mu-2019-2. Repo: github.com/akkartik/mu)

Show thread

The Mu compiler summarized in one page: akkartik.github.io/mu/html/mu_

More details: akkartik.name/akkartik-convivi

Repo: github.com/akkartik/mu

(Brief update since there isn't much to report: I'm working on safe heap allocations as described in the paper. But it's slow going because of life and the need to unwind some past decisions.)

Β· Β· Web Β· 1 Β· 1 Β· 1

I'm back from a death march.

Mu is a safe language built in machine code, translating almost 1:1 to machine code. A key check is for use-after-free errors, using a second address type (akkartik.name/akkartik-convivi, section 4.4)

I spent the last 2 months switching all of Mu's implementation to this scheme. It was a tough time: lobste.rs/s/vcx5vu/what_are_yo. But now I know it works (with 10-15% slowdown), and Mu functions calling low-level libraries should behave unsurprisingly.

github.com/akkartik/mu

Show thread

I'm starting to build some simple apps in Mu, my memory-safe language that translates 1:1 to machine code.

Today I built a program to print a file to screen: akkartik.github.io/mu/html/app

Experience report: github.com/akkartik/mu/commit/

Also:
- I fixed a bug in the process: github.com/akkartik/mu/commit/
- I wished I already had clobbered-variable warnings.
- I wished I had type checks.

All in all, this language isn't ready for others yet. I'm constantly inspecting the code generated by the translator.

Show thread

A new day, a new app

A text-mode paginator for text files. Think `more`, but no ncurses, no termbox, no libc, just Linux syscalls.

2-minute demo video: archive.org/details/akkartik-2

App sources: akkartik.github.io/mu/html/app

Repo: github.com/akkartik/mu

Show thread

It's amazing how much you can do layout-wise with just plain text. Pictured in this toot:

Alice in Wonderland by Lewis Carroll

Poems by e e cummings (en.wikipedia.org/wiki/E._E._Cu)

Show thread

My text-mode paginator for text files implemented all the way up from machine code now supports a tiny subset of Markdown syntax. Screenshots below.

The code is terribly ugly, and there are zero tests. But it did help flush out three bugs in Mu. Next steps:

- Build out the compiler checks I missed the most.
- Implement a fake screen and keyboard so I can write tests for this app.
- Throw the app away and redo it right.

(Background: akkartik.name/akkartik-convivi. Repo: github.com/akkartik/mu)

Show thread

Why do programming languages require us to specify what modules we use? I think that stuff is easy to deduce. Even in machine code.

archive.org/details/akkartik-2

cc @s_ol

Show thread

I spent the last few days implementing a 'byte' type in Mu.

For the most part, Mu is exclusively 32-bit. No long/short nonsense here. However, I do like strings. Eventually even UTF-8 strings. So, minimal byte support. Mostly they behave like 32-bit values. You can't store them on the stack. (Because x86 reasons.)

As a test, I built a little calculator app: akkartik.github.io/mu/html/app. This app also shows off multiple return values.

Read more: github.com/akkartik/mu

cc @s_ol

Show thread

*Update on the Mu computer's memory-safe language*

Mu now checks all function calls.

Pass in the wrong type = error.
Save a result to the wrong type = error.
Save a result to the wrong register = error.

There are automated tests for error messages.

I estimate this change protects against 60% of the most common mistakes. Checking the most recent variable in a register should provide another 20%. And I hopefully have TODOs for the remainder to gradually whack away.

github.com/akkartik/mu

Show thread

*Update on the Mu computer's memory-safe language*

Mu now checks for most variable accesses if the variable is still live, and it's register hasn't been clobbered by some other variable. The extra-burdensome parts of programming in Mu are hopefully now not very burdensome.

Next up: testable syscalls for screen and keyboard. But I might take a break first. My RSI has been acting up.

github.com/akkartik/mu

Show thread

*Update on the Mu computer's memory-safe language*

Since the language is starting to seem stable, and the error messages have been getting better, and I managed to build some little programs without _too_ much trouble, I figured it was time to start actually _talking_ about the Mu language in the documentation. So make way SubX, and yield center-stage to Mu.

github.com/akkartik/mu/blob/ma

github.com/akkartik/mu/blob/ma

Show thread

*Update on the Mu computer's memory-safe language*

Mu now type-checks calls to functions implemented in unsafe SubX machine code. I have to provide signatures explicitly, and they look like this:

akkartik.github.io/mu/html/400

github.com/akkartik/mu

Show thread

*Update on the Mu computer's memory-safe language*

I've been thinking lately about spreadsheets. I don't really use them, but I'm trying to understand why they're so popular. As part of that, here's a rudimentary little demo of what a spreadsheet for trees might look like: archive.org/details/akkartik-2

No idea yet where I'm going to go with it, but so it goes. I'm now an existence proof that it's possible to build prototypes in not much more than machine code.

github.com/akkartik/mu

Show thread

*Update on the Mu computer's memory-safe language*

Mu now has streams: akkartik.github.io/mu/html/402

I had to really force myself to do this. Streams are generic types, but support for them is hard-coded into the language (just like arrays, and just like in Go). If I need a third generic type I'm going to think hard about just supporting generic type definitions. But my mantra today: YAGNI, YAGNI.

(Mu already supports generics in function declarations.)

github.com/akkartik/mu

Show thread

*Update on the Mu computer*

Mu now has support for Unicode. Just graphemes that map to single code points; no combining characters.

Mu also is starting to gain a fake screen that (interactive) programs can print to in tests.

Here's how it looks: archive.org/details/akkartik-2

Strings are arrays of bytes. To iterate over the graphemes in a string, store it in a stream and read graphemes from the stream.

github.com/akkartik/mu

Show thread

3 months ago I built a little prototype text-mode browser for a tiny subset of Markdown. Today it's a prototype no longer; it has fairly thorough tests. See how I write tests for the rendering in a language that maps 1:1 to machine code:

akkartik.github.io/mu/html/app

This one is for you, @yrabbit πŸ™‚

Old demo: archive.org/details/akkartik-2

Repo: github.com/akkartik/mu

Show thread

New demo: a text-mode RPN calculator built up from machine code

archive.org/details/akkartik-2

Inspirations:
* LoGlo (loglo.app/2020-06-16)
* Brief (youtube.com/watch?v=R3MNcA2dpt)

Unlike these, however, this version tries to hew to two principles:
* Show all the data (following spreadsheets and Joshua Horowitz; joshuahhh.com/projects/pane)
* Minimize interaction (following Bret Victor; worrydream.com/MagicInk)

Project page: github.com/akkartik/mu

Show thread

*Update on stress-testing Mu*

I'm continuing to play with my prototype postfix calculator. Who knows, it may even become Mu's mythical level-3 language[1].

Today's video demonstrates function definitions that look different from concatenative languages, and a visualization for drilling down into function calls. All in an environment that updates as you type, built up from machine code.

archive.org/details/akkartik-2

(More details: github.com/akkartik/mu)

[1] akkartik.name/post/mu-2019-1

Show thread

I just finished adding floating-point to Mu. Took 4 days. Floating-point is where the ugliness of x86 really becomes apparent.

Show thread

Detective story of the day

I've been stress-testing Mu's floating-point instructions for a few days using this ray-tracing tutorial: raytracing.github.io/books/Ray

It's been great; I've found 2 bugs so far.

Today I thought I found a third, in the floating-point reciprocal instruction. Except it wasn't really. Read on: github.com/akkartik/mu/blob/ma

Show thread

@akkartik I'm interested in the note on syscalls. Is there a way you'd prefer to see them implemented? Mu still uses registers so I feel like I'm missing something there. Viewing syscalls a part of StdLib it seems fine for that to be subX or Mu so I think I'm missing something. :)

Think the program looks nice overall besides the noted orchestration. Things are getting pretty interesting! πŸ‘€

@kingcons Thanks!

You're right that putting wrappers around syscalls in the SubX layer is fine. Here I'm not sure of the right interface the wrapper should provide (which has the opportunity to be timeless, since Linux syscalls are anything but). So I wish I could put hacky layers 103-105 in the app. But my calling convention only supports pushing args to the stack.

I'd also like to change the syscall interface at some point (in the distant future). So this stuff is temporary, in my mind.

@akkartik Then again, stuff like this is very annoying to to read and while it can be stylistically great should be used very sparringly

@akkartik
And I immediately remembered the phrase:
``One of my hobbies is writing text formatter/editors.'' (c) Leo Brodie πŸ™‚

Page 102 (86)

dnd.utwente.nl/~tim/colorforth

@akkartik @s_ol Two modules, A and B, both implement a procedure P. Your program needs to use both implementations of P. How is the language to know which one to call where?

@akkartik @s_ol One thing I absolutely abhore about Scala is that it has *implicit* parameters to some types of methods. You don't need to mention them in the method call, but they're there. I learned about them while trying to use Chisel (hardware description language).

It was a **horrible** experience to me as a programmer. Made debugging nigh impossible.

IMHO, explicit is always better than implicit. Unconditionally.

@akkartik @s_ol That said, what you're doing in the video reminds me a great deal of some early research into statically compiled, prototype-based object oriented languages (I can't recall specific names at the moment; it's been a while!), where the compiler infers types based on static analysis of prototypes and how they're created and later used.

It's been a few years; I can't recall details at the moment.

@vertigo Agreed! I'm not sure if this was pushing back on something I said, but I was thinking the same in my parting shot on implicitly loaded standard libraries.

@akkartik I was actually thinking about the case of having smaller libraries built by different people, rather than a large library.

For example, a GUI toolkit could have a procedure named DrawLine, while a Postscript printer interface might also have a DrawLine procedure.

You mention namespaces, but how would they work? Are namespaces also implicitly created?

@vertigo I wasn't thinking of a single approach:

1. Some languages support local names for imports.

2. Some languages (C++) have idioms of libraries putting their code in 'unique' namespaces.

Stuff like that.

@vertigo
Scala sucks for many reasons, not least that all the rich type information is lost in the jvm bytecode. A lot of behaviors in Scala are just impossible to debug in a debugger. Lazy initialization had me running in circles for weeks once (because the debugger would initialize the variable to show it's value.)
@akkartik @s_ol

@vertigo Give them different names? Namespaces are also a solution here, though I have similar problems with them as well.

In general, I prefer small software stacks like you. These problems disappear in small stacks. People who rub up against these constraints need to start ripping out code and undoing some unnecessary specialization/delegation.

@akkartik @s_ol If it's easy to deduce then we should let our editors add the import declarations themselves. Oh wait they already can.

@lunch You'd rather rely on a whole second tool parsing your code to do this, when your whole first tool could do it?

@akkartik If we're supposing that we don't want to write out import decls ourselves I'd rather not have the ambiguity of the compiler making a decision about it and have it explicit in the source code.

@s_ol "there's a type named Error in 10 different modules, which one are we going to use?"

@lunch
as i understand, the point is not to have modules with conflicting in the first place.

@lunch
you will say "but that doesn't scale", but @akkartik's work is exactly about needing to scale as little as possible.

@akkartik @s_ol Modules serve as namespaces, to qualify the identifiers we use, because there may be and often are collisions, especially in short names.

Also package management is hell. All those search paths, places where they're set, and their precedence rules, relative paths, initialization of the modules, "diamond problems" from it, and incompatible dependencies' versions 🀦
Programming is easy, it's the dependency management that is hard.

@amiloradovsky That could be my tagline: programming without package managers.

Sure, require a declaration when you want to avoid repeating a namespace, or when you want to disambiguate a name. But if I have a function called print, and the language provides a function called print, and there's no other function called print, ...

@akkartik What if print is polymorphic, and I've defined a new data-structure and want to make it printable? Generally with overloading you need some hints to decide which exactly procedure to use.

@amiloradovsky That's actually a separate question. I'm not aware of any language that uses import declarations to disambiguate ad hoc polymorphism.

So now I'm wondering why we allow that source of ambiguity to be implicitly resolved but cargo-cult the easier case without overloading πŸ™‚

@akkartik By importing the modules explicitly you reduce the search space to a manageable sizes.
You also still need to install the external modules explicitly. Even if later on the interpreter/linker will search through all of them.

@akkartik Glad you're taking care of yourself. Didn't know you had RSI. ❀️ Also, I hope you're proud of how far Mu has come. It's starting to look pretty sick 🀘

@akkartik oh no! take care of yourself, RSI is priority #1

@akkartik Neat!! I like how you can seamlessly go from higher-level code into assembly language level and back again.

@akkartik
hm,
(addr stream int 4)
is a stream that can hold values of type (addr int 4)? I was expecting s2 to be defined as (stream addr int 4) based on the rest of the program

@akkartik
ah nvm, I see now that it's just a pointer to s, and later you are demonstrating that putting a pointer into the stream auto-dereferences it?

@akkartik
maybe you could set x to another value after adding it to the stream to make this more clear

@s_ol Good to hear that this is confusing. The intent is not to store addresses in the stream. Values of type `addr` are intended to be short-lived, and it will be illegal to store them in aggregate types. (Though it isn't checked at the moment.)

In akkartik.github.io/mu/html/402, `s` has type `(stream int 4)`. It contains values of type `int` and has capacity 4. `write-to-stream` writes an int to it. `read-from-stream` reads an int from it. I pass in pointers just because `int` could be a large type.

@akkartik This looks like such a cool project!

Tangent but I really like akkartik.name/post/readable-ba

@alcinnz you might like reading the above, too! I feel like it goes head-on into some issues both of us have expressed.

@emsenn @akkartik I have studied Mu before, and I'm looking into the calculator now!

@alcinnz Sorry, to be clear I meant specifically the piece I linked on readability. @akkartik

@emsenn @akkartik Ah yes, the importance of communicating & maintaining software architecture! That *does* need more advocacy!

Sign in to participate in the conversation
Mastodon

Server run by the main developers of the project 🐘 It is not focused on any particular niche interest - everyone is welcome as long as you follow our code of conduct!