2016-10-24 23:40:32 +00:00
|
|
|
|
_by Stephen Malina and Kartik Agaram_
|
|
|
|
|
|
2016-03-10 21:54:23 +00:00
|
|
|
|
Mu explores ways to turn arbitrary manual tests into reproducible automated
|
|
|
|
|
tests. Hoped-for benefits:
|
|
|
|
|
|
|
|
|
|
1. Projects release with confidence without requiring manual QA or causing
|
|
|
|
|
regressions for their users.
|
|
|
|
|
|
|
|
|
|
1. Open source projects become easier for outsiders to comprehend, since they
|
|
|
|
|
can more confidently try out changes with the knowledge that they'll get
|
2016-09-10 18:06:17 +00:00
|
|
|
|
rapid feedback if they break something. Projects also become more
|
|
|
|
|
*rewrite-friendly* for insiders: it's easier to leave your project's
|
|
|
|
|
historical accidents and other baggage behind if you can be confident of
|
|
|
|
|
not causing regressions.
|
2016-03-10 21:54:23 +00:00
|
|
|
|
|
|
|
|
|
1. It becomes easier to teach programming by emphasizing tests far earlier
|
|
|
|
|
than we do today.
|
|
|
|
|
|
2016-10-24 23:52:42 +00:00
|
|
|
|
The hypothesis is that designing the OS to be testable from day 1 would
|
|
|
|
|
radically impact the culture of an eco-system in a way that no bolted-on tool
|
|
|
|
|
or service at higher levels can replicate. It would make it easier to write
|
|
|
|
|
programs that can be [easily understood by newcomers](http://akkartik.name/about).
|
|
|
|
|
It would reassure authors that an app is free from regression if all automated
|
|
|
|
|
tests pass. It would make the stack easy to rewrite and simplify by dropping
|
|
|
|
|
features, without fear that a subset of targeted apps might break. As a result
|
|
|
|
|
people might fork projects more easily, and also exchange code between
|
|
|
|
|
disparate forks more easily (copy the tests over, then try copying code over
|
|
|
|
|
and making tests pass, rewriting and polishing where necessary). The community
|
|
|
|
|
would have in effect a diversified portfolio of forks, a “wavefront” of
|
|
|
|
|
possible combinations of features and alternative implementations of features
|
|
|
|
|
instead of the single trunk with monotonically growing complexity that we get
|
|
|
|
|
today. Application writers who wrote thorough tests for their apps (something
|
|
|
|
|
they just can’t do today) would be able to bounce around between forks more
|
|
|
|
|
easily without getting locked in to a single one as currently happens.
|
|
|
|
|
|
2016-03-10 21:54:23 +00:00
|
|
|
|
In this quest, Mu is currently experimenting with the following mechanisms:
|
|
|
|
|
|
2016-03-15 18:35:13 +00:00
|
|
|
|
1. New, testable interfaces for the operating system. Currently manual tests
|
|
|
|
|
are hard to automate because a file you assumed might vanish, the network
|
|
|
|
|
might go down, etc. To make manual tests reproducible it suffices to
|
|
|
|
|
improve the 15 or so OS syscalls through which a computer talks to the
|
|
|
|
|
outside world. We have to allow programs to transparently write to a fake
|
|
|
|
|
screen, read from a fake disk/network, etc. In Mu, printing to screen
|
|
|
|
|
explicitly takes a screen object, so it can be called on the real screen,
|
|
|
|
|
or on a fake screen inside tests, so that we can then check the expected
|
|
|
|
|
state of the screen at the end of a test. Here's a test for a little
|
|
|
|
|
text-mode chessboard program in Mu (delimiting the edge of the 'screen'
|
|
|
|
|
with dots):
|
2016-09-18 07:25:00 +00:00
|
|
|
|
|
|
|
|
|
<img alt='a screen test' src='html/chessboard-test.png'>
|
|
|
|
|
|
2016-10-24 23:40:32 +00:00
|
|
|
|
We're building up similarly *dependency-injected* interfaces to the
|
|
|
|
|
keyboard, mouse, disk, network, graphics card, speakers, etc.
|
2016-03-10 21:54:23 +00:00
|
|
|
|
|
|
|
|
|
1. Support for testing side-effects like performance, deadlock-freedom,
|
|
|
|
|
race-freeness, memory usage, etc. Mu's *white-box tests* can check not just
|
|
|
|
|
the results of a function call, but also the presence or absence of
|
2016-03-10 22:46:11 +00:00
|
|
|
|
specific events in the log of its progress. For example, here's a test that
|
|
|
|
|
our string-comparison function doesn't scan individual characters unless it
|
|
|
|
|
has to:
|
2016-09-18 07:25:00 +00:00
|
|
|
|
|
|
|
|
|
<img alt='white-box test' src='html/tracing-test.png'>
|
|
|
|
|
|
|
|
|
|
Another example: if a sort function logs each swap, a performance test can
|
2016-03-15 00:36:53 +00:00
|
|
|
|
ensure that the number of swaps doesn't quadruple when the size of the
|
|
|
|
|
input doubles.
|
2016-09-18 07:25:00 +00:00
|
|
|
|
|
|
|
|
|
Besides expanding the scope of tests, this ability also allows more
|
2016-03-10 22:46:11 +00:00
|
|
|
|
radical refactoring without needing to modify tests. All Mu's tests call a
|
|
|
|
|
top-level function rather than individual sub-systems directly. As a result
|
|
|
|
|
the way the subsystems are invoked can be radically changed (interface
|
|
|
|
|
changes, making synchronous functions asynchronous, etc.). As long as the
|
|
|
|
|
new versions emit the same implementation-independent events in the logs,
|
|
|
|
|
the tests will continue to pass. ([More information.](http://akkartik.name/post/tracing-tests))
|
2016-03-10 21:54:23 +00:00
|
|
|
|
|
|
|
|
|
1. Organizing code and tests in layers of functionality, so that outsiders can
|
|
|
|
|
build simple and successively more complex versions of a project, gradually
|
|
|
|
|
enabling more peripheral features. Think of it as a cleaned-up `git log`
|
|
|
|
|
for the project. ([More information.](http://akkartik.name/post/wart-layers))
|
|
|
|
|
|
2016-10-24 23:40:32 +00:00
|
|
|
|
Since we don't understand how Linux and other modern platforms work, Mu is
|
|
|
|
|
built on an idealized VM while we [learn](https://github.com/akkartik/mu/wiki).
|
|
|
|
|
Eventually the plan is to transplant Mu's interfaces back to Linux.
|
2016-03-10 21:54:23 +00:00
|
|
|
|
|
2016-10-24 23:40:32 +00:00
|
|
|
|
To minimize workload, Mu doesn't have a high-level language yet. Instead, we
|
|
|
|
|
program directly in the VM's idealized assembly language. We expected this to
|
|
|
|
|
be painful, but it's had some surprising benefits. First, programs as lists of
|
|
|
|
|
instructions seem to be easier for non-programmers to comprehend than programs
|
|
|
|
|
as trees of expressions. Second, we've found that Literate Programming using
|
|
|
|
|
layers makes assembly much more ergonomic. Third, labels for gotos turn out to
|
|
|
|
|
be great waypoints to insert code at from future layers, more powerful than
|
|
|
|
|
nested expressions on a single line.
|
2016-03-10 21:54:23 +00:00
|
|
|
|
|
|
|
|
|
High level languages today seem to provide three kinds of benefits:
|
|
|
|
|
expressiveness (e.g. nested expressions, classes), safety (e.g. type checking)
|
2016-08-13 00:52:30 +00:00
|
|
|
|
and automation (e.g. garbage collection). Mu gives up some expressiveness by
|
|
|
|
|
not providing recursive expressions, but still supports lexical scope, generic
|
|
|
|
|
types, and higher-order functions. It provides strong memory safety in spite
|
|
|
|
|
of having manual memory management and supporting full-scale pointer
|
|
|
|
|
operations (albeit at the cost of some runtime checks).
|
2016-03-08 04:51:40 +00:00
|
|
|
|
|
2016-03-07 07:59:59 +00:00
|
|
|
|
*Taking Mu for a spin*
|
2014-11-01 23:15:15 +00:00
|
|
|
|
|
2016-09-25 03:07:42 +00:00
|
|
|
|
Mu is currently implemented in C++ and requires a Unix-like environment. It's
|
2016-10-06 22:40:56 +00:00
|
|
|
|
been tested on Ubuntu, Mac OS X and OpenBSD; on x86, x86\_64 and ARMv7; and on
|
|
|
|
|
recent versions of GCC and Clang. Since it uses no bleeding-edge language
|
|
|
|
|
features and has no exotic dependencies, it should work with most reasonable
|
|
|
|
|
versions, compilers or processors.
|
2015-09-02 19:29:39 +00:00
|
|
|
|
|
2016-05-09 01:16:45 +00:00
|
|
|
|
[![Build Status](https://api.travis-ci.org/akkartik/mu.svg)](https://travis-ci.org/akkartik/mu)
|
|
|
|
|
|
2015-09-02 19:29:39 +00:00
|
|
|
|
Running Mu will always recompile it if necessary:
|
2015-06-10 17:22:02 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```shell
|
2014-11-01 23:15:15 +00:00
|
|
|
|
$ cd mu
|
2015-07-05 17:35:26 +00:00
|
|
|
|
$ ./mu
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2014-11-01 23:15:15 +00:00
|
|
|
|
|
2016-03-10 22:53:46 +00:00
|
|
|
|
As a simple example, here's a program with some arithmetic:
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='code example' src='html/example1.png'>
|
2014-11-25 07:59:55 +00:00
|
|
|
|
|
2016-10-24 23:40:32 +00:00
|
|
|
|
As stated before, Mu functions are lists of instructions, one to a line. Each
|
2016-03-10 22:46:11 +00:00
|
|
|
|
instruction operates on some *ingredients* and returns some *products*.
|
2014-11-25 07:59:55 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2015-07-14 03:50:25 +00:00
|
|
|
|
[products] <- instruction [ingredients]
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2014-11-25 07:59:55 +00:00
|
|
|
|
|
2016-08-13 00:52:30 +00:00
|
|
|
|
Result and ingredient *reagents* cannot contain instructions or infix
|
|
|
|
|
expressions. On the other hand, you can have any number of them. In
|
|
|
|
|
particular, you can have any number of products. For example, you can perform
|
|
|
|
|
integer division as follows:
|
2014-11-26 16:30:26 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2015-07-28 21:33:22 +00:00
|
|
|
|
quotient:number, remainder:number <- divide-with-remainder 11, 3
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2014-11-26 16:30:26 +00:00
|
|
|
|
|
2016-03-10 22:46:11 +00:00
|
|
|
|
Each reagent consists of a name and its type, separated by a colon. You only
|
|
|
|
|
have to specify the type the first time you mention a name, but you can be
|
|
|
|
|
more explicit if you choose. Types can be multiple words and even arbitrary
|
2015-11-11 17:13:40 +00:00
|
|
|
|
trees, like:
|
2014-11-25 07:59:55 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```nim
|
2015-06-08 21:24:05 +00:00
|
|
|
|
x:array:number:3 # x is an array of 3 numbers
|
|
|
|
|
y:list:number # y is a list of numbers
|
2016-03-10 22:46:11 +00:00
|
|
|
|
# ':' is just syntactic sugar
|
2015-11-11 17:13:40 +00:00
|
|
|
|
{z: (map (address array character) (list number))} # map from string to list of numbers
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2014-12-14 21:21:32 +00:00
|
|
|
|
|
2015-11-11 17:13:40 +00:00
|
|
|
|
Try out the program now:
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
$ ./mu example1.mu
|
|
|
|
|
$
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Not much to see yet, since it doesn't print anything. To print the result, try
|
2016-03-08 09:30:14 +00:00
|
|
|
|
adding the instruction `$print a` to the function.
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
Here's a second example, of a function that can take ingredients:
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='fahrenheit to celsius' src='html/f2c-1.png'>
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
2016-03-08 19:50:33 +00:00
|
|
|
|
Functions can specify headers showing their expected ingredients and products,
|
2016-03-10 23:02:05 +00:00
|
|
|
|
separated by `->` (unlike the `<-` in calls).
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
2016-09-10 17:34:39 +00:00
|
|
|
|
Once defined, functions can be called just like primitives. No need to mess
|
|
|
|
|
with a `CALL` instruction or push/pop arguments to the stack.
|
|
|
|
|
|
2016-03-08 08:15:04 +00:00
|
|
|
|
Since Mu is a low-level VM language, it provides extra control at the cost of
|
2015-11-15 00:26:33 +00:00
|
|
|
|
verbosity. Using `local-scope`, you have explicit control over stack frames to
|
2016-03-10 23:02:05 +00:00
|
|
|
|
isolate your functions in a type-safe manner. You can also create more
|
2016-03-10 22:46:11 +00:00
|
|
|
|
sophisticated setups like closures. One consequence of this extra control: you
|
|
|
|
|
have to explicitly `load-ingredients` after you set up the stack.
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
|
|
|
|
An alternative syntax is what the above example is converted to internally:
|
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='fahrenheit to celsius desugared' src='html/f2c-2.png'>
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
|
|
|
|
The header gets dropped after checking types at call-sites, and after
|
|
|
|
|
replacing `load-ingredients` with explicit instructions to load each
|
|
|
|
|
ingredient separately, and to explicitly return products to the caller. After
|
2016-03-08 09:30:14 +00:00
|
|
|
|
this translation functions are once again just lists of instructions.
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
2016-10-24 23:40:32 +00:00
|
|
|
|
This alternative syntax isn't just an implementation detail. It turns out to
|
|
|
|
|
be easier to teach functions to non-programmers by starting with this syntax,
|
|
|
|
|
so that they can visualize a pipe from caller to callee, and see the names of
|
|
|
|
|
variables get translated one by one through the pipe.
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
A third example, this time illustrating conditionals:
|
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='factorial example' src='html/factorial.png'>
|
2015-11-11 17:13:40 +00:00
|
|
|
|
|
2016-03-10 23:02:05 +00:00
|
|
|
|
In spite of how it looks, this is still just a list of instructions and
|
|
|
|
|
labels. Internally, the instructions `break` and `loop` get converted to
|
2016-04-28 00:55:14 +00:00
|
|
|
|
`jump` instructions to after the enclosing `}` or `{` labels, respectively.
|
2015-06-08 21:24:05 +00:00
|
|
|
|
|
2015-01-03 02:57:49 +00:00
|
|
|
|
Try out the factorial program now:
|
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```shell
|
2015-01-03 02:57:49 +00:00
|
|
|
|
$ ./mu factorial.mu
|
|
|
|
|
result: 120 # factorial of 5
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2015-01-03 02:57:49 +00:00
|
|
|
|
|
2015-06-08 21:24:05 +00:00
|
|
|
|
You can also run its unit tests:
|
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```shell
|
2015-06-08 21:24:05 +00:00
|
|
|
|
$ ./mu test factorial.mu
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2015-06-08 21:24:05 +00:00
|
|
|
|
|
|
|
|
|
Here's what one of the tests inside `factorial.mu` looks like:
|
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='test example' src='html/factorial-test.png'>
|
2015-06-08 21:24:05 +00:00
|
|
|
|
|
|
|
|
|
Every test conceptually spins up a really lightweight virtual machine, so you
|
|
|
|
|
can do things like check the value of specific locations in memory. You can
|
|
|
|
|
also print to screen and check that the screen contains what you expect at the
|
2016-03-10 22:46:11 +00:00
|
|
|
|
end of a test. For example, you've seen earlier how `chessboard.mu` checks the
|
|
|
|
|
initial position of a game of chess (delimiting the edges of the screen with
|
2016-03-11 22:36:59 +00:00
|
|
|
|
dots):
|
2015-06-08 21:24:05 +00:00
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='screen test' src='html/chessboard-test.png'>
|
2015-06-08 21:24:05 +00:00
|
|
|
|
|
|
|
|
|
Similarly you can fake the keyboard to pretend someone typed something:
|
|
|
|
|
|
2016-10-07 19:14:35 +00:00
|
|
|
|
<img alt='fake keyboard' src='html/fake-keyboard.png'>
|
|
|
|
|
|
|
|
|
|
..or clicked somewhere:
|
|
|
|
|
|
|
|
|
|
<img alt='fake console (keyboard, mouse, ..)' src='html/fake-console.png'>
|
|
|
|
|
|
2016-10-24 22:06:15 +00:00
|
|
|
|
Within tests you can map arbitrary paths (local files or URLs) to contents:
|
2016-10-07 19:14:35 +00:00
|
|
|
|
|
2016-10-24 22:06:15 +00:00
|
|
|
|
<img alt='fake file-system and network' src='html/resources.png'>
|
2015-06-08 21:24:05 +00:00
|
|
|
|
|
2016-10-24 22:06:15 +00:00
|
|
|
|
As we add graphics, audio, and so on, we'll augment scenarios with
|
|
|
|
|
corresponding abilities.
|
2015-06-08 21:24:05 +00:00
|
|
|
|
|
2015-01-03 02:57:49 +00:00
|
|
|
|
---
|
|
|
|
|
|
2016-09-10 18:43:00 +00:00
|
|
|
|
Mu assumes that all ingredients passed in to functions are immutable by
|
|
|
|
|
default -- *unless* they are also products. So this program will throw an
|
|
|
|
|
error:
|
|
|
|
|
|
2016-10-10 22:08:38 +00:00
|
|
|
|
<img alt='immutable ingredient triggering an error' src='html/immutable-error.png'>
|
2016-09-10 18:43:00 +00:00
|
|
|
|
|
|
|
|
|
To modify `foo`'s ingredient, you have to add it to the list of products
|
|
|
|
|
returned:
|
|
|
|
|
|
2016-10-10 22:08:38 +00:00
|
|
|
|
<img alt='mutable ingredient' src='html/mutable.png'>
|
2016-09-10 18:43:00 +00:00
|
|
|
|
|
|
|
|
|
The names of the variables are important here: a function that takes an
|
|
|
|
|
(immutable) address and returns a different one is different from a function
|
|
|
|
|
that takes a mutable address (and also returns it).
|
|
|
|
|
|
|
|
|
|
Immutability checks can be annoying sometimes, but the benefit they provide is
|
|
|
|
|
that you always know what a function modifies just by looking at its header.
|
|
|
|
|
They provide all the benefits of [referential transparency](https://en.wikipedia.org/wiki/Referential_transparency)
|
|
|
|
|
that we typically associate with (particularly purely functional) high-level
|
|
|
|
|
languages -- but without giving up the flexibility to imperatively modify
|
|
|
|
|
variables willy-nilly.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2015-05-06 04:17:24 +00:00
|
|
|
|
You can append arbitrary properties to reagents besides types and spaces. Just
|
2015-01-03 02:57:49 +00:00
|
|
|
|
separate them with slashes.
|
2014-12-14 21:21:32 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```nim
|
2015-05-13 17:03:26 +00:00
|
|
|
|
x:array:number:3/uninitialized
|
2014-12-14 21:21:32 +00:00
|
|
|
|
y:string/tainted:yes
|
2016-08-13 00:52:30 +00:00
|
|
|
|
z:number/assign-once:true/assigned:false
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2014-12-14 21:21:32 +00:00
|
|
|
|
|
2015-03-10 19:16:28 +00:00
|
|
|
|
Most properties are meaningless to Mu, and it'll silently skip them when
|
2015-01-03 02:57:49 +00:00
|
|
|
|
running, but they are fodder for *meta-programs* to check or modify your
|
|
|
|
|
programs, a task other languages typically hide from their programmers. For
|
|
|
|
|
example, where other programmers are restricted to the checks their type
|
2014-12-14 21:21:32 +00:00
|
|
|
|
system permits and forces them to use, you'll learn to create new checks that
|
|
|
|
|
make sense for your specific program. If it makes sense to perform different
|
|
|
|
|
checks in different parts of your program, you'll be able to do that.
|
|
|
|
|
|
2015-08-13 15:27:18 +00:00
|
|
|
|
You can imagine each reagent as a table, rows separated by slashes, columns
|
|
|
|
|
within a row separated by colons. So the last example above would become
|
|
|
|
|
something like this:
|
2015-01-08 03:34:23 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2016-08-13 00:52:30 +00:00
|
|
|
|
z : integer /
|
|
|
|
|
assign-once : true /
|
2015-01-08 03:34:23 +00:00
|
|
|
|
assigned : false
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2014-11-25 07:59:55 +00:00
|
|
|
|
|
|
|
|
|
---
|
2014-11-01 23:15:15 +00:00
|
|
|
|
|
2016-03-11 22:36:59 +00:00
|
|
|
|
An alternative way to define factorial is by inserting labels and later
|
2014-11-26 16:30:26 +00:00
|
|
|
|
inserting code at them.
|
|
|
|
|
|
2016-03-09 00:50:22 +00:00
|
|
|
|
<img alt='literate programming' src='html/tangle.png'>
|
2014-11-26 16:30:26 +00:00
|
|
|
|
|
|
|
|
|
(You'll find this version in `tangle.mu`.)
|
|
|
|
|
|
2016-03-11 22:36:59 +00:00
|
|
|
|
By convention we use the prefix '+' to indicate function-local label names you
|
|
|
|
|
can jump to, and surround in '<>' global label names for inserting code at.
|
2015-02-02 20:19:47 +00:00
|
|
|
|
|
2014-11-26 16:30:26 +00:00
|
|
|
|
---
|
|
|
|
|
|
2016-08-13 00:52:30 +00:00
|
|
|
|
Another example, this time with concurrency:
|
2014-11-01 23:34:33 +00:00
|
|
|
|
|
2016-03-09 00:50:22 +00:00
|
|
|
|
<img alt='forking concurrent routines' src='html/fork.png'>
|
2015-05-11 16:59:29 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```shell
|
2014-12-13 08:33:20 +00:00
|
|
|
|
$ ./mu fork.mu
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2014-11-01 23:34:33 +00:00
|
|
|
|
|
|
|
|
|
Notice that it repeatedly prints either '34' or '35' at random. Hit ctrl-c to
|
|
|
|
|
stop.
|
|
|
|
|
|
2016-08-13 00:52:30 +00:00
|
|
|
|
[Yet another example](http://akkartik.github.io/mu/html/channel.mu.html) forks
|
|
|
|
|
two 'routines' that communicate over a channel:
|
2014-11-25 09:25:20 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```shell
|
2014-12-13 08:33:20 +00:00
|
|
|
|
$ ./mu channel.mu
|
2014-11-25 09:25:20 +00:00
|
|
|
|
produce: 0
|
|
|
|
|
produce: 1
|
|
|
|
|
produce: 2
|
|
|
|
|
produce: 3
|
|
|
|
|
consume: 0
|
|
|
|
|
consume: 1
|
|
|
|
|
consume: 2
|
|
|
|
|
produce: 4
|
|
|
|
|
consume: 3
|
|
|
|
|
consume: 4
|
|
|
|
|
|
|
|
|
|
# The exact order above might shift over time, but you'll never see a number
|
|
|
|
|
# consumed before it's produced.
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2014-11-25 09:25:20 +00:00
|
|
|
|
|
2016-08-13 00:52:30 +00:00
|
|
|
|
Channels are the unit of synchronization in Mu. Blocking on a channel is the
|
|
|
|
|
only way for the OS to put a task to sleep. The plan is to do all I/O over
|
|
|
|
|
channels.
|
2014-11-25 09:25:20 +00:00
|
|
|
|
|
|
|
|
|
Routines are expected to communicate purely by message passing, though nothing
|
|
|
|
|
stops them from sharing memory since all routines share a common address
|
2015-03-10 19:16:28 +00:00
|
|
|
|
space. However, idiomatic Mu will make it hard to accidentally read or clobber
|
2014-11-25 09:25:20 +00:00
|
|
|
|
random memory locations. Bounds checking is baked deeply into the semantics,
|
2016-08-13 00:52:30 +00:00
|
|
|
|
and pointers can never be invalidated.
|
2014-11-25 09:25:20 +00:00
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2016-09-10 17:34:39 +00:00
|
|
|
|
Mu has a programming environment:
|
2015-07-30 21:16:30 +00:00
|
|
|
|
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```shell
|
2015-09-05 18:50:49 +00:00
|
|
|
|
$ ./mu edit
|
2015-08-10 23:14:38 +00:00
|
|
|
|
```
|
2015-07-30 21:16:30 +00:00
|
|
|
|
|
|
|
|
|
Screenshot:
|
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='programming environment' src='html/edit.png'>
|
2015-07-30 21:16:30 +00:00
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
You write functions on the left and try them out in *sandboxes* on the right.
|
2015-09-06 23:52:48 +00:00
|
|
|
|
Hit F4 to rerun all sandboxes with the latest version of the code. More
|
|
|
|
|
details: http://akkartik.name/post/mu. Beware, it won't save your edits by
|
|
|
|
|
default. But if you create a sub-directory called `lesson/` under `mu/` it
|
2015-07-30 21:16:30 +00:00
|
|
|
|
will. If you turn that directory into a git repo with `git init`, it will also
|
2016-09-10 18:00:07 +00:00
|
|
|
|
back up your changes each time you hit F4. Use the provided `new_lesson`
|
|
|
|
|
script to take care of these details.
|
2015-07-30 21:16:30 +00:00
|
|
|
|
|
2015-08-13 15:27:18 +00:00
|
|
|
|
Once you have a sandbox you can click on its result to mark it as expected:
|
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='expected result' src='html/expected-result.png'>
|
2015-08-13 15:27:18 +00:00
|
|
|
|
|
|
|
|
|
Later if the result changes it'll be flagged in red to draw your attention to
|
|
|
|
|
it. Thus, manually tested sandboxes become reproducible automated tests.
|
|
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
|
<img alt='unexpected result' src='html/unexpected-result.png'>
|
2015-08-13 15:27:18 +00:00
|
|
|
|
|
|
|
|
|
Another feature: Clicking on the code in a sandbox expands its trace for you
|
2015-08-13 15:58:41 +00:00
|
|
|
|
to browse. To add to the trace, use `stash`. For example:
|
|
|
|
|
|
|
|
|
|
```nim
|
2016-04-24 23:28:03 +00:00
|
|
|
|
stash [first ingredient is], x
|
2015-08-13 15:58:41 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Invaluable for understanding complex control flow without cluttering up the
|
|
|
|
|
screen.
|
2015-08-13 15:27:18 +00:00
|
|
|
|
|
2016-09-10 17:34:39 +00:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
If you're still reading, here are some more things to check out:
|
|
|
|
|
|
|
|
|
|
a) Look at the [chessboard program](http://akkartik.github.io/mu/html/chessboard.mu.html)
|
2016-10-24 23:40:32 +00:00
|
|
|
|
for a more complex example with tests of blocking reads from the keyboard and
|
|
|
|
|
what gets printed to the screen -- things we don't typically associate with
|
|
|
|
|
automated tests.
|
2016-09-10 17:34:39 +00:00
|
|
|
|
|
|
|
|
|
b) Try skimming the [colorized source code](https://akkartik.github.io/mu).
|
2016-10-24 23:40:32 +00:00
|
|
|
|
You should be able to get a pretty good sense for how things work just by
|
|
|
|
|
skimming the files in order, skimming the top of each file and ignoring
|
|
|
|
|
details lower down.
|
2016-09-10 17:34:39 +00:00
|
|
|
|
|
|
|
|
|
c) Try running the tests:
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
$ ./mu test
|
|
|
|
|
```
|
|
|
|
|
|
2016-02-29 17:48:40 +00:00
|
|
|
|
The next major milestone on Mu's roadmap is dependency-injected interfaces for
|
2016-09-10 17:34:39 +00:00
|
|
|
|
the network.
|
2015-08-13 15:27:18 +00:00
|
|
|
|
|
2014-11-29 15:52:08 +00:00
|
|
|
|
**Credits**
|
2014-11-25 07:59:55 +00:00
|
|
|
|
|
|
|
|
|
Mu builds on many ideas that have come before, especially:
|
|
|
|
|
|
2014-11-26 15:04:04 +00:00
|
|
|
|
- [Peter Naur](http://alistair.cockburn.us/ASD+book+extract%3A+%22Naur,+Ehn,+Musashi%22)
|
2014-11-25 07:59:55 +00:00
|
|
|
|
for articulating the paramount problem of programming: communicating a
|
|
|
|
|
codebase to others;
|
2014-11-26 15:04:04 +00:00
|
|
|
|
- [Christopher Alexander](http://www.amazon.com/Notes-Synthesis-Form-Harvard-Paperbacks/dp/0674627512)
|
|
|
|
|
and [Richard Gabriel](http://dreamsongs.net/Files/PatternsOfSoftware.pdf) for
|
2014-11-25 07:59:55 +00:00
|
|
|
|
the intellectual tools for reasoning about the higher order design of a
|
|
|
|
|
codebase;
|
|
|
|
|
- Unix and C for showing us how to co-evolve language and OS, and for teaching
|
|
|
|
|
the (much maligned, misunderstood and underestimated) value of concise
|
|
|
|
|
*implementation* in addition to a clean interface;
|
2014-11-26 15:04:04 +00:00
|
|
|
|
- Donald Knuth's [literate programming](http://www.literateprogramming.com/knuthweb.pdf)
|
2014-11-25 07:59:55 +00:00
|
|
|
|
for liberating "code for humans to read" from the tyranny of compiler order;
|
2014-11-26 15:04:04 +00:00
|
|
|
|
- [David Parnas](http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf)
|
2014-11-25 07:59:55 +00:00
|
|
|
|
and others for highlighting the value of separating concerns and stepwise
|
|
|
|
|
refinement;
|
2014-11-26 15:04:04 +00:00
|
|
|
|
- [Lisp](http://www.paulgraham.com/rootsoflisp.html) for showing the power of
|
2015-06-24 22:46:30 +00:00
|
|
|
|
dynamic languages, late binding and providing the right primitives *a la
|
|
|
|
|
carte*, especially lisp macros;
|
2014-11-25 07:59:55 +00:00
|
|
|
|
- The folklore of debugging by print and the trace facility in many lisp
|
|
|
|
|
systems;
|
|
|
|
|
- Automated tests for showing the value of developing programs inside an
|
|
|
|
|
elaborate harness;
|
2014-11-26 15:04:04 +00:00
|
|
|
|
- [Python doctest](http://docs.python.org/2/library/doctest.html) for
|
2014-11-25 07:59:55 +00:00
|
|
|
|
exemplifying interactive documentation that doubles as tests;
|
2014-11-26 15:04:04 +00:00
|
|
|
|
- [ReStructuredText](https://en.wikipedia.org/wiki/ReStructuredText)
|
|
|
|
|
and [its antecedents](https://en.wikipedia.org/wiki/Setext) for showing that
|
2014-11-25 07:59:55 +00:00
|
|
|
|
markup can be clean;
|
|
|
|
|
- BDD for challenging us all to write tests at a higher level;
|
|
|
|
|
- JavaScript and CSS for demonstrating the power of a DOM for complex
|
|
|
|
|
structured documents.
|
2016-07-04 19:16:20 +00:00
|
|
|
|
- Rust for demonstrating that a system-programming language can be safe.
|