3 ms·
One functional feature that is missing is that of having blocks in different order. Jeremy Ashkenas argues that because of functions, we do not need that reorde
by jostylr 11y ago
One functional feature that is missing is that of having blocks in different order. Jeremy Ashkenas argues that because of functions, we do not need that reordering.
I disagree with that. I do think a large part of what makes literate programming powerful is that one can easily sculpt the order of the presentation. It elevates the code and comment to telling a story for humans.
I think the code is not incidental, but is part of the aspect of the story, much like in a fictional story one has descriptive passages and dialog passages. If one updates the story, both may change or perhaps just one of them.
My take on literate programming, using markdown:
* minimal client at https://www.npmjs.com/package/litpro https://www.npmjs.com/package/litpro
* core library and docs at https://github.com/jostylr/literate-programming-lib https://github.com/jostylr/literate-programming-lib
- e12e 11y agoI agree that functions are not usually a good one-to-one fit for abstraction. If they were, we wouldn't need variables, loops, blocks etc. Now you could argue that we don't, we should just write code in lambda calculus -- but we don't do that. Especially for languages like assembler and C-like languages, it can be very nice to single out smaller sections of code. And while for eg: C, or I suppose a macro assembler, one might be able to in-line a lot of such blocks -- having to stay at the "block-semantic"-level of the host language can make some things pretty hard to communicate to the human reader in a good way. Ruby might actually be a good candidate for "simple" literate programming, in the sense that one probably could, and perhaps sometimes should, program ruby much like smalltalk -- no method/function longer than five lines or so, except for the most exceptional circumstances. Even then, I think one would find patterns that would make sense to abstract out of the "function level", or "language level". At the other end of the spectrum is too much magic, just as with any meta-programming technique, such as proper macros. I had a most peculiar experience trying to write some (mostly procedural) java with noweb. It was typical intro programming stuff, basically some very simple data structures/algorithms. It was a very nice fit for literate programming, but not such a good fit for java -- while the literate program read nicely, and was well structured, the mangled java code was unwieldy -- it turned out I'd ended up generating a java program that did what I wanted. Now, that's not really a problem, we generate assembly programs that are unwieldy all the time -- but the point is it took some discipline and thought to write a literate program that was also readable in it's tangled form. Only an issue if people are expected to read/modify it in that state, obviously. And they are, as they'll have to debug it at some point ;-) > I think the code is not incidental That was a bit tongue-in-cheek -- I meant more in the sense that comments are incidental to code in most programming languages. > https://github.com/jostylr/literate-programming-lib https://github.com/jostylr/literate-programming-lib Very nice, thank you for sharing.
- jostylr 11y agoMy version of literate-programming may have a bit too much possibility of that magic. I agree it can be dangerous and is something that takes good discipline, like any programming technique. But at least there is something to fall back on in terms of the narrative. On the flip side of the tangled form, I do appreciate the "flattening" of potential functions. Imagine code that uses a lot of functions, scattered about. It can be hard to follow all that, rather a bit like the GOTO of old (better, to be sure, but still hard to follow). With literate programming one can get the conceptual separation of writing in different blocks, but then they get put back together and the flattened version can be read quite easily, one would hope. So I agree that a locally readable tangled form is very important. I'd be curious to see your example's code, if you are willing to share it.
- e12e 11y ago[ed: I feel I should preface this to say that this is very old code, and something I'd normally show to anyone. But since you asked... :-) ] Unfortunately it looks like the code that was the best (worst) example of what I'm talking about isn't readily available (I have it some backup-archive or other...) -- and my other code is partially restructured based on what I learnt, and most significantly in Norwegian. However, one example, while not breaking the function-gap, is a small sub-section from the noweb document that reads (this is java 1.4): <<src/AllTests.java>>= import junit.framework.*; import junit.extensions.*; public class AllTests extends TestCase { public AllTests(String name) { super (name); } public static void main(String[] args) { junit.textui.TestRunner.run(AllTests.class); } <<testSucceed>> <<testTabell2D>> <<testBrikke>> } And the testSucceed-section is just a simplistic sanity check to make sure tests can be run/pass: <<testSucceed>>= /** Testing the test harness */ public void testSucceed() throws Exception { assertEquals(10, 10); } These two blocks, the test setup, and the meta-test go together in a neglected corner of the document, given only a little more priority than the build.xml-file -- while the more functional tests are moved close to the various interfaces (in this case) they are testing (rather than having them too close to the implementations they're actually testing). So one could say that this gives us injection without an injection framework. Or something. This is basically fixing a naming issue in java, where you need methods to be bound to a class (except for static stuff etc) -- and is an "abstraction free" (at the language level) way of moving things that go better together -- closer together. Note that the blocks pretty much lacks comments, as they are a bit gnarly to get to work with both java and noweb and javadoc -- but that is more of a tooling issue than anything else. In this case (imagine 10s of test cases) the tests might be a bit under-documented when seen in isolation. Note that each block actually holds a couple of test-cases applicable to whatever class/interface-pair it tests. But it gets even more interesting when you're sharing a block of code that implements a binary search on an array-like structure... does make it a little too easy to trip over local variables though. The full code (in Norwegian) is at: http://folk.uib.no/st05861/inf101/oblig1/ http://folk.uib.no/st05861/inf101/oblig1/ -- it's not very good, but the noweb source and pdf (oblig1.nw, oblig1.pdf) might be of some very limited interest -- and could be contrasted with the java code under src. This is all from an entry level programming course, the task was given as a pdf-document with some specs and a few stub interfaces -- the resulting pdf essentially interleaves the questions/specs as given, along with the interface stubs -- and builds up answers to each sub-section/point. The other code I mentioned was more along the lines of implementing binary search for a an array-like interface etc -- basically Abstract Data Structures.