I'm not sure what I'm looking at?
I'm not sure what I'm looking at?
It's a new programming language.
edit: The source seems to be structured intentionally in a recommended reading order. See the comment at the top of
https://github.com/akkartik/mu/blob/master/000organization.c...
Layers of code are filled in as you read down the list of files. It's an interesting concept, similar to literate programming. (And FWIW, these source files are C++ code for the compiler, not an example of Mu code.)
The author also has a blog post up here: http://akkartik.name/post/mu
More details on my flavor of literate programming: http://akkartik.name/post/wart-layers
a) It makes the build scripts more complicated, which means they'll be more likely to break on some poor noob, and that when they break it'll be less likely the noob will be able to tell how to fix it.
b) Invariably the codebase accumulates dependencies between directories that are uneconomic to reorganize. At least a flat directory has a shot at under-promising and over-delivering.
c) Maybe people do it to make the place look neat, they way I used to 'clean my room' by stuffing all my dirty clothes into drawers. But codebases that are messes at a deep level are less likely to be cleaned up if they look clean at a superficial level. And all codebases eventually turn into messes, the way we've done things so far.
But they can also be used well, and the promise of a meaningful directory structure is really appealing.
Here's a question, given all of what I understand about your layered way of structuring code: how easy is it to spin off logical portions of a project? If my project accretes its own HTTP server and I want to turn that into a stand alone library, could I? Would it be possible to "rewrite history" so that the HTTP-related changes never appeared in the layers to start with?
Thanks!
$ ./mu factorial.mu
To run a more complex app, you just give a directory name rather than a filename: $ ./mu edit
Files inside the directory are loaded in numeric order just like at the top level. You can also run just a subset of the layers for the editor: $ ./mu test edit/001*
$ ./mu test edit/00[12]*
$ ./mu test edit/00[1-3]*
(Notice how the number of tests/dots grows at each layer.)Since the layers are just regular files there's nothing stopping you from rewriting history as much as you want. That ability was precisely what I built them for.
I've only recently started using directories, so I'm sure there's stuff here I haven't considered. Feedback most welcome.
You're right that there are points beyond which a single file becomes too unwieldy, but with a good editor that limit is quite high for me. Maybe 10k LoC. Directories can grow even larger before they start having problems.
So, no, there's a difference. I'll also note that Daniel Bernstein of qmail & NaCl often used a filesystem how some use databases under the philosophy of "Why create new, complex functionality when you have well-tested code that gets the job done?"
Designing a programming language is kind of like a 'rite of passage.' I think most of us have at least thought about how to make languages better.
Thanks for your kind words! I'm gratified that somebody understood what I'm trying to do in spite of my crappy writing skills.
I like your idea, and I think there's room for improved introspection in debugging.
At the same time, I think that if a program can't be understood without being executed, then it's already lost (in terms of readability).
Certainly, for example, if you have a threaded program, you need to be able to visually inspect and verify that there will be no deadlocks or race conditions when the program is run, because you won't be able to test every possible condition in a debugger.
(Mu scenarios can't insert context switches yet, but it's planned.)
Perhaps it would help to think of the dichotomy as between the rules and the state space of inputs they handle, rather than between reading and running. Seemingly simple code can often hide surprising subtleties. Why is this line written just like so and not thus? How does everything turn out just right in this one situation? Tests help to record the right questions for the reader to ask.
> I can't imagine visually inspecting and verifying anything if I didn't write it to begin with.
It's a skill, you need to develop it. You develop it by doing it :) > I wouldn't know where to begin thinking of possible ways to break it.
For deadlocks, look at every single lock used. Show that one of the Coffman conditions doesn't apply, and you've proven that there can never be a deadlock.For race conditions, look at every piece of shared memory (or other shared resource). That is where race conditions always occur.
For understanding a program, the key is to understand the structure. That is why people put things in subdirectories, to help communicate the structure of the program, and show which things are closely related.
> Do you really look at every single piece of shared memory?
Yes > When you inherit a large codebase from someone?
If the codebase has lots of threading errors, then yes, it's the only way. If it's a large program, it can take months to go through and check every piece of shared memory (and removing threads along the way, removing shared stuff); but the alternative could take years.In one case, I moved every single lock/unlock to the top of a file so I could quickly see all the locks and unlocks, and that each lock had a matching unlock, even in error conditions.
I think I'm not concerned so much about inheriting a codebase with lots of threading errors. It's more about a codebase that's almost perfectly right, but where I'm scared to change anything because I don't have a big-picture model of the concurrency in my head..
Do you have any code samples I can try to learn from? For example, I'm not sure how you would move lock/unlock pairs to the top of a file from different functions/scopes. Unless you were doing some sort of literate programming as well?
> How did you get into such issues? Were there classes where you got started, or was it all on the job?
I took the usual college classes dealing with concurrency (in my school it was in the OS class), but it took several years in the industry to really feel confident with threads (it took less time to feel confident with networking). I wrote down my knowledge (for what it's worth) in this book: http://www.amazon.com/dp/0996193308 > I'm not sure how you would move lock/unlock pairs to the top of a file from different functions/scopes.
That solution might not work in every case. It worked in the particular case I was referring to. > It's more about a codebase that's almost perfectly right, but where I'm scared to change anything because I don't have a big-picture model of the concurrency in my head..
Hmmmmm, that's an interesting question. Usually when the codebase is written, the person who wrote it had an idea in his head that, "this is how things will be locked to avoid problems." I try to figure out what that idea was.Sometimes there is like a critical 'zone,' where a thread acquires the lock when it enters, and releases when it leaves. For example, it could acquire the lock when it enters a class method, and releases it when it leaves the class. Then the class becomes the critical zone.
Maybe learning to think of 'critical zones' is the most important skill to understanding the big picture?
I'm glad I kept the conversation going so I could find out about your book. Purchased.
> n * n-1 # does what you expect
Very good idea!