{"id":171,"date":"2016-07-03T18:11:38","date_gmt":"2016-07-03T18:11:38","guid":{"rendered":"http:\/\/procyonic.org\/blog\/?p=171"},"modified":"2016-10-03T12:29:44","modified_gmt":"2016-10-03T12:29:44","slug":"a-critique-of-the-programming-language-j","status":"publish","type":"post","link":"https:\/\/procyonic.org\/blog\/a-critique-of-the-programming-language-j\/","title":{"rendered":"A Critique of The Programming Language J"},"content":{"rendered":"<p>I&#8217;ve spent around a year now fiddling with and eventually doing real<br \/>\ndata analytic work in the <a title=\"The Programming Language J\" href=\"https:\/\/en.wikipedia.org\/wiki\/J_(programming_language)\" target=\"_blank\">The Programming Language J<\/a>. <em>J<\/em> is one of<br \/>\nthose languages which produces a special enthusiasm from its users and<br \/>\nin this way it is similar to other unusual programming languages like<br \/>\nForth or Lisp. My peculiar interest in the language was due to no<br \/>\nlonger having access to a Matlab license, wanting an array oriented<br \/>\nlanguage to do analysis in, and an attraction to brevity and the point<br \/>\nfree programming style, two aspects of programming which J emphasizes.<\/p>\n<figure id=\"attachment_173\" aria-describedby=\"caption-attachment-173\" style=\"width: 264px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/procyonic.org\/blog\/wp-content\/uploads\/2016\/07\/iverson.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-173\" src=\"http:\/\/procyonic.org\/blog\/wp-content\/uploads\/2016\/07\/iverson.jpg\" alt=\"Sorry, Ken.\" width=\"264\" height=\"191\" \/><\/a><figcaption id=\"caption-attachment-173\" class=\"wp-caption-text\">Sorry, Ken.<\/figcaption><\/figure>\n<p>I&#8217;ve been moderately happy with it, but after about a year of light<br \/>\nwork in the language and then a month of work-in-earnest (writing<br \/>\ninterfaces to gnuplot and hive and doing Bayesian inference and<br \/>\nspectral clustering) I now feel I am in a good position to offer a<br \/>\nfriendly critique of the language.<\/p>\n<h2>First, The Good<\/h2>\n<p>J is terse to nearly the point of obscurity. While terseness is not a<br \/>\nparticularly valuable property in a general purpose programming<br \/>\nlanguage (that is, one meant for Software Engineering), there is a<br \/>\ncase to be made for it in a data analytical language. Much of my work<br \/>\ninvolves interactive exploration of the structure of data and for that sort<br \/>\nof workflow, being able to quickly try a few different ways of<br \/>\nchopping, slicing or reducing some big pile of data is pretty<br \/>\nhandy. That you can also just copy and paste these snippets into some<br \/>\nanalysis pipeline in a file somewhere is also nice. In other words,<br \/>\nterseness allows an agile sort of development style.<\/p>\n<p>Much of this terseness is enabled by built in support for tacit<br \/>\nprogramming. What this means is that certain expressions in J are<br \/>\ninterpreted at <em>function level<\/em>. That is, they denote, given a set of<br \/>\nverbs in a particular arrangement, a new verb, without ever explicitly<br \/>\nmentioning values.<\/p>\n<p>For example, we might want a function which adds up all the maximum<br \/>\nvalues selected from the rows of an array. In J:<\/p>\n<pre><code>+\/@:(&gt;.\/\"1)\r\n<\/code><\/pre>\n<p>J takes considerable experience to read, particularly in Tacit<br \/>\nstyle. The above denotes, from RIGHT to LEFT: for each row (<code>\"1<\/code>)<br \/>\nreduce (<code>\/<\/code>) that row using the maximum operation <code>&gt;.<\/code> and then (<code>@:<\/code>)<br \/>\nreduce (<code>\/<\/code>) the result using addition (<code>+<\/code>). In english, this means:<br \/>\nfind the max of each row and sum the results.<\/p>\n<p>Note that the <em>meaning<\/em> of this expression is itself a verb, that is<br \/>\nsomething which operates on data. We may capture that meaning:<\/p>\n<pre><code>sumMax =: +\/@:(&gt;.\/\"1)\r\n<\/code><\/pre>\n<p>Or use it directly:<\/p>\n<pre><code>+\/@:(&gt;.\/\"1) ? (10 10 $ 10)\r\n<\/code><\/pre>\n<p>Tacit programming is enabled by a few <em>syntactic<\/em> rules (the so-called<br \/>\nhooks and forks) and by a bunch of function level operators called<br \/>\nadverbs and conjuctions. (For instance, <code>@:<\/code> is a conjunction rougly<br \/>\ndenoting function composition while the expression <code>+\/ % #<\/code> is a fork,<br \/>\ndenoting the average operation. The <code>forkness<\/code> is that it is three<br \/>\nexpressions denoting verbs separated by spaces.<\/p>\n<p>The details obscure the value: its nice to program at function level<br \/>\nand it is nice to have a terse denotation of common operations.<\/p>\n<p>J has one other really nice trick up its sleeve called <em>verb<br \/>\nrank<\/em>. Rank itself is not an unusual idea in data analytic languages:<br \/>\nit just refers to the length of the shape of the matrix; that is, its<br \/>\ndimensionality.<\/p>\n<p>We might want to say a bit about J&#8217;s basic evaluation strategy before<br \/>\nexplaining rank, since it makes the origin of the idea more clear. All<br \/>\nverbs in J take one or two arguments on the left and the right. Single<br \/>\nargument verbs are called monads, two argument verbs are called dyads.<br \/>\nVerbs can be either monadic or dyadic in which case we call the<br \/>\ninvocation itself monadic or dyadic. Most of J&#8217;s built-in operators<br \/>\nare both monadic and dyadic, and often the two meanings are unrelated.<\/p>\n<p>NB. monadic and dyadic invocations of &lt;<br \/>\n4 &lt; 3 NB. evaluates to 0<br \/>\n&lt;3 NB. evalutes to 3, but in a box.<\/p>\n<p>Give that the arguments (usually called <code>x<\/code> and <code>y<\/code> respectively) are<br \/>\noften matrices it is natural to think of a verb as some sort of matrix<br \/>\noperator, in which case it has, like any matrix operation, an expected<br \/>\ndimensionality on its two sides. This is sort of what verb rank is<br \/>\nlike in J: the verb itself carries along some information about how<br \/>\nits logic operates on its operands. For instance, the built-in verb<br \/>\n<code>-:<\/code> (called <em>match<\/em>) compares two things structurally. Naturally, it<br \/>\napplies to its operands as a whole. But we might want to compare two<br \/>\n<em>lists<\/em> of objects via match, resulting in a list of results. We can<br \/>\ndo that by modifying the rank of <code>-:<\/code><\/p>\n<p>x -:&#8221;(1 1) y<\/p>\n<p>The expression -:&#8221;(1 1) denotes a version of match which applies to<br \/>\nthe elements of x and y, each treated as a list. Rank in J is roughly<br \/>\nanalogous the the use of repmat, permute and reshape in Matlab: we can<br \/>\nuse rank annotations to quickly describe how verbs operate on their<br \/>\noperands in hopes of pushing looping down into the C engine, where<br \/>\nit can be executed quickly.<\/p>\n<p>To recap: array orientation, terseness, tacit programming and rank are<br \/>\nthe really nice parts of the language.<\/p>\n<h2>The Bad and the Ugly<\/h2>\n<p>As a programming environment J can be productive and efficient, but it<br \/>\nis not without flaws. Most of these have to do with irregularities in<br \/>\nthe syntax and semantics which make the language confusing without<br \/>\noffering additional power. These unusual design choices are<br \/>\nparticularly apparent when J is compared to more modern programming<br \/>\nlanguages.<\/p>\n<h3>Fixed Verb Arities<\/h3>\n<p>As indicated above, J verbs, the nearest cousin to functions or<br \/>\nprocedures from other programming languages, have arity 1 or<br \/>\narity 2. A single symbol may denote expressions of both arity, in<br \/>\nwhich case context determines which function body is executed.<\/p>\n<p>There are two issues here, at least. The first is that we often want<br \/>\nfunctions of <em>more than<\/em> two arguments. In J the approach is to pass<br \/>\nboxed arrays to the verb. There is some syntactic sugar to support<br \/>\nthis strategy:<\/p>\n<p>multiArgVerb =: monad define<br \/>\n&#8216;arg1 arg2 arg3&#8217; =. y<br \/>\nNB. do stuff<br \/>\n)<\/p>\n<p>If a string appears as the left operand of the <code>=.<\/code> operator, then<br \/>\nsimple destructuring occurs. Boxed items are unboxed by this<br \/>\noperation, so we typically see invocations like:<\/p>\n<pre><code>multiArgVerb('a string';10;'another string')\r\n<\/code><\/pre>\n<p>But note that the expression on the right (starting with the open<br \/>\nparentheses) just denotes a boxed array.<\/p>\n<p>This solution is fine, but it does short-circuit J&#8217;s notion of verb<br \/>\nrank: we may specify the the rank with which the function operates on<br \/>\nits left or right operand as a whole, but not on the individual<br \/>\n&#8220;arguments&#8221; of a boxed array. But nothing about the concept of rank<br \/>\ndemands that it be restricted to one or two argument functions: rank<br \/>\nentirely relates to how arguments are extracted from array valued<br \/>\nprimitive arguments and dealt to the verb body. This idea can be<br \/>\ngeneralized to functions of arbitrary argument count.<\/p>\n<p>Apart from this, there is the minor gripe that denoting such single<br \/>\nuse boxed arrays with <code>;<\/code> feels clumsy. Call that the Lisper&#8217;s bias:<br \/>\nthe best separator is the space character.<sup>1<\/sup><\/p>\n<p>A second, related problem is that you can&#8217;t have a<br \/>\n<em>zero<\/em> argument function either. This isn&#8217;t the only language where<br \/>\nthis happens (Standard ML and OCaml also have this tradition, though I<br \/>\nthink it is weird there too). The problem in J is that it would feel<br \/>\n<em>natural<\/em> to have such functions and to be able to mention them.<\/p>\n<p>Consider the following definitions:<\/p>\n<pre><code>o1 =: 1&amp;-\r\no2 =: -&amp;1\r\n\r\n(o1 (0 1 2 3 4)); (o2 (0 1 2 3 4))\r\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\r\n\u25021 0 _1 _2 _3\u2502_1 0 1 2 3\u2502\r\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\r\n<\/code><\/pre>\n<p>So far so good. Apparently using the <code>&amp;<\/code> conjunction (called &#8220;bond&#8221;)<br \/>\nwe can partially apply a two-argument verb on either the left or the<br \/>\nright. It is natural to ask what would happen if we <em>bond<\/em>ed twice.<\/p>\n<blockquote><p>(o1&amp;1)<br \/>\no1&amp;1<\/p><\/blockquote>\n<p>Ok, so it produces a verb.<\/p>\n<pre><code> 3 3 $ ''\r\n  ;'o1'\r\n  ;'o2'\r\n  ;'right'\r\n  ;((o1&amp;1 (0 1 2 3 4))\r\n  ; (o2&amp;1 (0 1 2 3 4))\r\n  ;'left'\r\n  ; (1&amp;o1 (0 1 2 3 4))\r\n  ; (1&amp;o2 (0 1 2 3 4)))\r\n\r\n\u250c\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\r\n\u2502     \u2502o1          \u2502o2          \u2502\r\n\u251c\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\r\n\u2502right\u25021 0 1 0 1   \u25021 0 _1 _2 _3\u2502\r\n\u251c\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\r\n\u2502left \u25021 0 _1 _2 _3\u2502_1 0 1 2 3  \u2502\r\n\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\r\n<\/code><\/pre>\n<p>I would describe these results as goofy, if not entirely impossible to<br \/>\nunderstand (though I challenge the reader to do so). However, none of<br \/>\nthem really seem right, in my opinion.<\/p>\n<p>I would argue that one of two possibilities would make some sense.<\/p>\n<ol>\n<li>(1&amp;-)&amp;1 -&gt; 0 (eg, 1-1)<\/li>\n<li>(1&amp;-)&amp;1 -&gt; 0&#8243;_ (that is, the constant function returning 0)<\/li>\n<\/ol>\n<p>That many of these combinations evaluate to <code>o1<\/code> or <code>o2<\/code> is doubly<br \/>\nconfusing because it ignores a value AND because we can denote<br \/>\nconstant functions (via the rank conjunction), as in the expression<br \/>\n<code>0\"_<\/code>.<\/p>\n<h2>Generalizations<\/h2>\n<p>What this is all about is that <em>J<\/em> doesn&#8217;t handle the idea of a<br \/>\n<em>function<\/em> very well. Instead of having a single, unified abstraction<br \/>\nrepresenting operations on things, it has a variety of different ideas<br \/>\nthat are function-like (verbs, conjuctions, adverbs, hooks, forks,<br \/>\ngerunds) which in a way puts it ahead of a lot of old-timey languages<br \/>\nlike Java 7 without first order functions, but ultimately this<br \/>\nhandful of disparate techniques fails to acheive the conceptual unity<br \/>\nof first order functions with lexical scope.<\/p>\n<p>Furthermore, I suggest that nothing whatsoever would be lost (except<br \/>\n<em>J<\/em>&#8216;s interesting historical development) by collapsing these ideas<br \/>\ninto the more typical idea of closure capturing functions.<\/p>\n<h2>Other Warts<\/h2>\n<h3>Weird Block Syntax<\/h3>\n<p>Getting top-level<sup>2<\/sup> semantics right is hard in any<br \/>\nlanguage. Scheme is <a href=\"http:\/\/calculist.blogspot.com\/2009\/01\/fexprs-in-scheme.html\">famously<\/a> ambiguous on the subject, but at<br \/>\nleast for most practical purposes it is comprehensible. Top-level has<br \/>\nthe same syntax and semantics as any other body of code in scheme<br \/>\n(with some restrictions about where <code>define<\/code> can be evaluated) but in<br \/>\n<em>J<\/em> neither is the same.<\/p>\n<p>We may write <em>block strings<\/em> in J like so:<\/p>\n<pre><code>blockString =: 0 : 0 \r\nEverything in here is a block string.       \r\n)\r\n<\/code><\/pre>\n<p>When the evaluator reads <code>0:0<\/code> it switches to sucking up characters<br \/>\ninto a string until it encounters a line with a <code>)<\/code> as its first<br \/>\ncharacter. The verb <code>0:3<\/code> does the same except the resulting string is<br \/>\nturned into a verb.<\/p>\n<pre><code>plus =: 3 : 0\r\n    x+y\r\n)\r\n<\/code><\/pre>\n<p>However, we can&#8217;t nest this syntax, so we can&#8217;t define non-tacit<br \/>\nfunctions inside non-tacit functions. That is, this is illegal:<\/p>\n<pre><code>plus =: 3 : 0\r\n  plusHelper =. 3 : 0\r\n    x+y\r\n  )\r\n  x plusHelper y\r\n)\r\n<\/code><\/pre>\n<p>This forces to the programmer to do a lot of <em>lambda lifting<\/em><br \/>\nmanually, which also forces them to bump into the restrictions on<br \/>\nfunction arity and their poor interaction with rank behavior, for if<br \/>\nwe wish to capture parts of the private environment, we are forced to<br \/>\npass those parts of the environment in as an argument, forcing us to<br \/>\ngive up rank behavior or forcing us to jump up a level to verb<br \/>\nmodifiers.<\/p>\n<h3>Scope<\/h3>\n<p>Of course, you can define local functions if you do it tacitly:<\/p>\n<pre><code>plus =: 3 : 0\r\n    plusHelper =. +\r\n    x plusHelper y   \r\n)\r\n<\/code><\/pre>\n<p>But, even if you are defining a conjunction or an adverb, whence you<br \/>\nare able to &#8220;return&#8221; a verb, you can&#8217;t capture any local functions &#8211;<br \/>\nthey disappear as soon as execution leaves the conjunction or adverb<br \/>\nscope.<\/p>\n<p>That is because <em>J<\/em> is dynamically scoped, so any capture has to be<br \/>\nhandled manually, using things like adverbs, conjunctions, or the good<br \/>\nold fashioned fix <code>f.<\/code>, which inserts values from the current scope<br \/>\ndirectly into the representation of a function. Essentially all modern<br \/>\nlanguages use lexical scope, which is basically a rule which says: the<br \/>\nvalue of a variable is exactly what it <em>looks like<\/em> from reading the<br \/>\nprogram. Dynamic scope says: the valuable of the variable is whatever<br \/>\nits most recent binding is.<\/p>\n<h1>Recapitulation!<\/h1>\n<p>The straight dope, so to speak, is that J is great for a lot of<br \/>\nreasons (terseness, rank) but also a lot of irregular language<br \/>\nfeatures (adverbs, conjunctions, hooks, forks, etc) which could be<br \/>\nfolded all down into regular old functions without harming the<br \/>\nbenefits of the language, and simplifying it enormously.<\/p>\n<p>If you don&#8217;t believe that regular old first order functions with<br \/>\nlexical scope can get us where we need to go, check out my<br \/>\ntacit-programming libraries in <a href=\"https:\/\/github.com\/VincentToups\/fugu\"><em>R<\/em><\/a> and <a href=\"https:\/\/github.com\/VincentToups\/puff\"><em>Javascript<\/em><\/a>. I<br \/>\neven wrote a complete, if ridiculously slow implementation of <em>J<\/em>&#8216;s<br \/>\nrank feature, literate-style, <a href=\"http:\/\/procyonic.org\/blog\/?p=137\">here<\/a>.<\/p>\n<hr \/>\n<h2>Footnotes<\/h2>\n<p><sup>1<\/sup> It bears noting that <code>;<\/code> in an expression like <code>(a;b;c)<\/code><br \/>\nis not a syntactic element, but a semantic one. That is, it is the<br \/>\nverb called &#8220;link&#8221; which has the effect of linking its arguments into<br \/>\na boxed list. It is evaluated like this:<\/p>\n<pre><code>(a;(b;c))\r\n<\/code><\/pre>\n<p><code>(a;b;c)<\/code> is nice looking but a little strange: In an expression<br \/>\n<code>(x;y)<\/code> the effect depends on y is boxed already or not: x is always boxed regardless, but <code>y<\/code> is boxed only if it wasn&#8217;t boxed before.<\/p>\n<p><sup>2<\/sup> Top level? Top-level is the context where everything<br \/>\n&#8220;happens,&#8221; if anything happens at all. Tricky things about top-level<br \/>\nare like: can functions refer to functions which are not yet defined,<br \/>\nif you read a program from top to bottom? What about values? Can you<br \/>\nredefine functions, and if so, how do the semantics work? Do functions<br \/>\nwhich call the redefined function change their behavior, or do they<br \/>\ncontinue to refer to the old version? What if the calling interface<br \/>\nchanges? Can you check types if you imagine that functions might be<br \/>\nredefined at any time? If your language has classes, what about<br \/>\ninstances created before a change in the class definition. Believe or<br \/>\nnot, Common Lisp tries to let you do this &#8211; and its confusing!<\/p>\n<p>On the opposite end of the spectrum are really static languages like<br \/>\nHaskell, wherein type enforcement and purity ensure that the top-level<br \/>\nis only meaningful as a monolith, for the most part.<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve spent around a year now fiddling with and eventually doing real data analytic work in the The Programming Language J. J is one of those languages which produces a special enthusiasm from its users and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"footnotes":""},"categories":[19,10,18,47,16,38],"tags":[20,39,40,42,41],"class_list":["post-171","post","type-post","status-publish","format-standard","hentry","category-data-analysis","category-development","category-j","category-programming","category-science","category-work","tag-j-2","tag-jsoftware","tag-matlab","tag-rank","tag-tacit-programming"],"_links":{"self":[{"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/posts\/171","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/comments?post=171"}],"version-history":[{"count":11,"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/posts\/171\/revisions"}],"predecessor-version":[{"id":190,"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/posts\/171\/revisions\/190"}],"wp:attachment":[{"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/media?parent=171"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/categories?post=171"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/procyonic.org\/blog\/wp-json\/wp\/v2\/tags?post=171"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}