Skip to content(if available)orjump to list(if available)

Ray Tracing in J

Ray Tracing in J

12 comments

·May 28, 2025

gcanyon

A few important bits this left out (as far as I read, which wasn't too far). Note: I am not a J expert, just a dabbler.

J's tacit syntax can generally transparently take either a single argument on the right, or two arguments, one on the left and one on the right.

In addition to the fork described in the article, J defines a "Hook" for two verbs (instead of the fork's three). A hook applies the right verb to the right argument, then applies the left verb with the original argument on the left and the result from the right verb on the right. Meaning:

   this gets the largest item from a list >./ 
   this divides the left by the right %
   so this scales every item in a list, so the largest becomes 1 and everything else becomes its ratio to the largest: %>./
J allows arbitrarily long strings of verbs: these get forked and hooked until you go insane trying to track it all in your brain.

Defining a function longer than a fork and using the same code inline can (often?) not give the same results. I think that's why the caps are needed in the magnitude function in the article.

I think the article is missing a trick on the magnitude-of-a-vector bit: J has a marvelous conjunction called "under" which, when applied to two verbs, first applies the first (right) verb, then applies the second verb to the result, and then unapplies the first verb.

So when you have the need to "sqrt the sum of the squares" you should immediately be noticing that sqrt and square are opposites, and be thinking "under".

   Under is &.:
   Sum is +/
   Square is *:
So magnitude can be expressed more succinctly (and I think more idiomatically, but again I'm not an expert) as:

magnitude =: +/&.:*:

magnitude 3 4

   5
magnitude 3 4 5

   7.07107

dfboyd

"[verbs] get forked and hooked until you go insane trying to track it all"

J comes with a Qt IDE, which has a function "dissect" that displays a graphical parse tree of an expression.

load 'debug/dissect'

dissect '(+/ % #) ? 10 $ 100'

gcanyon

Thanks! I haven't touched J in about ten years -- and I never used dissect -- and I never did anything serious in it, just about thirty project euler problems for fun.

anthk

That should have an ASCII art alternative too.

Vox_Leone

Fascinating article – a great example of J's array-processing power for concise, performant geometric computation.

It got me thinking about how different paradigms could complement this. I've been working on a Python project[0], which is a framework for quaternion-driven traversal of tree-like structures based on orientation rather than just position or order.

Essentially, J handles the low-level "how" of vector math at scale, while SpinStep-like concepts could provide a higher-level, more semantic "what" and "why" for decisions driven by explicit orientation sets and angular relationships.

It's an interesting thought experiment on combining the raw power of array languages for geometry with more specialized frameworks for orientation-based reasoning.

[0] https://github.com/VoxleOne/SpinStep

magicalhippo

Bit disappointed it wasn't a re-implementation of SmallPT[1].

Would have been interesting to see it deal with multiple different objects with different materials, the recursion and such.

Guess it shouldn't take that much to turn it into something like SmallPT.

[1]: https://kevinbeason.com/smallpt/

bobsmooth

Could someone write a script to find out how many times "<problem> in <single letter>" has been posted to HN?

MangoToupe

Yea but ray tracing is super fun. It's hard to be irritated with fun.

pasquinelli

what if i write one in J and then post it on HN?

libraryatnight

It'll make front page, and I'll follow it up with a blog post about why it changed my life to rewrite it in K.

ThrowawayTestr

Only if it counts itself