aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorMarshall Lochbaum <mwlochbaum@gmail.com>2021-12-20 22:02:06 -0500
committerMarshall Lochbaum <mwlochbaum@gmail.com>2021-12-20 22:02:06 -0500
commit55c82e40a499c95d6a823c49bbd91f745badadfd (patch)
tree5530e13bbe20c9881048e497f0c9de20d507b844 /docs
parent7d8e3be9529e624f228926fe8abfa8e7294dd9ed (diff)
Comparison with J
Diffstat (limited to 'docs')
-rw-r--r--docs/commentary/why.html64
1 files changed, 64 insertions, 0 deletions
diff --git a/docs/commentary/why.html b/docs/commentary/why.html
index 14d2bb20..7231e1d4 100644
--- a/docs/commentary/why.html
+++ b/docs/commentary/why.html
@@ -9,3 +9,67 @@
<p>If you haven't yet used an array language, BQN will present you with new ways of thinking that can streamline the way you work with data and algorithms. There's no denying that array programming has begun to creep into the mainstream, and you might be wondering if BQN has anything to offer when you can hack reduces and filters with the best of them. It does: real array programming is different in character, with more and better array operations on immutable multidimensional arrays, and syntax better suited to them. Performance that resembles a low-level compiled language more than a high-level dynamic one. Primitives flow together and compose better—one aspect that sets BQN apart from other array languages is a set of combinators that's more intuitive than previous attempts. I also happen to think BQN's <a href="../tutorial/expression.html#character-arithmetic">character arithmetic</a> system would improve just about any language.</p>
<p>If your favorite language is J, you are missing out even more! Array programmers never seem willing to accept that good ideas can come from people other than Iverson and that legends like John McCarthy and Barbara Liskov advanced human knowledge of how to express computation. They did, and being able to casually pass around first-class functions and mutable closures, with namespaces keeping everything organized, is a huge quality of life improvement. Writing APL again is claustrophobic, the syntax worries and constraints in functionality suddenly rushing back. BQN's mutable objects make methods such as graph algorithms that just don't have a good array implementation (no, your O(n³) matrix method doesn't scale) possible, even natural. With bytecode compilation and NaN-boxing, a natural fit for the based array model, it evaluates that scalar code many times faster than APL or J. The Unix-oriented scripting system stretches seamlessly from quick sketch to multi-file program.</p>
<p>BQN has no intention of being the last word in programming, but could be a practical and elegant tool in your kit—even if only used to inform your use of another language. Give it a try!</p>
+<h2 id="versus-apl-and-j"><a class="header" href="#versus-apl-and-j">Versus APL and J</a></h2>
+<p>Here are some more specific comparisons against the two most similar languages to BQN. I'll try to bring up the areas where BQN can be considered worse, but my focus here is definitely on BQN's strong points—I'm not trying to offer an unbiased account.</p>
+<p>BQN is more like APL, but adopts some of the developments made by J as well. However, it's much simpler than both, with fewer and less overloaded primitives as well as less special syntax (J has fewer syntactic rules, but more special cases handled during execution that I think <em>should</em> have been implemented with syntax).</p>
+<p>The major differences are listed on <a href="../index.html#whats-the-language-like">the front page</a> (&quot;But it's redesigned…&quot;): <a href="../doc/based.html">based arrays</a>, <a href="../doc/arrayrepr.html">list notation</a>, <a href="../doc/context.html">context-free grammar</a> and <a href="../doc/functional.html">first-class functions</a>, <a href="../doc/primitive.html">reworked primitives</a>, and dedicated <a href="../doc/namespace.html">namespace syntax</a>.</p>
+<h3 id="j"><a class="header" href="#j">J</a></h3>
+<p><em>J is under development again and a moving target. I stopped using it completely shortly after starting work on BQN in 2020, and while I try to keep up to date on language changes, some remarks here might not fit with the experience you'd get starting with J today.</em></p>
+<p>To me building with J feels like making a tower out of wood and nails by hand: J itself is reliable but I soon don't trust what I'm standing on. J projects start to feel hacky when I have multiple files, locales, or a bit of global state. With BQN I begin to worry about maintainability only when I have enough functions that I can't remember what arguments they expect, and with lexically-scoped variables I simply don't use global state. If you don't reach this scale (in particular, if you use J as a calculator or spreadsheet substitute) you won't feel these concerns, and will have less to gain by moving to BQN. And if you go beyond, you'd need to augment your programs with rigorous documentation and testing in either language.</p>
+<p>The biggest difference could be in file loading. If you write a script that depends on other files, and want it to work regardless of the directory it's called from, you need to deal with this. In J, <code><span class='Function'>&gt;</span><span class='Brace'>{</span><span class='Value'>:</span><span class='Number'>4</span><span class='Function'>!</span><span class='Value'>:</span><span class='Number'>3</span> <span class='String'>''</span></code> gives the name of the most recently loaded script (the current one, if you put it before any imports), but to make it into a utility you need this glob of what's-going-on:</p>
+<pre><span class='Value'>cur_script</span> <span class='Function'>=</span><span class='Value'>:</span> <span class='Brace'>{{</span><span class='Paren'>(</span><span class='Number'>4</span><span class='Function'>!</span><span class='Value'>:</span><span class='Number'>3</span><span class='Value'>$</span><span class='Number'>0</span><span class='Paren'>)</span> <span class='Brace'>{</span><span class='Value'>::~</span> <span class='Number'>4</span><span class='Function'>!</span><span class='Value'>:</span><span class='Number'>4</span><span class='Function'>&lt;</span><span class='String'>'y'</span><span class='Brace'>}}</span>
+</pre>
+<p>In BQN it's <code><span class='Value'>•path</span></code>. And usually you don't need it because <code><span class='Function'>•Import</span></code> resolves paths relative to the file containing it.</p>
+<p>J uses numeric codes; BQN uses mostly names. So J's <code><span class='Number'>1</span><span class='Value'>&amp;o.</span></code> is BQN's <code><span class='Value'>•math.</span><span class='Function'>Sin</span></code>, and <code><span class='Number'>6</span><span class='Function'>!</span><span class='Value'>:</span><span class='Number'>9</span></code> corresponds to BQN's <code><span class='Function'>•MonoTime</span></code>.</p>
+<p>J uses bytestrings by default, making Unicode handling a significant difficulty (<a href="https://code.jsoftware.com/wiki/Vocabulary/uco">see</a> <code><span class='Value'>u:</span></code>). BQN strings are lists of codepoints, so you don't have to worry about how they're encoded or fight to avoid splitting up UTF-8 bytes that need to go together.</p>
+<p>J locales are not first-class values, and BQN namespaces are. I think BQN's namespaces are a lot more convenient to construct, although it is lacking an inheritance mechanism (but J's path system can become confusing quickly). More importantly, BQN namespaces (and closures) are garbage collected. J locales leak unless manually freed by the programmer. More generally, J has no mutable data at all, and to simulate it properly you'd have to write your own tracing garbage collection as the J interpreter doesn't have any. I discussed this issue some in <a href="http://www.jsoftware.com/pipermail/programming/2021-April/058006.html">this J forum thread</a>.</p>
+<p>In J, each function has a built-in rank attribute: for example the ranks of <code><span class='Function'>+</span></code> are <code><span class='Number'>0</span> <span class='Number'>0</span> <span class='Number'>0</span></code>. This rank is accessed by the &quot;close&quot; compositions <code><span class='String'>@</span></code>, <code><span class='Value'>&amp;</span></code>, and <code><span class='Value'>&amp;.</span></code>. Choosing the shorter form for the close compositions—for example <code><span class='String'>@</span></code> rather than <code><span class='String'>@</span><span class='Value'>:</span></code>—is often considered a mistake within the J community. And function ranks are unreliable: consider that the ranks of <code><span class='Value'>]</span><span class='String'>@</span><span class='Value'>:</span><span class='Function'>+</span></code>, a function that behaves just like <code><span class='Function'>+</span></code>, are <code><span class='Modifier2'>_</span> <span class='Modifier2'>_</span> <span class='Modifier2'>_</span></code>. In BQN there aren't any close compositions at all, and no function ranks. J's <code><span class='Value'>&amp;.</span><span class='Function'>&gt;</span></code> is simply <code><span class='Modifier'>¨</span></code>, and other close compositions, in my opinion, just aren't needed.</p>
+<p>Gerunds are J's answer to BQN's first-class functions. For example J's <code><span class='Paren'>(</span><span class='Function'>+</span><span class='Value'>&amp;</span><span class='Number'>3</span><span class='Paren'>)</span><span class='Modifier'>`</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Value'>&amp;*</span><span class='Paren'>)</span><span class='String'>@</span><span class='Value'>.</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Value'>&amp;</span><span class='Function'>|</span><span class='Paren'>)</span></code> would be written <code><span class='Number'>2</span><span class='Modifier2'>⊸</span><span class='Function'>|</span><span class='Modifier2'>◶</span><span class='Bracket'>⟨</span><span class='Function'>+</span><span class='Modifier2'>⟜</span><span class='Number'>3</span><span class='Separator'>,</span><span class='Number'>2</span><span class='Modifier2'>⊸</span><span class='Function'>×</span><span class='Bracket'>⟩</span></code> with a list of functions. I think lists of functions are a big improvement, since there's no need to convert between gerund and function, and no worries about arrays that just happen to be valid gerunds (worried about losing the ability to construct gerunds? Constructing tacit functions in BQN is much easier). The usability gap widens because passing J functions around either as values or gerunds has presents some highly idiosyncratic challenges, discussed below.</p>
+<h4 id="named-functions"><a class="header" href="#named-functions">Named functions</a></h4>
+<p>Its impact on the programmer is smaller than a lot of the issues above, but this section describes a behavior that I find pretty hard to justify. What does the identifier <code><span class='Value'>fn</span></code> indicate in a J expression? The value of <code><span class='Value'>fn</span></code> in the current scope, one might suppose. Nope—only if the value is a noun. Let's make it a function.</p>
+<pre> <span class='Value'>fn</span> <span class='Function'>=</span><span class='Value'>:</span> <span class='Function'>-</span>
+ <span class='Value'>fn</span><span class='Modifier'>`</span><span class='Function'>-</span>
+<span class='Value'>┌──┬─┐</span>
+<span class='Value'>│fn│</span><span class='Function'>-</span><span class='Value'>│</span>
+<span class='Value'>└──┴─┘</span>
+</pre>
+<p>The tie adverb <code><span class='Modifier'>`</span></code> makes gerund representations of both operands and places them in a list. It returns <code><span class='String'>'</span><span class='Value'>fn</span><span class='String'>'</span><span class='Value'>;</span><span class='Separator'>,</span><span class='String'>'-'</span></code> here: two different strings for what we'd think of as the same function. But it's just being honest. The value of <code><span class='Value'>fn</span></code> really is more like a name than the primitive <code><span class='Function'>-</span></code>. To see this we can pass it in to an adverb that defines its own local, totally separate copy of <code><span class='Value'>fn</span></code>.</p>
+<pre> <span class='Value'>fn</span><span class='Brace'>{{</span><span class='Value'>u</span> <span class='Number'>3</span><span class='Brace'>}}</span>
+<span class='Modifier'>_3</span>
+ <span class='Value'>fn</span><span class='Brace'>{{</span>
+ <span class='Value'>fn</span> <span class='Function'>=</span><span class='Value'>.</span> <span class='Value'>%</span> <span class='Function'>NB</span><span class='Value'>.</span> <span class='Value'>local</span> <span class='Value'>assignment</span>
+ <span class='Value'>u</span> <span class='Number'>3</span>
+ <span class='Brace'>}}</span>
+<span class='Number'>0.333333</span>
+</pre>
+<p>That's right, it is not safe to use <code><span class='Value'>fn</span></code> as an operand! Instead you're expected to write <code><span class='Value'>fn</span> <span class='Value'>f.</span></code>, where <code><span class='Value'>f.</span></code> (<a href="https://code.jsoftware.com/wiki/Vocabulary/fdot">fix</a>) is a primitive that recursively expands all the names. Okay, but if you didn't have these weird name wrappers everywhere you wouldn't have to expand them. Why?</p>
+<pre> <span class='Value'>a</span> <span class='Function'>=</span><span class='Value'>:</span> <span class='Number'>3</span> <span class='Function'>+</span> <span class='Value'>b</span>
+ <span class='Value'>b</span> <span class='Function'>=</span><span class='Value'>:</span> <span class='Value'>a^:</span><span class='Paren'>(</span><span class='Number'>10</span><span class='Value'>&amp;</span><span class='Function'>&lt;</span><span class='Paren'>)</span> <span class='String'>@</span><span class='Value'>:</span> <span class='Function'>-</span><span class='Value'>:</span>
+ <span class='Value'>b</span> <span class='Number'>100</span>
+<span class='Number'>15.25</span>
+</pre>
+<p>This feature allows tacit recursion and mutual recursion. You can't do this in BQN, because <code><span class='Function'>A</span> <span class='Gets'>←</span> <span class='Number'>3</span> <span class='Function'>+</span> <span class='Function'>B</span></code> with no <code><span class='Function'>B</span></code> defined is a reference to an undefined identifier. You have to use <code><span class='Brace'>{</span><span class='Function'>B</span><span class='Value'>𝕩</span><span class='Brace'>}</span></code> instead. So this is actually kind of nice. 'Cept it's broken:</p>
+<pre> <span class='Value'>b</span> <span class='Value'>f.</span> <span class='Function'>NB</span><span class='Value'>.</span> <span class='Value'>impossible</span> <span class='Value'>to</span> <span class='Value'>fix</span> <span class='Value'>all</span> <span class='Value'>the</span> <span class='Value'>way</span>
+<span class='Paren'>(</span><span class='Number'>3</span> <span class='Function'>+</span> <span class='Value'>b</span><span class='Paren'>)</span><span class='Value'>^:</span><span class='Paren'>(</span><span class='Number'>10</span><span class='Value'>&amp;</span><span class='Function'>&lt;</span><span class='Paren'>)</span><span class='String'>@</span><span class='Value'>:</span><span class='Function'>-</span><span class='Value'>:</span>
+
+ <span class='Value'>b</span> <span class='Value'>f.</span><span class='Brace'>{{</span>
+ <span class='Value'>b</span> <span class='Function'>=</span><span class='Value'>.</span> <span class='Number'>2</span>
+ <span class='Value'>u</span> <span class='Number'>100</span>
+ <span class='Brace'>}}</span>
+<span class='Function'>|</span><span class='Value'>domain</span> <span class='Value'>error:</span> <span class='Value'>b</span>
+<span class='Function'>|</span> <span class='Value'>u</span> <span class='Number'>100</span>
+</pre>
+<p>A tacit-recursive function can't be called unless its definition is visible, period. We gained the ability to do this cool tacit recursion thing, and all it cost us was… the ability to reliably use functions as values at all, which should be one of the things tacit programming is <em>good</em> for.</p>
+<p>It gets worse.</p>
+<pre> <span class='Value'>g</span> <span class='Function'>=</span><span class='Value'>:</span> <span class='Function'>-</span>
+ <span class='Value'>f</span> <span class='Function'>=</span><span class='Value'>:</span> <span class='Value'>g</span>
+ <span class='Value'>g</span> <span class='Function'>=</span><span class='Value'>:</span> <span class='Function'>|</span><span class='Value'>.</span>
+ <span class='Value'>f</span> <span class='Value'>i.</span> <span class='Number'>3</span>
+<span class='Number'>2</span> <span class='Number'>1</span> <span class='Number'>0</span>
+ <span class='Function'>&lt;</span><span class='String'>@</span><span class='Value'>f</span> <span class='Value'>i.</span> <span class='Number'>3</span>
+<span class='Value'>┌─┬─┬─┐</span>
+<span class='Value'>│</span><span class='Number'>0</span><span class='Value'>│</span><span class='Number'>1</span><span class='Value'>│</span><span class='Number'>2</span><span class='Value'>│</span>
+<span class='Value'>└─┴─┴─┘</span>
+</pre>
+<p>This should not be possible. <code><span class='Value'>f</span></code> here doesn't behave like <code><span class='Function'>+</span></code>, or quite like <code><span class='Function'>|</span><span class='Value'>.</span></code>: in fact there is no function that does what <code><span class='Value'>f</span></code> does. The result of <code><span class='Value'>f</span></code> depends on the entire argument, but <code><span class='Function'>&lt;</span><span class='String'>@</span><span class='Value'>f</span></code> encloses rank 0 components! How long would it take you to debug an issue like this? It's rare, but I've run into it in my own code and seen similar reports on the forums.</p>
+<p>The cause is that the value of <code><span class='Value'>f</span></code> here—a named <code><span class='Value'>g</span></code> function—is not just a name, but also comes with a function rank. The function rank is set by the assignment <code><span class='Value'>f</span> <span class='Function'>=</span><span class='Value'>:</span> <span class='Value'>g</span></code>, and doesn't change along with <code><span class='Value'>g</span></code>. Calling <code><span class='Value'>f</span></code> doesn't rely on the rank, but <code><span class='String'>@</span></code> does, so <code><span class='Function'>&lt;</span><span class='String'>@</span><span class='Value'>f</span></code> effectively becomes <code><span class='Function'>&lt;</span><span class='String'>@</span><span class='Function'>|</span><span class='Value'>.</span><span class='String'>&quot;</span><span class='Function'>-</span></code>, mixing the two versions of <code><span class='Value'>g</span></code>. The only explanation I have for this one is implementation convenience.</p>