4 ms·
Mr. Klabnik goes in depth into the argument that literate programming has to be tangled and weaved into a different order, in order to be considered "true" lite
by jashkenas 16y ago
Mr. Klabnik goes in depth into the argument that literate programming has to be tangled and weaved into a different order, in order to be considered "true" literate programming.
Respectfully, I have to disagree.
It may have been the case that a macro source-code rewriter was necessary before the advent of the subroutine, but in this day and age you can factor out functions as you see fit. Moving around source code with macros is an unnecessary obfuscation between the code you read, and the code as it runs. At any point where you're tempted to pull out a block of code and interpolate it later, just make it a function with a descriptive name, and hey presto.
Edit: Steve wrote it.
- steveklabnik 16y agoActually, this one is by me. Getting some author tags are on the feature list for Timeless. ;) You'll have to take that argument up with Knuth, and not with me, though. Also, while you may be thinking of some languages, many others don't make it easy to re-arrange code. C code, for example, pretty much has to be in order. Unless you write a CPP macro. Which is basically the same as a documentation macro. (ps: oh, and this doesn't mean I don't <3 Docco. Part of writing this post was so that I could stop blathering about it to all of my friends.)
- jashkenas 16y agoI agree entirely. My point is just that in any modern language at a reasonable level of granularity, the order in which you write the code is 99% independent from the order in which you execute it. To port tangle/weave for a modern language would be to cargo cult a feature that can't possibly help matters, in my opinion. That said, I'd love to see an example (in a modern language) where a woven bit of literate code was more readable than the well-factored equivalent.
- steveklabnik 16y agoYep. I certainly don't think that this is as large of a problem now, and I'm unsure if it'd be a large value add. I think that Rocco's presentation over RDoc/YARD is a much, much larger step forward.
- evanrmurphy 16y ago> My point is just that in any modern language at a reasonable level of granularity, the order in which you write the code is 99% independent from the order in which you execute it. I believe that in most dialects of lisp, macros must be defined before they can be called. [citation needed] This is not to undermine your point, which I think is valid. Macros would just be an interesting exception because they're arguably the feature of lisp, and surely make up > 1% usage for that family of programming languages.
- steveklabnik 16y ago> Macros should be written so as to depend as little as possible on the execution environment to produce a correct expansion. To ensure consistent behavior, it is best to ensure that all macro definitions are available, whether to the interpreter or compiler, before any code containing calls to those macros is introduced. - Common Lisp the Language, http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/html/cltl/clm/node97.html http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/html/c...
- evanrmurphy 16y agoThat was also the most relevant snippet I found while searching. :) Unfortunately, I couldn't quite figure out if it was a confirmation of my claim or a rebuttal. Would you mind clarifying?
- steveklabnik 16y agoI know about as much as you do. I did some googling, and maybe it's because I'm sitting at pitt.edu, but cmu.edu seems authoritative. ;) To me, this paragraph says "using a macro before it's defined is undefined behavior," and seems to back up your assertion.
- thisrod 16y agoScheme code that takes advantage of lexical scope with indefinite extent might qualify: The functions f, g and h use private variables x and y. (define f #f) (define g #f) (define h #f) (let ((x #f) (y #f)) (set! f <<Lambda term for f>>) (set! g <<Lambda term for g>>) (set! h <<Lambda term for h>>)) F does whatever. <<Lambda term for f>>= (lambda (p q) (21 lines of code)) G does something else <<Lambda term for g>>= (20 lines of code) ...
- jerf 16y ago"You'll have to take that argument up with Knuth, and not with me, though." And.... so what? We don't all run to Alan Kay for our definitions of object orientation, we don't all run to John McCarthy for a definition of a lambda calculus-based programming language, and we don't all go running to Dijkstra as the final word in structured programming techniques. No disrespect intended to Knuth any more than I intend disrespect to the three other shining luminaries I name, but if we're still arguing about Literate Programming's original Knuth definition 26 years later that is nothing more and nothing less than a testament to the utter failure of the term. Note carefully how I said the term has failed. In point of fact I think what has happened is that the core ideas that led to the formation of literate programming has indeed essentially succeeded (if not exactly "won") and does indeed live on in languages with abstractions powerful enough that they don't need an additional mangling step layered on top of them and already have powerful comment conventions, some even machine readable. We've found that we don't need to narrate the entire program, but just some bits, and that a "literate" approach isn't always the best. If we have not adopted every last trapping of Knuth's proscription, it is not because it hasn't been tried, it is because it wasn't perfect, any more than any of the three luminaries I mentioned above managed to give us the Last Word on any of those topics. I'm not particularly all that interested in Knuth's precise definition in my day-to-day life any more than I sit here agonizing over the fact that my primary language's object model is in gross violation of a couple of Alan Kay's ideas about OO. We've refined our ideas about documentation a lot since 1984, in all kinds of ways. And I think Knuth-style LP has some serious cost/benefit problems in modern times that didn't exist at the time of the original proposal; maybe in 1984 I'd use it, but the costs have at best stayed steady and maybe even crept up a bit (as you are now no longer augmenting code with good reordering capabilities but now supplementing and interacting with their capabilities and adding additional complexity thereby), while the relative benefits have plummeted unless you're still stuck in 1980s era languages with 1980s era design techniques.
- steveklabnik 16y agoUpvoted. > We don't all run to Maybe you don't. ;) I try to keep terms as sacred as possible, usually... What I was trying to say is this: I don't feel that I have the right to redefine Knuth's term. Yes, it may not be the best anymore, and as MenTaLguY suggested a few minutes ago[1], maybe a rename or rebranding is in order, but I don't feel comfortable saying "Literate Programming is x", for all x that isn't what Knuth said. I think we're in agreement about the questionableness of the value if going 'fully literate,' which I tried to hint at in my last few paragraphs. I haven't ever written such a program, and so I can't really say if I think it's worth it or not. However, lately I find myself on a quest to compare and contrast and blend together English and code, and so it's something of a great interest to me, and so I do happen to care about those that have come before, for both their successes and their failures. 1: http://twitter.com/#!/mentalguy/status/24667821577338880 http://twitter.com/#!/mentalguy/status/24667821577338880
- jmillikin 16y ago> Mr. Klabnik goes in depth into the argument that literate programming has to be tangled and weaved into a different order, in order to be considered "true" literate programming. > Respectfully, I have to disagree. If you're not re-ordering the code, there's no difference between a "literate program" and simple comments. And I find code-reordering useful even in modern languages; most impose some structure like: 1. module-level documentation 2. exports 3. imports / includes 4. implementation (functions, procedures, etc) 4.1 return type (static languages only) 4.2 function/procedure documentation 4.3 code With literate programming, you can add supporting text (like export entries, module imports, or documentation) wherever would make the most sense for a human reader, not to the compiler. > At any point where you're tempted to pull out a block of code and interpolate it later, just make it a function with a descriptive name, and hey presto. What if you've got a few dozen local variables? Do you want to pass them all as parameters, for every single logical block in your algorithm? What sort of names do you give your extracted procedures? Literate programs can have block names like "Check for common post-traversal error conditions", which in a procedure name would likely be abbreviated to "traversed_errcheck()".
- jules 16y agoIt seems that folding code to a natural language summary is what you really want.
- jmillikin 16y agoNot at all; I want to be able to print stuff like this in the generated documentation: ---------------------------------------------- 3.2 HTTPS driver The HTTPS driver is currently implemented using either GNU TLS or OpenSSL: == driver includes #include <gnutls.h> #include <openssl.h> == driver list , {"HTTPS (GNU TLS)", driver_https_gnutls} , {"HTTPS (Open SSL)", driver_https_openssl} == drivers.c static void driver_https_gnutls(DriverState *s) { ||common driver local storage|| gnutls_init(); gnutls_ctx_init(&ctx); check_extra_algos = "FOO:BAR"; some_feature_flag = 1; // etc } static void driver_https_openssl(DriverState *s) { ||common driver local storage|| openssl_init(); check_extra_algos = "BAZ"; some_feature_flag = 0; // etc } ----------------------------------------------