[HN Gopher] J one-page interpreter fragment (1992)
       ___________________________________________________________________
        
       J one-page interpreter fragment (1992)
        
       Author : Tomte
       Score  : 56 points
       Date   : 2021-01-25 12:59 UTC (10 hours ago)
        
 (HTM) web link (code.jsoftware.com)
 (TXT) w3m dump (code.jsoftware.com)
        
       | zserge wrote:
       | Some time ago I've made a humble decoding of this wonderful code
       | snippet: https://zserge.com/posts/j/
        
         | daneelsan wrote:
         | Thanks for this!
        
           | daneelsan wrote:
           | I don't get why the 5 in '5 + tr(...)'. t+r+d[3] is 5, I
           | guess? The verb function should return an I and not an A.
           | e->tokens in the wd function.
        
           | bear8642 wrote:
           | Indeed - was confused what elements of struct were on line 2.
           | 
           | Thanks for explaining
        
         | dang wrote:
         | Discussed here: https://news.ycombinator.com/item?id=22831931
        
       | userbinator wrote:
       | Its density is many times higher than most C programs, but that's
       | no big obstacle to understanding if you don't attempt to "skim"
       | it; you need to read it character-by-character from top to
       | bottom. It starts off defining some basic types, C for Character
       | and I for Integer, and then the all-important Array. This is
       | followed by some more shorthand for printf, return, and functions
       | of one and two arguments, all of the array type. The DO macro is
       | used to make iteration more concise.
       | 
       | Then the function definitions begin. ma allocates an array of n
       | integers (this code is hardcoded for a 32-bit system), mv is
       | basically memcpy, tr (Total Rank?) is used to compute the total
       | number of elements, and ga (Get/Generate Array) allocates an
       | array.
       | 
       | This is followed by the definitions of all the primitive
       | operations (interestingly, find is empty), a few more globals,
       | and then the main evaluator body. Lastly, main contains the REPL.
       | 
       | While I don't think this style is suitable for most programmers,
       | it's unfortunate that the industry seems to have gone towards the
       | other extreme.
        
         | maest wrote:
         | Btw, this is considered more or less canonical k style. (with q
         | being a slighty more readable version of this)
         | 
         | It takes some time getting used to it, but, once you get the
         | hang of it, going back to e.g. Python/Pandas is painful.
        
       | wassenaar10 wrote:
       | Somehow still more readable than actual J code
        
         | avmich wrote:
         | Unlikely. The point of writing C in this manner was to bring C
         | closer to APL - or J, which was an evolution of APL at the
         | time. So that J interpreter would be written in a form of J
         | language. J language itself doesn't need to satisfy also C
         | syntax, so J code is somewhat easier.
        
       | KMnO4 wrote:
       | The repository[0] for J is just as unreadable (albeit with
       | slightly more white space). I don't know how a project is managed
       | like this. Even the file names look obfuscated.
       | 
       | [0]: https://github.com/tavmem/j
        
         | jpfr wrote:
         | That is pretty readable C... for developers from that
         | particular community.
         | 
         | The ngn/k implementation of the k language [1] is even more
         | terse.
         | 
         | [1] https://git.sr.ht/~ngn/k/tree
        
         | sndean wrote:
         | I think this is the main J repo [0]. (Though I'm not sure if
         | it's any more readable.) Possibly interesting that Tavmem is
         | the maintainer of Kona (open source K3/4). I guess he's
         | comfortable with all APL/J/K languages.
         | 
         | [0] https://github.com/jsoftware/jsource
        
         | geocar wrote:
         | > The repository[0] for J is just as unreadable
         | 
         | People who can read this find it readable.
         | 
         | I think it's a mistake to think that because you can't read the
         | code, that it is the _code_ that is somehow unreadable, instead
         | of a language you simply haven 't learned to read.
         | 
         | > I don't know how a project is managed like this.
         | 
         | It's not dissimilar to working with any proprietary programming
         | language: You have to learn how to read and write this
         | language.
         | 
         | The fact that we can use an existing language's compiler can be
         | confusing to people who don't know that language very well, but
         | if you approach it from the perspective of a new (proprietary)
         | language, using an existing language's compiler can be a great
         | way to leverage the benefits of that existing language.
        
           | MontyCarloHall wrote:
           | >People who can read this find it readable.
           | 
           | > I think it's a mistake to think that because you can't read
           | the code, that it is the code that is somehow unreadable,
           | instead of a language you simply haven't learned to read.
           | 
           | The same could be said about Brainfuck. With enough effort
           | people can learn to read almost anything; that doesn't mean
           | that everything is equally readable.
        
             | bidirectional wrote:
             | Brainfuck is so simple that it is trivial to read. The
             | problem there is a semantic one rather than a syntactic
             | one, you cannot build any abstractions. J-style C has all
             | the semantic expressiveness of C, and chooses a terse, but
             | fairly uniform style.
        
           | AshamedCaptain wrote:
           | > I think it's a mistake to think that because you can't read
           | the code, that it is the code that is somehow unreadable,
           | instead of a language you simply haven't learned to read.
           | 
           | This argument is significantly weakened when simply removing
           | the meaningless macros and adding whitespace improves
           | readability.
           | 
           | It's not like it is complicated because it is written in a
           | structurally different language, nor will you actually
           | leverage any benefit from learning this language. It's just
           | obfuscated under the guise of abbreviation.
        
             | avmich wrote:
             | > This argument is significantly weakened when simply
             | removing the meaningless macros and adding whitespace
             | improves readability.
             | 
             | Yes, but for this case adding whitespace actually decreases
             | readability. At least if you know Whitney's hate of
             | scrolling.
        
             | geocar wrote:
             | > This argument is significantly weakened when simply
             | removing the meaningless macros and adding whitespace
             | improves readability.
             | 
             | I disagree wholeheartedly. Whitespace tends to move code
             | further away from the code that uses it; scrolling and tab-
             | flipping requires the developer hold that code _in their
             | head_ where it is most likely to degrade. It is much _much_
             | better to make them remember as little as possible.
             | 
             | It also helps reuse: If you don't scroll, you can see more
             | code, so you can see if something is a good candidate for
             | abstracting, just because you can _see_ them doing the same
             | thing.
             | 
             | Macros like this help with that, and so they aren't
             | "meaningless". Less whitespace helps with that, and so it
             | actually improves readability (to those who have to read
             | it!).
             | 
             | The trade-off is that you can't hire someone with "C" on
             | their CV and expect them to be productive on their first
             | day, but in a complex codebase, this might not be possible
             | for other reasons.
        
       | lihaoyi wrote:
       | While this example is pretty dense, a "one page programming
       | language interpreter" doesn't need to be so impenetrable. Here's
       | a one-page (67 line) interpreter for a subset of the Jsonnet
       | programming language, implemented in Scala:
       | 
       | - https://github.com/handsonscala/handsonscala/blob/v1/example...
       | 
       | From the top down, that snippet contains an AST definition, a
       | parser, an object model, an evaluator, and an output serializer.
       | This 67-line programming language interpreter is one of the
       | projects in my book https://www.handsonscala.com/ (chapter 20),
       | and while this example is minimal the same techniques were used
       | for my production-ready Sjsonnet interpreter
        
       | avisaven wrote:
       | I actually used this as inspiration for a little self-challenge
       | to write a programming language in 24hrs not too long ago [1]. I
       | didn't get quite as far as I'd've liked to, but nonetheless if
       | you have some time to kill, it was an extremely fun task to
       | tackle.
       | 
       | [1] https://github.com/block8437/afternoon-lang
        
       | dang wrote:
       | If curious see also
       | 
       | 2017 https://news.ycombinator.com/item?id=14463874
       | 
       | 2016 (one comment): https://news.ycombinator.com/item?id=12654054
       | 
       | 2014 https://news.ycombinator.com/item?id=8533843
       | 
       | Related from last year:
       | https://news.ycombinator.com/item?id=22831931
       | 
       | I'm pretty sure there have been other threads about this,
       | probably via different articles.
        
       | skruger wrote:
       | A good walk-through of this code is here:
       | https://rickyhan.com/jekyll/update/2020/01/16/j-incunabulum-...
        
       | danmg wrote:
       | It leaks memory on every line it evaluates.
        
         | avmich wrote:
         | I'm sure memory management was left to deal with later. In
         | Roger Hui variant, memory leaks were eliminated early on, on a
         | systemic level.
        
         | MontyCarloHall wrote:
         | I guess freeing all those pointers returned by ma() would be
         | too verbose.
         | 
         | Seriously though, this must have been a deliberate design
         | decision? Arthur Whitney is no amateur.
        
       | DaiPlusPlus wrote:
       | Question: where/how are the `mv` and `pr` functions defined? And
       | how does this even compile when it's using `gets` without
       | `#include <stdio.h>` ?
       | 
       | I do see it's using the `implicit int` rule though.
        
         | naters wrote:
         | `mv` is defined on the same line as `ma` is, right after the
         | five `#define`s.
         | 
         | `pr` is on the last line before the only line break.
         | 
         | It's a pretty dense program to walk through, but not as
         | completely impenetrable as I first thought after taking some
         | time and making notes as I went.
        
         | userbinator wrote:
         | This is pre-C89, K&R C.
        
       | jonjacky wrote:
       | Here is a recent C program in a similar compressed style, a
       | Scheme compiler:
       | 
       | https://c9x.me/qscm/data/qscm.c
       | 
       | via this page which was recently linked on HN:
       | 
       | https://c9x.me/qscm/
        
       | eimrine wrote:
       | Is there any Lisp interpretation on J language? I have hard time
       | searching anything called with one letter only.
        
         | rscho wrote:
         | Anyways, info about J can pretty much be found only on its
         | website (jsoftware.com), so don't really bother looking
         | elsewhere. The only other good place is Rosettacode.
         | 
         | What do you mean by "Lisp interpretation on J language"?
         | 
         | There's an APL in Common Lisp called April. Otherwise, there's
         | an unfinished J interpreter on the Racket package manager.
        
           | eimrine wrote:
           | Sorry for incorrectness, I want to look at interpreter of any
           | dialect of Lisp language, written in J, if the one exists. I
           | found J's approach to syntax interesting to explore.
        
             | kd0amg wrote:
             | Writing a lisp interpreter in J won't really do more to
             | help explore J's syntax than writing anything else in J. It
             | might be a good way to explore how J handles tree-like
             | data, but that's not really something J is designed to do
             | well (if you _really_ want to use an array-oriented
             | language for tree processing, Aaron Hsu 's dissertation
             | covers a range of techniques that are more scalable than
             | the naive nest-of-short-boxed-vectors approach typically
             | used in J).
        
       | rscho wrote:
       | What people often miss with J is how good it is for exploratory
       | programming due to its terseness and most importantly its
       | integrated columnar store. It replaced R for data wrangling in my
       | stats programs, and relegated it to just running the models.
       | 
       | Once you get used to it, it's really a breeze and far easier to
       | modify than 500+ sloc R scripts.
       | 
       | Of course, that does not work for everyone, and especially not
       | for big teams, but still!
        
         | vmchale wrote:
         | > It replaced R for data wrangling in my stats programs
         | 
         | Do you find it faster?
         | 
         | I have good experiences with J due to its terseness, but I'm
         | curious why scientists still use R/Python - is it just inertia?
         | Libraries/FFI?
        
           | rscho wrote:
           | Faster to program yes, massively so. Faster to execute, it
           | depends on what I'm doing, but it's never a problem for me as
           | my data is usually pretty small and quite messy. It doesn't
           | feel slow at all, at least. And obviously if you're doing
           | arrays you'll certainly not run faster in Python/R.
           | 
           | As for R/Python it's mostly familiarity with the notation
           | (especially for python) and established popularity, with a
           | large ecosystem as a consequence.
           | 
           | I mean, as a beginner in Python it just works (slowly). As a
           | beginner in J, you cry... The interesting distinction is that
           | Python/R APIs can be quite convoluted and the rug may be
           | pulled from under you without warning, while in J you learn
           | the primitives and you're off to the races. Also, J is much
           | faster for its use case and avoids the need to write C in
           | most cases where using it is relevant.
        
       | up2isomorphism wrote:
       | I want to point out the large part of "unreadability" feeling
       | here comes from the fact the code is pre-ANSI C89. so tr(r,d)I
       | _d;{I z=1;DO(r,z=z_ d[i]);R z;} is just a function definition.
       | 
       | I would say the structurally this extremely easy to read
       | considering there is zero comments and the way it is presented.
       | One can make this readability obvious by just expand the macros,
       | change indentations and add line breaks, or, you can just spend
       | several days to "get used" to it like Roger Hui (and Arthur who
       | just use this kind of style for life).
        
       ___________________________________________________________________
       (page generated 2021-01-25 23:02 UTC)