Live data from Hacker News

Literate programming is much more than just commenting code

justinmeiners.github.io

41–50 of 112 posts

Re: Literate programming is much more than just commenting code

#41

I like literate programming in theory but the most common response I see to it is that writing self documenting code is better because as you are working on a code base with many people, it is unlikely they will keep your prose up to date as the code is changed.

How are newcomers handled in those "self-documenting codebases"?

Re: Literate programming is much more than just commenting code

#42

Are there any large (> 5 people teams) projects written with literate programming? Also are there any IDE plugins or error stack trace/debuggers for literate programming? I haven't really paid attention to literate programming in a long long time and I'm curious if the field has advanced. (Also I don't understand this: "A typical literate file produces many source files." Why? Why would you care about having multiple…

IMHO the two biggest problems I find with existing tools are that they assume the documentation is the source of truth and that the tangling will leave artifacts in code. Both of these make them poorly suited to the sort of projects that most of us work on, I'm not Knuth writing a dead tree tome but I would like some better ways to add documentation to existing projects and have to integrate with others.

I wrote a PoC of a tangling tool that worked through "virtual" files and had a syntax aware handler, there's enough information that it could possible work with language servers too, but sadly I haven't had time to take things further: https://gitlab.com/lusher/tanglemd

Re: Literate programming is much more than just commenting code

#43
post #26

Literate programming has been particularly useful for my "dotfile" configurations, such as .emacs, .vimrc, .zshrc and even the .gitconfig file. I use one .org file to declare all of my configurations, and tangle them together into the aforementioned files. This keeps things pretty portable, and makes up for the unintuitive readability of many dotfiles. It can also work for rudimentary shell scripts and other single-f…

This is a cool idea. Also so if you switch tools like WMs you know what you used to have even if it takes some work to reconstruct what that was. But have such a tangle of glued together and custom written tiling WM rice that I can never switch to anything every again.

Re: Literate programming is much more than just commenting code

#44

This is great stuff. It's how all code and data research should be presented, where the document is the program and you can reproduce it as easily as you can read it. After years of using Pure Data (a visual dataflow) whose unofficial motto was "The diagram is the program" I got this philosophy stuck deep in my brain. Today I use Org-Mode (In Emacs) for tangling (with something called Babel) that can run source code…

I remember my first day of advanced computer graphics (25 years ago, so advanced then wasn’t advanced now) the whole class was shocked when the professor did his dramatic start of class saying “you should never document your code!”…dramatic pause…”you should code your document”. I still think of that today when I’m writing complex algorithms. I write everything first in prose. Then translate that to a more list like…

What you describe sounds like top down development (“in the small”). When you try to use it for bottom-up reasoning, you get Jupyter notebooks.

Re: Literate programming is much more than just commenting code

#45

I like literate programming in theory but the most common response I see to it is that writing self documenting code is better because as you are working on a code base with many people, it is unlikely they will keep your prose up to date as the code is changed.

> self documenting code is better because as you are working on a code base with many people, it is unlikely they will keep your prose up to date as the code is changed.

There is no reason to believe they are any more likely to keep code self-documenting (or to succeed even if they try) - it is not as if it will not compile or run unless it is.

I see literate programming to be an attempt to put some rigor into the otherwise terminally vague concept of self-documenting code (conceptually, it is way beyond the platitudes in 'clean code', even though it came first.) It is, however, doomed to failure in practice because it always takes less information (and less skill) to merely specify what a program will do than it does to not only specify what it will do but also explain and justify that as a correct and efficient solution to a problem that matters.

Neither 'literate' nor 'self-documenting' code are objective concepts.

Re: Literate programming is much more than just commenting code

#46
post #11

The problems one will run into with literate programming: 1. Lack of tooling. 2. Refactoring becomes nontrivial 3. How one would write a program in literate style will vary widely from person to person. If you write your code in literate style, it may be easy for you to follow it years later and modify it, but it likely will not be the case for a coworker. If they have to modify the code, the cognitive load will not…

Problems 1 and 3 I could imagine. I would need to learn how to be a better writer to share a literate program. As someone experienced in the topic, What's the biggest hurdle when trying to refactor the code?

> What's the biggest hurdle when trying to refactor the code?

I'd guess it's updating cross-references in prose and rewriting chapters of documentation which no longer make sense after your refactoring.

Re: Literate programming is much more than just commenting code

#47

My favorite literate program still has to be the book "Physically Based Rendering". An optimized, feature rich ray tracer in the form of a textbook. That said, I wouldn't personally want to try and collaborate on such a program with more than one other person. It would make for a great single-contributer OSS library though. Rubber duck debugging built right into the prose.

https://smile.amazon.com/gp/product/1541259335 is also a great book. As is Stanford GraphBase.

My personal bet is that it is probably easier to collaborate on something like this than you would think. The imposed structure of programs, in general, already makes a lot of collaboration tough.

Re: Literate programming is much more than just commenting code

#48

What are the key differences between a human audience and a machine interpreter? It is not the language or prose. It is the structure and order. For machines, details comes first. You declare all the actors and types with every non-forgiving annotations first. You may tuck the details into a header, but it still needs be ordered according to compilers and structured in the way that machines gets the details first. On…

Context can be expresses with thin, somewhat redundant interfaces that group code around how they map to desiderata. Eg the meat in “matrix pseudoinverse” and “linear regression” is the same, but you can expose domain-meaningful abstractions. Regular OOP does “tangle and weave” without the messy text transformation mechanics.

Re: Literate programming is much more than just commenting code

#49
post #39
post #20

Earlier quoted context omitted.

Have you actually read TeX: The Book? It is far from “extremely flawed”.

Well, I have neither read through the entire 500 pages of tex.pdf[1] nor the 25k lines of tex.web[2], but I certainly have an impression of both. I think it is very hard to comprehend what one single part of a given algorithm does and it's imho almost impossible to get a good picture of how all these pieces fit together. [1] https://texdoc.org/serve/tex.pdf/0 [2] https://mirror.las.iastate.edu/tex-archive/systems/knu…

Ok, tex.pdf is the same as TeX: The Book, but obviously rendered into a PDF instead of a hardcover book.

The chapters of the book each cover one aspect of the whole system. Sometimes it is a data type (such as boxes, hash tables, token lists, stacks, etc), other times it is functions that operate on them (creating/printing/copying/destroying boxes, for instance), other times it is an algorithm. Giving each chapter a coherent topic like this allows the human reader to comprehend them in isolation, without distractions from unrelated code. Modern languages have more facilities for high–level abstractions than Pascal did, so you could argue that this is no longer necessary, but I disagree.

Chapter 38 Breaking paragraphs into lines is a good example; it is all about the algorithm for breaking paragraphs into lines that fit into whatever width is currently available. The first thing he does is give a very high–level overview of the purpose of this code (line breaking of paragraphs), what primitives it operates on (boxes and vertical lists), the source of the algorithm (a paper he coauthored a few years previously), plus the improvements made to that algorithm (less memory usage, less likely to encounter numeric overflow).

He then discusses how this algorithm interacts with the rest of the system. It is called with one explicit argument, and relies on this and that global state. It makes certain changes to that global state. It also adds a single global variable not previously mentioned, and here is where we start to see the benefit of Web over plain Pascal. Pascal requires that all global variables be declared ahead of time, before any of the functions are declared and before the block of code that forms the body of the program. If we were reading the Pascal source code directly, we would see dozens or hundreds of these declarations before we even know what part of the program they are for, and before we even know what parts the program has. Instead, we see here that a single declaration is added to section 13, Global Variables. All the other globals are hidden from view, because they aren’t relevant to the task of line breaking a paragraph:

    〈 Global variables 13 〉 +≡
    just_box : pointer ; { the hlist node for the last line of the new paragraph }
Next, we are given an outline of the whole line_break procedure, where we can see that it has four basic steps:

    〈 Declare subprocedures for line break 826 〉
    procedure line_break (final_widow_penalty : integer );
      label done , done1 , done2 , done3 , done4 , done5 , continue ;
      var 〈 Local variables for line breaking 862 〉
      begin pack_begin_line ← mode_line ; { this is for over/underfull box messages }
      〈 Get ready to start line breaking 816 〉;
      〈 Find optimal breakpoints 863 〉;
      〈 Break the paragraph at the chosen breakpoints, justify the resulting lines to the correct widths, and
           append them to the current vertical list 876 〉;
      〈 Clean up the memory by removing the break nodes 865 〉;
      pack_begin_line ← 0;
      end;
The third of those steps is rather more complex than the others, which is perhaps a little unusual. Also, the second step was the subject of a whole paper. Regardless, this is a pretty good overview of the process: Identify the optimal breakpoints, then rebuild the data structures so that instead of one line of text that doesn’t fit we have a vertical list of lines of text that do fit.

If we immediately saw a few hundred lines of code here, we would have no idea what any of them were doing, or why.

Of course, modern programming languages are much more expressive than Pascal. If this program had been written in Rust, for example, then the code would have started out much more readable. The boxes would be defined in a crate of their own, so that no global definitions would need to be inserted into the main crate. The main crate would have a single `use` line for the box crate, and would probably refer to box–related types and functions using prefixed names like `box::short_display` or `box::fast_delete_glue_ref`. The `line_box` function would only be as long as this overview here, because all of the small tasks that it does would be packaged up into iterators and such. That third subtask in the overview might literally be `current_vlist = break_paragraph(para, breakpoints).iter().map(justify_line).collect()`. The overview would almost not be necessary; the code is approaching the expressiveness of the overview.

I think that this hows that that the literate programming style that Knuth uses does not make it “very hard to comprehend what one single part of a given algorithm does”, nor is it “almost impossible to get a good picture of how all these pieces fit together”. I think it enables Knuth to explain everything in a much clearer way than he ever could have done with comments in the source code. I think that many programs could benefit from a similar treatment, even when they are written in better languages than Pascal.

Re: Literate programming is much more than just commenting code

#50

Earlier quoted context omitted.

I think the one potential mitigating factor is that new features can be entirely new "chapters". Thanks to the tangling, a feature that needs to be added in 10 different places in the code can be written completely separately from the rest of the code. Additionally, bugs can be fixed in-situ, refactoring can occur at will, and neither would require the prose around them to change, since code being talked about (despi…

It seems like adding new code as "Chapters," unless pursued with a bit of self-discipline, may result in spahgetti which is worse than a non-literate style. Imagine a multi-person project where every little feature gets its own file, and now the programmer has to find the source of the bug between interacting blocks of in code fragments split across multiple files, ehich are combined together by tooling.... oh wait,…

> unless pursued with a bit of self-discipline

Any programming unless pursued with a bit of self-discipline may result in spaghetti code.

Post reply on HN