Code Comparison
Zig
const std = @import("std");
test {
var str = "The C Programming Language".*;
str[4] += 23;
std.debug.print("{s}\n", .{str});
}
BQN
str ← "The C Programming Language"
str ↩ str + -'C' = str
"The B Programming Language"
∾"BQN"⌾(4⊸⊑) str
"The BQN Programming Language"
J
#! /usr/bin/env ijconsole
str =: 'The C Programming Language'
str =: (a. {~ 7 + a. i. 4 { str) 4 } str
echo str
exit 0
APL
str ← 'The C Programming Language'
str[5] ← ⎕UCS ¯2+⎕UCS str[5]
str
The A Programming Language
Lil
str:"The C Programming Language"
"The C Programming Language"
# representation math with byte array
a:array[count str "u8"].cat[str]
<array>
a[4]:a[4]+9
"" fuse a.slice[0 "char"] @ range count str
"The L Programming Language"
str[4]:"Lil" # mutates
"The Lil Programming Language"
Zig dereferences an array in static memory to get a mutable copy, increments 'C' to change the language, and the prints the string. The J is a complete script that changes 'C' to 'J' instead. The APL is from an interactive session, and goes with 'A' for a comparable example.
The Zig is typical of static non-APL languages in that there's a bit going on in the code that's unrelated to the task. But, still, it's a short and straightforward example. The APL I think looks pretty nice, especially compared to the J. The index syntax has its faults but they don't show up here. The J is... well, at 4 { str it fetches 'C' from the string, then 7 + a. i. finds the index of 'C' in the ASCII table and then adds 7 to the index, and then a. {~ looks up that index in the ASCII table, and finally 4 } str puts 'J' into the string, and with str =: and without aliases, this is a proper mutation. Geez. I don't think it's that bad, but it certainly doesn't compare well. I haven't tried to refine the J any, but the Zig and especially the APL also haven't had any special effort; these are all first attempts.
J rewrites
Anyway, let's give J some additional attempts.
Defining some ⎕UCS like words:
fc =: a. i. ] NB. from char
tc =: a. {~ ] NB. to char
str =: 'The C Programming Language'
str =: str 4 }~ tc 7 + fc 4 { str
str
The J Programming Language
Defining a 'mutate this element with this verb' adverb:
mut =: 1 : 'y x }~ tc u fc x { y'
str =: 'The C Programming Language'
]str =: 4 (7&+) mut str
The J Programming Language
Maybe just try more suggestive formatting?
str =: 'The C Programming Language'
]str =: str 4}~ a.{~ 7 + a.i. 4{str
The J Programming Language
Or even:
str =: 'The C Programming Language'
]str =: 4}&str a.{~ 7 + a.i. 4{str
The J Programming Language
I think that last one's the best, emphasizing idioms a.i. to convert a char to a number, a.{~ to do the reverse, etc.
You could say that it's unfortunate that it took some rewrites to get good code, but that'll improve as skill with J improves.
How about Unicode?
Zig
The original version of this page used D instead of Zig, which compared much more favorably to the J. Zig anyway is extremely distracted by memory management here:
test {
var str: std.BoundedArray(u8, 64) = try .init(0);
var buf: [4]u8 = undefined;
var it: std.unicode.Utf8Iterator = .{ .bytes = "这种C编程语言", .i = 0 };
var i: usize = 0;
while (it.nextCodepoint()) |u| : (i += 1) {
if (i == 2) {
try str.append('Z');
} else {
const n = try std.unicode.utf8Encode(u, &buf);
try str.appendSlice(buf[0..n]);
}
}
std.debug.print("{s}\n", .{str.slice()});
}
BQN
BQN strings are lists of codepoints, so there's no difference at all:
str ← "这种C编程语言"
str + -'C' = str
"这种B编程语言"
∾"BQN"⌾(2⊸⊑) str
"这种BQN编程语言"
J
#! /usr/bin/env ijconsole
str =: ucp '这种C编程语言'
str =: utf8 2}&str a.{~ 7 + a.i. 2{str
echo str
exit 0
J's working with reference to a. ("Alphabet"), a 256-length array of ASCII characters. This is code with some suggestivity: you could do the same with reference to some other array, say for cryptographic purposes.