Planet Factor
John Benediktsson: PBRT
2026-02-03T15:00:00.000000Z
<p><a href="https://pbrt.org">PBRT</a> is an impressive photorealistic rendering system:</p>
<blockquote>
<p>From movies to video games, computer-rendered images are pervasive today.
<strong>Physically Based Rendering</strong> introduces the concepts and theory of
photorealistic rendering hand in hand with the source code for a
sophisticated renderer.</p>
</blockquote>
<p>The fourth edition of their book is now available <a href="https://www.amazon.com/Physically-Based-Rendering-fourth-Implementation/dp/0262048027?keywords=physically+based+rendering+4th+edition&qid=1671730412&sprefix=physically+based%2Caps%2C145&sr=8-1&linkCode=ll1&tag=pharr-20&linkId=81a816d90f0c7e872617f1f930a51fd6&language=en_US&ref_=as_li_ss_tl">on
Amazon</a>
as well as freely available <a href="https://pbr-book.org/">online</a>.</p>
<p>
<img src="https://re.factorcode.org/images/2026-02-03-bookcover-4ed.jpg" alt="" width="384" height="495" />
</p>
<p>I thought it would be fun to explore the <a href="https://pbrt.org/fileformat-v4">PBRT v4 file
format</a> using
<a href="https://factorcode.org">Factor</a>.</p>
<p>Here’s a short example <code>pbrt</code> file from their website:</p>
<pre tabindex="0"><code class="language-pbrt" data-lang="pbrt">LookAt 3 4 1.5 # eye
.5 .5 0 # look at point
0 0 1 # up vector
Camera "perspective" "float fov" 45
Sampler "halton" "integer pixelsamples" 128
Integrator "volpath"
Film "rgb" "string filename" "simple.png"
"integer xresolution" [400] "integer yresolution" [400]
WorldBegin
# uniform blue-ish illumination from all directions
LightSource "infinite" "rgb L" [ .4 .45 .5 ]
# approximate the sun
LightSource "distant" "point3 from" [ -30 40 100 ]
"blackbody L" 3000 "float scale" 1.5
AttributeBegin
Material "dielectric"
Shape "sphere" "float radius" 1
AttributeEnd
AttributeBegin
Texture "checks" "spectrum" "checkerboard"
"float uscale" [16] "float vscale" [16]
"rgb tex1" [.1 .1 .1] "rgb tex2" [.8 .8 .8]
Material "diffuse" "texture reflectance" "checks"
Translate 0 0 -1
Shape "bilinearmesh"
"point3 P" [ -20 -20 0 20 -20 0 -20 20 0 20 20 0 ]
"point2 uv" [ 0 0 1 0 1 1 0 1 ]
AttributeEnd
</code></pre><p>And this is what it might look like:</p>
<p>
<img src="https://re.factorcode.org/images/2026-02-03-simple-v4.png" alt="" width="200" height="200" />
</p>
<p>Using our new <a href="https://github.com/factor/factor/blob/master/extra/pbrt/pbrt.factor">pbrt
vocabulary</a>,
we can convert that text into a set of
<a href="https://docs.factorcode.org/content/article-tuples.html">tuples</a> that we
could do computations on, or potentially look into rendering or processing.
And, of course, it also supports round-tripping back and forth from text to
tuples.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl"> T{ pbrt-look-at
</span></span><span class="line"><span class="cl"> { eye-x <span class="m">3 </span>}
</span></span><span class="line"><span class="cl"> { eye-y <span class="m">4 </span>}
</span></span><span class="line"><span class="cl"> { eye-z <span class="m">1.5 </span>}
</span></span><span class="line"><span class="cl"> { look-x <span class="m">0.5 </span>}
</span></span><span class="line"><span class="cl"> { look-y <span class="m">0.5 </span>}
</span></span><span class="line"><span class="cl"> { look-z <span class="m">0 </span>}
</span></span><span class="line"><span class="cl"> { up-x <span class="m">0 </span>}
</span></span><span class="line"><span class="cl"> { up-y <span class="m">0 </span>}
</span></span><span class="line"><span class="cl"> { up-z <span class="m">1 </span>}
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-camera
</span></span><span class="line"><span class="cl"> { type <span class="s">"perspective"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"float"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"fov"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">45 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-sampler
</span></span><span class="line"><span class="cl"> { type <span class="s">"halton"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"integer"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"pixelsamples"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">128 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-integrator { type <span class="s">"volpath"</span> } { params { } } }
</span></span><span class="line"><span class="cl"> T{ pbrt-film
</span></span><span class="line"><span class="cl"> { type <span class="s">"rgb"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"string"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"filename"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="s">"simple.png"</span> } }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"integer"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"xresolution"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">400 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"integer"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"yresolution"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">400 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-world-begin }
</span></span><span class="line"><span class="cl"> T{ pbrt-light-source
</span></span><span class="line"><span class="cl"> { type <span class="s">"infinite"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"rgb"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"L"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">0.4 0.45 0.5 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-light-source
</span></span><span class="line"><span class="cl"> { type <span class="s">"distant"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"point3"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"from"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">-30 40 100 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"blackbody"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"L"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">3000 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"float"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"scale"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">1.5 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-attribute-begin }
</span></span><span class="line"><span class="cl"> T{ pbrt-material { type <span class="s">"dielectric"</span> } { params { } } }
</span></span><span class="line"><span class="cl"> T{ pbrt-shape
</span></span><span class="line"><span class="cl"> { type <span class="s">"sphere"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"float"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"radius"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">1 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-attribute-end }
</span></span><span class="line"><span class="cl"> T{ pbrt-attribute-begin }
</span></span><span class="line"><span class="cl"> T{ pbrt-texture
</span></span><span class="line"><span class="cl"> { name <span class="s">"checks"</span> }
</span></span><span class="line"><span class="cl"> { value-type <span class="s">"spectrum"</span> }
</span></span><span class="line"><span class="cl"> { class <span class="s">"checkerboard"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"float"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"uscale"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">16 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"float"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"vscale"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">16 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"rgb"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"tex1"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">0.1 0.1 0.1 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"rgb"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"tex2"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">0.8 0.8 0.8 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-material
</span></span><span class="line"><span class="cl"> { type <span class="s">"diffuse"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"texture"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"reflectance"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="s">"checks"</span> } }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-translate { x <span class="m">0 </span>} { y <span class="m">0 </span>} { z <span class="m">-1 </span>} }
</span></span><span class="line"><span class="cl"> T{ pbrt-shape
</span></span><span class="line"><span class="cl"> { type <span class="s">"bilinearmesh"</span> }
</span></span><span class="line"><span class="cl"> { params
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"point3"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"P"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values
</span></span></span><span class="line"><span class="cl"> { <span class="m">-20 -20 0 20 -20 0 -20 20 0 20 20 0 </span>}
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-param
</span></span><span class="line"><span class="cl"> { type <span class="s">"point2"</span> }
</span></span><span class="line"><span class="cl"> { name <span class="s">"uv"</span> }
</span></span><span class="line"><span class="cl"> { <span class="nb">values </span>{ <span class="m">0 0 1 0 1 1 0 1 </span>} }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> T{ pbrt-attribute-end }
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>This is available now in the <a href="https://github.com/factor/factor">development version of
Factor</a>!</p>
John Benediktsson: Migrating to GTK3
2025-12-17T15:00:00.000000Z
<p><a href="https://factorcode.org">Factor</a> has a native
<a href="https://docs.factorcode.org/content/word-ui-backend,ui.backend.html">ui-backend</a>
that allows us to render our <a href="https://docs.factorcode.org/content/article-ui.html">UI
framework</a> using OpenGL
on top of platform-specific APIs for our primary targets of Linux, macOS,
and Windows.</p>
<p>On Linux, for a long time that has meant using the
<a href="https://www.gtk.org/">GTK2</a> library, which has also meant using
<a href="https://en.wikipedia.org/wiki/X_Window_System">X11</a> and an old library
called <code>libgtkglext</code> which provides a way to use OpenGL within GTK
windows. Well, Linux has moved on and is now pushing
<a href="https://wayland.freedesktop.org/">Wayland</a> as the “<em>replacement for the X11
window system protocol and architecture with the aim to be easier to
develop, extend, and maintain</em>”. Most modern Linux distributions have moved
to GTK3 or GTK4 and abstraction libraries like
<a href="https://github.com/anholt/libepoxy">libepoxy</a> for working with OpenGL and
others for supporting both X11 and Wayland renderers.</p>
<p>I was reminded of this after our recent <a href="https://re.factorcode.org/2025/12/factor-0-101-now-available.html">Factor
0.101</a> release when someone <a href="https://github.com/factor/factor/issues/3131#issuecomment-3638609485">asked
the
question</a>:</p>
<blockquote>
<p>Does that message mean that Factor still relies on GTK2? IIRC it was EOL:ed around 2020.</p>
</blockquote>
<p>Well, this is embarassing – yeah it sure does! Or rather – yes it sure did.</p>
<p>I got motivated to look into what it would take to support GTK3 or GTK4. We
had a pull request that was working through adding <a href="https://github.com/factor/factor/pull/3100">support for
GTK4</a>. After merging that, and
modifying it to also provide GTK3 support, I re-discovered that our OpenGL
rendering was generally using OpenGL 1.x pipelines and that would not work
in a GTK3+ world.</p>
<p>So, after adding OpenGL 3.x support for most of the things our user
interface needs, and <a href="https://docs.gtk.org/gtk3/migrating-2to3.html">migrating from GTK 2.x to
GTK3</a>, we now have
experimental nightly builds using the GTK3 backend:</p>
<p>
<img src="https://re.factorcode.org/images/2025-12-17-gtk3.png" alt="" width="845" height="866" />
</p>
<p>You can revert to the older GTK2 backend by applying this diff and then
performing a fresh bootstrap:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-diff" data-lang="diff"><span class="line"><span class="cl"><span class="gh">diff --git a/basis/bootstrap/ui/ui.factor b/basis/bootstrap/ui/ui.factor
</span></span></span><span class="line"><span class="cl"><span class="gh">index 2974e530f9..416704ce29 100644
</span></span></span><span class="line"><span class="cl"><span class="gd">--- a/basis/bootstrap/ui/ui.factor
</span></span></span><span class="line"><span class="cl"><span class="gi">+++ b/basis/bootstrap/ui/ui.factor
</span></span></span><span class="line"><span class="cl"><span class="gu">@@ -12,6 +12,6 @@ IN: bootstrap.ui
</span></span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> { [ os macos? ] [ "ui.backend.cocoa" ] }
</span></span><span class="line"><span class="cl"> { [ os windows? ] [ "ui.backend.windows" ] }
</span></span><span class="line"><span class="cl"><span class="gd">- { [ os unix? ] [ "ui.backend.gtk3" ] }
</span></span></span><span class="line"><span class="cl"><span class="gi">+ { [ os unix? ] [ "ui.backend.gtk2" ] }
</span></span></span><span class="line"><span class="cl"> } cond
</span></span><span class="line"><span class="cl"> ] if* require
</span></span><span class="line"><span class="cl"><span class="gh">diff --git a/basis/opengl/gl/extensions/extensions.factor b/basis/opengl/gl/extensions/extensions.factor
</span></span></span><span class="line"><span class="cl"><span class="gh">index 2d408e93bb..51394eeb4a 100644
</span></span></span><span class="line"><span class="cl"><span class="gd">--- a/basis/opengl/gl/extensions/extensions.factor
</span></span></span><span class="line"><span class="cl"><span class="gi">+++ b/basis/opengl/gl/extensions/extensions.factor
</span></span></span><span class="line"><span class="cl"><span class="gu">@@ -7,7 +7,7 @@ ERROR: unknown-gl-platform ;
</span></span></span><span class="line"><span class="cl"> << {
</span></span><span class="line"><span class="cl"> { [ os windows? ] [ "opengl.gl.windows" ] }
</span></span><span class="line"><span class="cl"> { [ os macos? ] [ "opengl.gl.macos" ] }
</span></span><span class="line"><span class="cl"><span class="gd">- { [ os unix? ] [ "opengl.gl.gtk3" ] }
</span></span></span><span class="line"><span class="cl"><span class="gi">+ { [ os unix? ] [ "opengl.gl.gtk2" ] }
</span></span></span><span class="line"><span class="cl"> [ unknown-gl-platform ]
</span></span><span class="line"><span class="cl"> } cond use-vocab >>
</span></span></code></pre></div><p>It seems like the newer OpenGL 3.x functions might introduce some lag which
is visible when scrolling on some installations, perhaps by not caching
certain things that were cached in the OpenGL 1.x code paths. There will
need to be some improvements before we are ready to release it, but it is
plenty usable as-is.</p>
<p>I also migrated our macOS backend to use the OpenGL 3.x functions as well to
allow us to more broadly test and improve these new rendering paths.</p>
<p>This is available in the latest <a href="https://github.com/factor/factor">development version</a>.</p>
John Benediktsson: DNS LOC Records
2025-12-10T15:00:00.000000Z
<p><a href="https://en.wikipedia.org/wiki/Domain_Name_System">DNS</a> is the <em>Domain Name
System</em> and is the backbone of the internet:</p>
<blockquote>
<p>Most prominently, it translates readily memorized domain names to the
numerical <a href="https://en.wikipedia.org/wiki/IP_address">IP addresses</a> needed
for locating and identifying computer services and devices with the
underlying <a href="https://en.wikipedia.org/wiki/Network_protocol">network protocols</a>.
The Domain Name System has been an essential component of the
functionality of the Internet since 1985.</p>
</blockquote>
<p>It is also an oft-cited reason for service outages, with a funny decade-old
<a href="https://www.reddit.com/r/sysadmin/comments/4oj7pv/comment/d4czk91/">r/sysadmin
meme</a>:</p>
<p>
<img src="https://re.factorcode.org/images/2025-12-10-its-always-dns.png" alt="" width="619" height="292" />
</p>
<p><a href="https://factorcode.org">Factor</a> has a <a href="https://docs.factorcode.org/content/vocab-dns.html">DNS
vocabulary</a> that
supports querying and parsing responses from
<a href="https://en.wikipedia.org/wiki/Name_server">nameservers</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="kn">USE:</span> <span class="nn">tools.dns</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"google.com"</span> host
</span></span><span class="line"><span class="cl">google.com has address 142.250.142.113
</span></span><span class="line"><span class="cl">google.com has address 142.250.142.138
</span></span><span class="line"><span class="cl">google.com has address 142.250.142.100
</span></span><span class="line"><span class="cl">google.com has address 142.250.142.101
</span></span><span class="line"><span class="cl">google.com has address 142.250.142.102
</span></span><span class="line"><span class="cl">google.com has address 142.250.142.139
</span></span><span class="line"><span class="cl">google.com has IPv6 address 2607:f8b0:4023:1c01:0:0:0:8b
</span></span><span class="line"><span class="cl">google.com has IPv6 address 2607:f8b0:4023:1c01:0:0:0:8a
</span></span><span class="line"><span class="cl">google.com has IPv6 address 2607:f8b0:4023:1c01:0:0:0:64
</span></span><span class="line"><span class="cl">google.com has IPv6 address 2607:f8b0:4023:1c01:0:0:0:65
</span></span><span class="line"><span class="cl">google.com mail is handled by <span class="m">10 </span>smtp.google.com
</span></span></code></pre></div><p>Recently, I bumped into an old post on the <a href="https://blog.cloudflare.com">Cloudflare
blog</a> about <a href="https://blog.cloudflare.com/the-weird-and-wonderful-world-of-dns-loc-records/">The weird and wonderful world of
DNS LOC
records</a>
and realized that we did not properly support parsing <a href="https://www.rfc-editor.org/rfc/rfc1876.txt">RFC
1876</a> which specifies a format
for returning <code>LOC</code> or <em>location</em> record specifying the <em>physical
location</em> of a service.</p>
<p>At the time of the post, Cloudflare indicated they handle <em>“millions of DNS
records; of those just 743 are LOCs.”</em>. I found a webpage that lists <a href="https://www.ckdhr.com/dns-loc/sites.html">sites
supporting DNS LOC</a> and contains
only nine examples.</p>
<p>It is not widely used, but it is very cool.</p>
<p>You can use the <a href="https://en.wikipedia.org/wiki/Dig_(command)">dig command</a>
to query for a <code>LOC</code> record and see what is returned:</p>
<pre tabindex="0"><code>$ dig alink.net LOC
alink.net. 66 IN LOC 37 22 26.000 N 122 1 47.000 W 30.00m 30m 30m 10m
</code></pre><p>The fields that were returned include:</p>
<ul>
<li>latitude (37° 22’ 26.00" N)</li>
<li>longitude (122° 1’ 47.00" W)</li>
<li>altitude (30.00m)</li>
<li>horizontal precision (30m)</li>
<li>vertical precision (30m)</li>
<li>entity size estimate (10m)</li>
</ul>
<p>In <a href="https://re.factorcode.org/2025/12/factor-0-101-now-available.html">Factor 0.101</a>, the field is
available and returned as bytes but not parsed:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"alink.net"</span> dns-LOC-query answer-section>> ...
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl"> T{ rr
</span></span><span class="line"><span class="cl"> { name <span class="s">"alink.net"</span> }
</span></span><span class="line"><span class="cl"> { type LOC }
</span></span><span class="line"><span class="cl"> { class IN }
</span></span><span class="line"><span class="cl"> { ttl <span class="m">300 </span>}
</span></span><span class="line"><span class="cl"> { rdata
</span></span><span class="line"><span class="cl"> B{
</span></span><span class="line"><span class="cl"> <span class="m">0 51 51 19 136 5 2 80 101 208 181 8 0 152 162 56
</span></span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>Of course, I love odd uses of technology like <a href="https://re.factorcode.org/2011/04/wikipedia-over-dns.html">Wikipedia over
DNS</a> and I thought
<a href="https://factorcode.org">Factor</a> should probably add proper support for the
<code>LOC</code> record!</p>
<p>First, we define a <a href="https://docs.factorcode.org/content/article-tuples.html">tuple
class</a> to hold the
<code>LOC</code> record fields:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">TUPLE:</span> <span class="nc">loc</span> <span class="nv">size</span> <span class="nv">horizontal</span> <span class="nv">vertical</span> <span class="nv">lat</span> <span class="nv">lon</span> <span class="nv">alt</span> <span class="k">;
</span></span></span></code></pre></div><p>Next, we parse the <code>LOC</code> record, converting sizes (in centimeters),
lat/lon (in degrees), and altitude (in centimeters):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">parse-loc</span> <span class="nf">( -- </span><span class="nv">loc</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"> loc <span class="nb">new
</span></span></span><span class="line"><span class="cl"> <span class="nb">read1 </span><span class="m">0 </span><span class="nb">assert=
</span></span></span><span class="line"><span class="cl"> <span class="nb">read1 </span>[ <span class="m">-4 </span><span class="nb">shift </span>] [ <span class="m">4 </span>bits ] <span class="nb">bi </span>10^ <span class="nb">* </span>>>size
</span></span><span class="line"><span class="cl"> <span class="nb">read1 </span>[ <span class="m">-4 </span><span class="nb">shift </span>] [ <span class="m">4 </span>bits ] <span class="nb">bi </span>10^ <span class="nb">* </span>>>horizontal
</span></span><span class="line"><span class="cl"> <span class="nb">read1 </span>[ <span class="m">-4 </span><span class="nb">shift </span>] [ <span class="m">4 </span>bits ] <span class="nb">bi </span>10^ <span class="nb">* </span>>>vertical
</span></span><span class="line"><span class="cl"> <span class="m">4 </span><span class="nb">read </span>be> <span class="m">31 </span><span class="nb">2^ - </span><span class="m">3600000 </span><span class="nb">/ </span>>>lat
</span></span><span class="line"><span class="cl"> <span class="m">4 </span><span class="nb">read </span>be> <span class="m">31 </span><span class="nb">2^ - </span><span class="m">3600000 </span><span class="nb">/ </span>>>lon
</span></span><span class="line"><span class="cl"> <span class="m">4 </span><span class="nb">read </span>be> <span class="m">10000000 </span><span class="nb">- </span>>>alt <span class="k">;
</span></span></span></code></pre></div><p>We hookup the <code>LOC</code> type to be parsed properly:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">M:</span> <span class="nc">LOC</span> <span class="nf">parse-rdata</span> <span class="nb">2drop </span>parse-loc <span class="k">;
</span></span></span></code></pre></div><p>And then build a word to print the location nicely:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">LOC.</span> <span class="nf">( </span><span class="nv">name</span> <span class="nf">-- )
</span></span></span><span class="line"><span class="cl"> dns-LOC-query answer-section>> [
</span></span><span class="line"><span class="cl"> rdata>> {
</span></span><span class="line"><span class="cl"> [ lat>> [ <span class="nb">abs </span><span class="m">1 </span><span class="nb">/mod </span><span class="m">60 </span><span class="nb">* </span><span class="m">1 </span><span class="nb">/mod </span><span class="m">60 </span><span class="nb">* </span>] [ <span class="nb">neg? </span><span class="s">"S"</span> <span class="s">"N"</span> <span class="nb">? </span>] <span class="nb">bi </span>]
</span></span><span class="line"><span class="cl"> [ lon>> [ <span class="nb">abs </span><span class="m">1 </span><span class="nb">/mod </span><span class="m">60 </span><span class="nb">* </span><span class="m">1 </span><span class="nb">/mod </span><span class="m">60 </span><span class="nb">* </span>] [ <span class="nb">neg? </span><span class="s">"W"</span> <span class="s">"E"</span> <span class="nb">? </span>] <span class="nb">bi </span>]
</span></span><span class="line"><span class="cl"> [ alt>> <span class="m">100 </span><span class="nb">/ </span>]
</span></span><span class="line"><span class="cl"> [ size>> <span class="m">100 </span><span class="nb">/i </span>]
</span></span><span class="line"><span class="cl"> [ horizontal>> <span class="m">100 </span><span class="nb">/i </span>]
</span></span><span class="line"><span class="cl"> [ vertical>> <span class="m">100 </span><span class="nb">/i </span>]
</span></span><span class="line"><span class="cl"> } <span class="nb">cleave </span><span class="s">"%d %d %.3f %s %d %d %.3f %s %.2fm %dm %dm %dm\n"</span> printf
</span></span><span class="line"><span class="cl"> ] <span class="nb">each </span><span class="k">;
</span></span></span></code></pre></div><p>And, finally, we can give it a try!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"alink.net"</span> LOC.
</span></span><span class="line"><span class="cl"><span class="m">37 22 26.000 </span>N <span class="m">122 1 47.000 </span>W 30.00m 30m 30m 10m
</span></span></code></pre></div><p>Yay, it matches!</p>
<p>This is available in the latest <a href="https://github.com/factor/factor">development
version</a>.</p>
John Benediktsson: Factor 0.101 now available
2025-12-09T03:00:00.000000Z
<p><em>“Keep thy airspeed up, lest the earth come from below and smite thee.” -
William Kershner</em></p>
<p>I’m very pleased to announce the release of <a href="https://factorcode.org">Factor</a>
0.101!</p>
<table class="downloads" cellspacing="0">
<colgroup>
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
</colgroup>
<thead>
<tr class="header">
<th class="nobg" style="text-align: center;">OS/CPU</th>
<th class="bg" style="text-align: center;" scope="col">Windows</th>
<th class="bg" style="text-align: center;" scope="col">Mac OS</th>
<th class="bg" style="text-align: center;" scope="col">Linux</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<th class="bg" style="text-align: center;" scope="row">x86</th>
<td class="supported">
<a href="https://downloads.factorcode.org/releases/0.101/factor-windows-x86-32-0.101.zip">0.101</a>
</td>
<td class="doesnotexist">
</td>
<td class="supported">
<a href="https://downloads.factorcode.org/releases/0.101/factor-linux-x86-32-0.101.tar.gz">0.101</a>
</td>
</tr>
<tr class="even">
<th class="bg" style="text-align: center;" scope="row">x86-64</th>
<td class="supported">
<a href="https://downloads.factorcode.org/releases/0.101/factor-windows-x86-64-0.101.zip">0.101</a>
</td>
<td class="supported">
<a href="https://downloads.factorcode.org/releases/0.101/factor-macos-x86-64-0.101.dmg">0.101</a>
</td>
<td class="supported">
<a href="https://downloads.factorcode.org/releases/0.101/factor-linux-x86-64-0.101.tar.gz">0.101</a>
</td>
</tr>
</tbody>
</table>
<p><strong>Source code</strong>: <a
href="https://downloads.factorcode.org/releases/0.101/factor-src-0.101.zip"
class="release">0.101</a></p>
<p>This release is brought to you with almost 700 commits by the following individuals:</p>
<blockquote>
<p>Aleksander Sabak, Andy Kluger, Cat Stevens, Dmitry Matveyev, Doug Coleman,
Giftpflanze, John Benediktsson, Jon Harper, Jonas Bernouli, Leo Mehraban, Mike
Stevenson, Nicholas Chandoke, Niklas Larsson, Rebecca Kelly, Samuel Tardieu,
Stefan Schmiedl, <a href="https://github.com/Bruno-366">@Bruno-366</a>,
<a href="https://github.com/bobisageek">@bobisageek</a>,
<a href="https://github.com/coltsingleactionarmyocelot">@coltsingleactionarmyocelot</a>,
<a href="https://github.com/inivekin">@inivekin</a>,
<a href="https://github.com/knottio">@knottio</a>, <a href="https://github.com/timor">@timor</a></p>
</blockquote>
<p>Besides some bug fixes and library improvements, I want to highlight the following changes:</p>
<ul>
<li>Moved the UI to render buttons and scrollbars rather than using images, which
allows easier theming.</li>
<li>Fixed <a href="https://re.factorcode.org/2025/09/hidpi.html">HiDPI</a> scaling on Linux and
Windows, although it currently doesn’t update the window settings when
switching between screens with different scaling factors.</li>
<li>Update to Unicode 17.0.0.</li>
<li>Plugin support for the <a href="https://re.factorcode.org/2025/08/neovim.html">Neovim editor</a>.</li>
</ul>
<p>Some possible backwards compatibility issues:</p>
<ul>
<li>The argument order to <code>ltake</code> was swapped to be more consistent with words like <code>head</code>.</li>
<li>The <code>environment</code> vocabulary on Windows now supports disambiguating <code>f</code> and <code>""</code> (empty) values</li>
<li>The <code>misc/atom</code> folder was removed in favor of the <a href="https://github.com/factor/atom-language-factor">factor/atom-language-factor</a> repo.</li>
<li>The <code>misc/Factor.tmbundle</code> folder was removed in favor of the <a href="https://github.com/factor/factor.tmbundle">factor/factor.tmbundle</a> repo.</li>
<li>The <code>misc/vim</code> folder was removed in favor of the <a href="https://github.com/factor/factor.vim">factor/factor.vim</a> repo.</li>
<li>The <code>http</code> vocabulary <code>request</code> tuple had a slot rename from <code>post-data</code> to <code>data</code>.</li>
<li>The <code>furnace.asides</code> vocabulary had a slot rename from <code>post-data</code> to <code>data</code>, and might require running <code>ALTER TABLE asides RENAME COLUMN "post-data" TO data;</code>.</li>
<li>The <code>html.streams</code> vocabulary was renamed to <code>io.streams.html</code></li>
<li>The <code>pdf.streams</code> vocabulary was renamed to <code>io.streams.pdf</code></li>
</ul>
<h3 id="what-is-factor">What is Factor</h3>
<p>Factor is a <a href="https://www.concatenative.org/">concatenative</a>, stack-based
programming language with <a href="https://concatenative.org/wiki/view/Factor/Features/The%20language">high-level
features</a>
including dynamic types, extensible syntax, macros, and garbage
collection. On a practical side, Factor has a <a href="https://docs.factorcode.org/content/article-vocab-index.html">full-featured
library</a>,
supports many different platforms, and has been extensively documented.</p>
<p>The implementation is <a href="https://concatenative.org/wiki/view/Factor/Optimizing%20compiler">fully
compiled</a>
for performance, while still supporting <a href="https://concatenative.org/wiki/view/Factor/Interactive%20development">interactive
development</a>.
Factor applications are portable between all common platforms. Factor
can <a href="https://concatenative.org/wiki/view/Factor/Deployment">deploy stand-alone
applications</a> on
all platforms. Full source code for the Factor project is available
under a BSD license.</p>
<h3 id="new-libraries">New libraries:</h3>
<ul>
<li><a href="https://docs.factorcode.org/content/vocab-base92.html">base92</a>: adding support for Base92 encoding/decoding</li>
<li><a href="https://docs.factorcode.org/content/vocab-bitcask.html">bitcask</a>: implementing the <a href="https://re.factorcode.org/2025/06/bitcask.html">Bitcask key/value database</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-bluesky.html">bluesky</a>: adding support for the BlueSky protocol</li>
<li><a href="https://docs.factorcode.org/content/vocab-calendar.holidays.world.html">calendar.holidays.world</a>: adding some new holidays including <a href="https://re.factorcode.org/2025/07/world-emoji-day.html">World Emoji Day</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-classes.enumeration.html">classes.enumeration</a>: adding <em>enumeration classes</em> and new <code>ENUMERATION:</code> syntax word</li>
<li><a href="https://docs.factorcode.org/content/vocab-colors.oklab.html">colors.oklab</a>: adding support for <a href="https://en.wikipedia.org/wiki/Oklab_color_space">OKLAB color space</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-colors.oklch.html">colors.oklch</a>: adding support for <a href="https://en.wikipedia.org/wiki/Oklab_color_space">OKLCH color space</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-colors.wavelength.html">colors.wavelength</a>: adding <code>wavelength>rgba</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-combinators.syntax.html">combinators.syntax</a>: adding experimental <em>combinator syntax</em> words <code>@[</code>, <code>*[</code>, and <code>&[</code>, and short-circuiting <code>n&&[</code>, <code>n||[</code>, <code>&&[</code> and <code>||[</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-continuations.extras.html">continuations.extras</a>: adding <code>with-datastacks</code> and <code>datastack-states</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-dotenv.html">dotenv</a>: implementing support for <a href="https://re.factorcode.org/2025/06/dotenv.html">Dotenv</a> files</li>
<li><a href="https://docs.factorcode.org/content/vocab-edn.html">edn</a>: implementing support for <a href="https://re.factorcode.org/2025/10/extensible-data-notation.html">Extensible Data Notation</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-editors.cursor.html">editors.cursor</a>: adding support for the <a href="https://www.cursor.com">Cursor</a> editor</li>
<li><a href="https://docs.factorcode.org/content/vocab-editors.rider.html">editors.rider</a>: adding support for the <a href="https://www.jetbrains.com/rider/">JetBrains Rider</a> editor</li>
<li><a href="https://docs.factorcode.org/content/vocab-gitignore.html">gitignore</a>: parser for <code>.gitignore</code> files</li>
<li><a href="https://docs.factorcode.org/content/vocab-http.json.html">http.json</a>: promoted <code>json.http</code> and added some useful words</li>
<li><a href="https://docs.factorcode.org/content/vocab-io.streams.farkup.html">io.streams.farkup</a>: a <a href="https://concatenative.org/wiki/view/Farkup">Farkup</a> formatted stream protocol</li>
<li><a href="https://docs.factorcode.org/content/vocab-io.streams.markdown.html">io.streams.markdowns</a>: a <a href="https://en.wikipedia.org/wiki/Markdown">Markdown</a> formatted stream protocol</li>
<li><a href="https://docs.factorcode.org/content/vocab-locals.lazy.html">locals.lazy</a>: prototype of <a href="https://re.factorcode.org/2024/10/emit.html">emit syntax</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-monadics.html">monadics</a>: alternative vocabulary for using Haskell-style monads, applicatives, and functors</li>
<li><a href="https://docs.factorcode.org/content/vocab-multibase.html">multibase</a>: implementation of <a href="https://github.com/multiformats/multibase">Multibase</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-pickle.html">pickle</a>: support for the <a href="https://re.factorcode.org/2025/08/pickle.html">Pickle</a> serialization format</li>
<li><a href="https://docs.factorcode.org/content/vocab-persistent.hashtables.identity.html">persistent.hashtables.identity</a>: support an <a href="https://docs.factorcode.org/content/word-identity-hashcode,kernel.html">identity-hashcode</a> version of persisent hashtables</li>
<li><a href="https://docs.factorcode.org/content/vocab-raylib.live-coding.html">raylib.live-coding</a>: demo of a vocabulary to do “live coding” of Raylib programs</li>
<li><a href="https://docs.factorcode.org/content/vocab-rdap.html">rdap</a>: support for the <a href="https://re.factorcode.org/2025/03/rdap.html">Registration Data Access Protocol</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-reverse.html">reverse</a>: implementation of the <a href="https://re.factorcode.org/2025/09/std-flip.html">std::flip</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-slides.cli.html">slides.cli</a>: simple text-based command-line interface for slides</li>
<li><a href="https://docs.factorcode.org/content/vocab-tools.highlight.html">tools.highlight</a>: command-line syntax-highlighting tool</li>
<li><a href="https://docs.factorcode.org/content/vocab-tools.random.html">tools.random</a>: command-line random generator tool</li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.pens.rounded.html">ui.pens.rounded</a>: adding rounded corner <a href="https://docs.factorcode.org/content/vocab-ui.pens.html">pen</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.pens.theme.html">ui.pens.theme</a>: experimental themed <a href="https://docs.factorcode.org/content/vocab-ui.pens.html">pen</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.tools.theme.html">ui.tools.theme</a>: some words for updating <a href="https://docs.factorcode.org/content/article-ui-tools.html">UI developer tools</a> themes</li>
</ul>
<h3 id="improved-libraries">Improved libraries:</h3>
<ul>
<li><a href="https://docs.factorcode.org/content/vocab-alien.syntax.html">alien.syntax</a>: added <code>C-LIBRARY:</code> syntax word</li>
<li><a href="https://docs.factorcode.org/content/vocab-assocs.extras.html">assocs.extras</a>: added <code>nzip</code> and <code>nunzip</code>, <code>map-zip</code> and <code>map-unzip</code> macros</li>
<li><a href="https://docs.factorcode.org/content/vocab-base32.html">base32</a>: adding the <a href="http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt">human-oriented Base32</a> encoding via <code>zbase32></code> and <code>>zbase32</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-base64.html">base64</a>: minor performance improvement</li>
<li><a href="https://docs.factorcode.org/content/vocab-benchmark.html">benchmark</a>: adding more benchmarks</li>
<li><a href="https://docs.factorcode.org/content/vocab-bootstrap.assembler.html">bootstrap.assembler</a>: fixes for ARM-64</li>
<li><a href="https://docs.factorcode.org/content/vocab-brainfuck.html">brainfuck</a>: added <code>BRAINFUCK:</code> syntax word and <code>interpret-brainfuck</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-bson.html">bson</a>: use <a href="https://docs.factorcode.org/content/article-linked-assocs.html">linked-assocs</a> to preserve order</li>
<li><a href="https://docs.factorcode.org/content/vocab-cache.html">cache</a>: implement <code>M\ cache-assoc delete-at</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-calendar.html">calendar</a>: adding <code>year<</code>, <code>year<=</code>, <code>year></code>, <code>year>=</code> words</li>
<li><a href="https://docs.factorcode.org/content/vocab-calendar.format.html">calendar.format</a>: parse human-readable and elapsed-time output back into duration objects</li>
<li><a href="https://docs.factorcode.org/content/vocab-cbor.html">cbor</a>: use <a href="https://docs.factorcode.org/content/article-linked-assocs.html">linked-assocs</a> to preserve order</li>
<li><a href="https://docs.factorcode.org/content/vocab-classes.mixin.html">classes.mixin</a>: added <code>definer</code> implementation</li>
<li><a href="https://docs.factorcode.org/content/vocab-classes.singleton.html">classes.singleton</a>: added <code>definer</code> implementation</li>
<li><a href="https://docs.factorcode.org/content/vocab-classes.tuple.html">classes.tuple</a>: added <code>tuple>slots</code>, rename <code>tuple>array</code> to <code>pack-tuple</code> and <code>>tuple</code> to <code>unpack-tuple</code>.</li>
<li><a href="https://docs.factorcode.org/content/vocab-classes.union.html">classes.union</a>: added <code>definer</code> implementation</li>
<li><a href="https://docs.factorcode.org/content/vocab-checksums.sha.html">checksums.sha</a>: some 20-40% performance improvements</li>
<li><a href="https://docs.factorcode.org/content/vocab-command-line.html">command-line</a>: allow passing script name of <code>-</code> to use stdin</li>
<li><a href="https://docs.factorcode.org/content/vocab-command-line.parser.html">command-line.parser</a>: support for <a href="https://re.factorcode.org/2025/07/argument-parser-commands.html">Argument Parser Commands</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-command-line.startup.html">command-line.startup</a>: document <code>-q</code> quiet mode flag</li>
<li><a href="https://docs.factorcode.org/content/vocab-concurrency.combinators.html">concurrency.combinators</a>: faster <code>parallel-map</code> and <code>parallel-assoc-map</code> using a <a href="https://docs.factorcode.org/content/article-concurrency.count-downs.html">count-down latch</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-concurrency.promises.html">concurrency.promises</a>: 5-7% performance improvement</li>
<li><a href="https://docs.factorcode.org/content/vocab-continuations.html">continuations</a>: improve docs and fix stack effect for <code>ifcc</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-countries.html">countries</a>: adding <code>CQ</code> country code for <a href="https://en.wikipedia.org/wiki/Sark">Sark</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-cpu.architecture.html">cpu.architecture</a>: fix <code>*-branch</code> stack effects</li>
<li><a href="https://docs.factorcode.org/content/vocab-cpu.arm.html">cpu.arm</a>: fixes for ARM-64</li>
<li><a href="https://docs.factorcode.org/content/vocab-crontab.html">crontab</a>: added <code>parse-crontab</code> which ignores blank lines and comments</li>
<li><a href="https://docs.factorcode.org/content/vocab-db.html">db</a>: making <code>query-each</code> row-polymorphic</li>
<li><a href="https://docs.factorcode.org/content/vocab-delegate.protocols.html">delegate.protocols</a>: adding <code>keys</code> and <code>values</code> to <code>assoc-protocol</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-discord.html">discord</a>: better support for network disconnects, added a configurable retry interval</li>
<li><a href="https://docs.factorcode.org/content/vocab-discord.chatgpt-bot.html">discord.chatgpt-bot</a>: some fixes for <a href="https://lmstudio.ai/">LM Studio</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-editors.html">editors</a>: make the <em>editor restart</em> nicer looking</li>
<li><a href="https://docs.factorcode.org/content/vocab-editors.focus.html">editors.focus</a>: support <em>open-file-to-line-number</em> on newer releases, support Linux and Window</li>
<li><a href="https://docs.factorcode.org/content/vocab-editors.zed.html">editors.zed</a>: support use of <a href="https://zed.dev/">Zed</a> on Linux</li>
<li><a href="https://docs.factorcode.org/content/vocab-endian.html">endian</a>: faster endian conversions of c-ptr-like objects</li>
<li><a href="https://docs.factorcode.org/content/vocab-environment.html">environment</a>: adding <code>os-env?</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-eval.html">eval</a>: move datastack and error messages to stderr</li>
<li><a href="https://docs.factorcode.org/content/vocab-fonts.html">fonts</a>: make <code><font></code> take a name, easier defaults</li>
<li><a href="https://docs.factorcode.org/content/vocab-furnace.asides.html">furnace.asides</a>: rename <code>post-data</code> slot on <code>aside</code> tuples to <code>data</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-generalizations.html">generalizations</a>: moved some <em>dip</em> words to <a href="https://docs.factorcode.org/content/vocab-shuffle.html">shuffle</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-help.tour.html">help.tour</a>: fix some typos/grammar</li>
<li><a href="https://docs.factorcode.org/content/vocab-html.template.chloe.html">html.templates.chloe</a>: improve use of <code>CDATA</code> tags for unescaping output</li>
<li><a href="https://docs.factorcode.org/content/vocab-http.html">http</a>: rename <code>post-data</code> slot on <code>request</code> tuples to <code>data</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-http.json.html">http.json</a>: adding <code>http-json</code> that doesn’t return the response object</li>
<li><a href="https://docs.factorcode.org/content/vocab-http.websockets.html">http.websockets</a>: making <code>read-websocket-loop</code> row-polymorphic</li>
<li><a href="https://docs.factorcode.org/content/vocab-ini-file.html">ini-file</a>: adding <code>ini>file</code>, <code>file>ini</code>, and use <code>LH{ }</code> to preserve configuration order</li>
<li><a href="https://docs.factorcode.org/content/vocab-io.encodings.detect.html">io.encodings.detect</a>: adding <code>utf7</code> detection</li>
<li><a href="https://docs.factorcode.org/content/vocab-io.encodings.utf8.html">io.encodings.utf8</a>: adding <code>utf8-bom</code> to handle optional BOM</li>
<li><a href="https://docs.factorcode.org/content/vocab-io.random.html">io.random</a>: speed up <code>random-line</code> and <code>random-lines</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-io.streams.ansi.html">io.streams.ansi</a>: adding documentation and tests, support dim foreground on terminals that support it</li>
<li><a href="https://docs.factorcode.org/content/vocab-io.streams.escape-codes.html">io.streams.escape-codes</a>: adding documentation and tests</li>
<li><a href="https://docs.factorcode.org/content/vocab-ip-parser.html">ip-parser</a>: adding IPV4 and IPV6 network words</li>
<li><a href="https://docs.factorcode.org/content/vocab-kernel.html">kernel</a>: adding <code>until*</code>, fix docs for <code>and*</code> and <code>or*</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-linked-sets.html">linked-sets</a>: adding <code>LS{</code> syntax word</li>
<li><a href="https://docs.factorcode.org/content/vocab-lists.lazy.html">lists.lazy</a>: changed the argument order in <code>ltake</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-macho.html">macho</a>: support a few more link edit commands</li>
<li><a href="https://docs.factorcode.org/content/vocab-make.html">make</a>: adding <code>,%</code> for a <code>push-at</code> variant</li>
<li><a href="https://docs.factorcode.org/content/vocab-mason.release.tidy.html">mason.release.tidy</a>: cleanup a few more git artifacts</li>
<li><a href="https://docs.factorcode.org/content/vocab-math.combinatorics.html">math.combinatorics</a>: adding <em>counting</em> words</li>
<li><a href="https://docs.factorcode.org/content/vocab-math.distances.html">math.distances</a>: adding <code>jaro-distance</code> and <code>jaro-winkler-distance</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-math.extras.html">math.extras</a>: added <code>all-removals</code>, support <a href="https://re.factorcode.org/2025/05/recamans-sequence.html">Recamán’s sequence</a>, and <a href="https://re.factorcode.org/2025/07/tribonacci-numbers.html">Tribonacci Numbers</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-math.factorials.html">math.factorials</a>: added <code>subfactorial</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-math.functions.html">math.functions</a>: added “closest to zero” modulus</li>
<li><a href="https://docs.factorcode.org/content/vocab-math.parser.html">math.parser</a>: improve ratio parsing for consistency</li>
<li><a href="https://docs.factorcode.org/content/vocab-math.primes.html">math.primes</a>: make <code>prime?</code> safe from non-integer inputs</li>
<li><a href="https://docs.factorcode.org/content/vocab-math.runge-kutta.html">math.runge-kutta</a>: make generalized improvements to the <a href="https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods">Runge-Kutta</a> solver</li>
<li><a href="https://docs.factorcode.org/content/vocab-math.similarity.html">math.similarity</a>: adding <code>jaro-similarity</code>, <code>jaro-winkler-similarity</code>, and <code>trigram-similarity</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-math.text.english.html">math.text.english</a>: fix issue with very large and very small floats</li>
<li><a href="https://docs.factorcode.org/content/vocab-metar.html">metar</a>: updated the abbreviations glossary</li>
<li><a href="https://docs.factorcode.org/content/vocab-mime.types.html">mime.types</a>: updating <code>mime.types</code> file</li>
<li><a href="https://docs.factorcode.org/content/vocab-msgpack.html">msgpack</a>: use <a href="https://docs.factorcode.org/content/article-linked-assocs.html">linked-assocs</a> to preserve order</li>
<li><a href="https://docs.factorcode.org/content/vocab-qw.html">qw</a>: adding <code>qw:</code> syntax</li>
<li><a href="https://docs.factorcode.org/content/vocab-path-finding.html">path-finding</a>: added <code>find-path*</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-peg.parsers.html">peg.parsers</a>: faster <code>list-of</code> and <code>list-of-many</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-progress-bars.models.html">progress-bars.models</a>: added <code>with-progress-display</code>, <code>map-with-progress-bar</code>, <code>each-with-progress-bar</code>, and <code>reduce-with-progress-bar</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-raylib.html">raylib</a>: adding <code>trace-log</code> and <code>set-trace-log-level</code>, updated to Raylib 5.5</li>
<li><a href="https://docs.factorcode.org/content/vocab-readline-listener.html">readline-listener</a>: store history across sessions, support color on terminals that support it</li>
<li><a href="https://docs.factorcode.org/content/vocab-robohash.html">robohash</a>: support for <code>"set4"</code>, <code>"set5"</code>, and <code>"set6"</code> types</li>
<li><a href="https://docs.factorcode.org/content/vocab-sequences.html">sequences</a>: rename <code>midpoint@</code> to <code>midpoint</code>, faster <code>each-from</code> and <code>map-reduce</code> on slices</li>
<li><a href="https://docs.factorcode.org/content/vocab-sequences.extras.html">sequences.extras</a>: adding <code>find-nth</code>, <code>find-nth-last</code>, <code>subseq-indices</code>, <code>deep-nth</code>, <code>deep-nth-of</code>, <code>2none?</code>, <code>filter-errors</code>, <code>reject-errors</code>, <code>all-same?</code>, <code>adjacent-differences</code>, and <code>partial-sum</code>.</li>
<li><a href="https://docs.factorcode.org/content/vocab-sequences.generalizations.html">sequences.generalizations</a>: fix <code>?firstn</code> and <code>?lastn</code> for string inputs, removed <code>(nsequence)</code> which duplicates <code>set-firstn-unsafe</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-sequences.prefixed.html">sequences.prefixed</a>: swap order of <code><prefixed></code> arguments to match <code>prefix</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-sequences.repeating.html">sequences.repeating</a>: adding <code><cycles-from></code> and <code>cycle-from</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-sequences.snipped.html">sequences.snipped</a>: fixed out-of-bounds issues</li>
<li><a href="https://docs.factorcode.org/content/vocab-scryfall.html">scryfall</a>: update for duskmourn</li>
<li><a href="https://docs.factorcode.org/content/vocab-shuffle.html">shuffle</a>: improve stack-checking of <code>shuffle(</code> syntax, added <code>SHUFFLE:</code> syntax, <code>nreverse</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-sorting.html">sorting</a>: fix <code>sort-with</code> to apply the quot with access to the stack below</li>
<li><a href="https://docs.factorcode.org/content/vocab-sorting.human.html">sorting.human</a>: implement <a href="https://re.factorcode.org/2025/03/human-sorting-improved.html">human sorting improved</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-system-info.macos.html">system-info.macos</a>: adding “Tahoe” code-name for <a href="https://www.apple.com/newsroom/2025/06/macos-tahoe-26-makes-the-mac-more-capable-productive-and-intelligent-than-ever/">macOS 26</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-terminfo.html">terminfo</a>: add words for querying specific output capabilities</li>
<li><a href="https://docs.factorcode.org/content/vocab-threads.html">threads</a>: define a generalized <code>linked-thread</code> which used to be for <code>concurrency.mailboxes</code> only</li>
<li><a href="https://docs.factorcode.org/content/vocab-toml.html">toml</a>: use <a href="https://docs.factorcode.org/content/article-linked-assocs.html">linked-assocs</a> to preserve order, adding <code>>toml</code> and <code>write-toml</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-tools.annotations.html">tools.annotations</a>: adding <code><WATCH ... WATCH></code> syntax</li>
<li><a href="https://docs.factorcode.org/content/vocab-tools.deploy.html">tools.deploy</a>: adding a command-line interface for deploy options</li>
<li><a href="https://docs.factorcode.org/content/vocab-tools.deploy.backend.html">tools.deploy.backend</a>: fix boot image location in system-wide installations</li>
<li><a href="https://docs.factorcode.org/content/vocab-tools.deploy.unix.html">tools.deploy.unix</a>: change binary name to append <code>.out</code> to fix conflict with vocab resources</li>
<li><a href="https://docs.factorcode.org/content/vocab-tools.directory-to-file.html">tools.directory-to-file</a>: better test file metrics, print filename for editing</li>
<li><a href="https://docs.factorcode.org/content/vocab-tools.memory.html">tools.memory</a>: adding <code>heap-stats-of</code> arbitrary sequence of instances, and <code>total-size</code> size of everything pointed to by an object</li>
<li><a href="https://docs.factorcode.org/content/vocab-txon.html">txon</a>: use <a href="https://docs.factorcode.org/content/article-linked-assocs.html">linked-assocs</a> to preserve order</li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.html">ui</a>: adding <code>adjust-font-size</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.gadgets.buttons.html">ui.gadgets.buttons</a>: stop using images and respect theme colors</li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.gadgets.sliders.html">ui.gadgets.sliders</a>: stop using images and respect theme colors</li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.theme.base16.html">ui.theme.base16</a>: adding a lot more (270!) <a href="https://re.factorcode.org/2024/10/base16-themes.html">Base16 Themes</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.tools.html">ui.tools</a>: adding font-sizing keyboard shortcuts</li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.tools.browser.html">ui.tools.browser</a>: more responsive font sizing</li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.tools.listener.html">ui.tools.listener</a>: more responsive font sizing, adding some <a href="https://docs.factorcode.org/content/article-ui-listener-style.html">UI listener styling</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-ui.tools.listener.completion.html">ui.tools.listener.completion</a>: allow spaces in history search popup</li>
<li><a href="https://docs.factorcode.org/content/vocab-unicode.html">unicode</a>: update to <a href="https://www.unicode.org/versions/Unicode17.0.0/">Unicode 17.0.0</a></li>
<li><a href="https://docs.factorcode.org/content/vocab-webapps.planet.html">webapps.planet</a>: improve CSS for <code>video</code> tags</li>
<li><a href="https://docs.factorcode.org/content/vocab-words.html">words</a>: adding <code>define-temp-syntax</code></li>
<li><a href="https://docs.factorcode.org/content/vocab-zoneinfo.html">zoneinfo</a>: update to version 2025b</li>
</ul>
<h3 id="removed-libraries">Removed libraries</h3>
<ul>
<li><code>ui.theme.images</code></li>
</ul>
<h3 id="vm-improvements">VM Improvements:</h3>
<ul>
<li>More work on ARM64 backend (fix set-callstack, fix generic dispatch)</li>
</ul>
John Benediktsson: zxcvbn
2025-12-05T15:00:00.000000Z
<p>Years ago, <a href="https://dropbox.com">Dropbox</a> wrote about <a href="https://dropbox.tech/security/zxcvbn-realistic-password-strength-estimation">zxcvbn: realistic password strength
estimation</a>:</p>
<blockquote>
<p><code>zxcvbn</code> is a password strength estimator inspired by password crackers.
Through pattern matching and conservative estimation, it recognizes and
weighs 30k common passwords, common names and surnames according to US census
data, popular English words from Wikipedia and US television and movies, and
other common patterns like dates, repeats (<code>aaa</code>), sequences (<code>abcd</code>),
keyboard patterns (<code>qwertyuiop</code>), and l33t speak.</p>
</blockquote>
<p>And it appears to have been successful – the <a href="https://github.com/dropbox/zxcvbn">original
implementation</a> is in JavaScript, but there
have been clones of the algorithm generated in many different languages:</p>
<blockquote>
<p>At Dropbox we use zxcvbn (<a href="https://github.com/dropbox/zxcvbn/releases">Release notes</a>) on our web, desktop, iOS and Android clients. If JavaScript doesn’t work for you, others have graciously ported the library to these languages:</p>
<ul>
<li><a href="https://github.com/dwolfhub/zxcvbn-python"><code>zxcvbn-python</code></a> (Python)</li>
<li><a href="https://github.com/rianhunter/zxcvbn-cpp"><code>zxcvbn-cpp</code></a> (C/C++/Python/JS)</li>
<li><a href="https://github.com/tsyrogit/zxcvbn-c"><code>zxcvbn-c</code></a> (C/C++)</li>
<li><a href="https://github.com/shssoichiro/zxcvbn-rs"><code>zxcvbn-rs</code></a> (Rust)</li>
<li><a href="https://github.com/nbutton23/zxcvbn-go"><code>zxcvbn-go</code></a> (Go)</li>
<li><a href="https://github.com/nulab/zxcvbn4j"><code>zxcvbn4j</code></a> (Java)</li>
<li><a href="https://github.com/GoSimpleLLC/nbvcxz"><code>nbvcxz</code></a> (Java)</li>
<li><a href="https://github.com/envato/zxcvbn-ruby"><code>zxcvbn-ruby</code></a> (Ruby)</li>
<li><a href="https://github.com/bitzesty/zxcvbn-js"><code>zxcvbn-js</code></a> (Ruby [via ExecJS])</li>
<li><a href="https://github.com/dropbox/zxcvbn-ios"><code>zxcvbn-ios</code></a> (Objective-C)</li>
<li><a href="https://github.com/mickford/zxcvbn-cs"><code>zxcvbn-cs</code></a> (C#/.NET)</li>
<li><a href="https://github.com/tekul/szxcvbn"><code>szxcvbn</code></a> (Scala)</li>
<li><a href="https://github.com/bjeavons/zxcvbn-php"><code>zxcvbn-php</code></a> (PHP)</li>
<li><a href="https://github.com/wcjr/zxcvbn-api"><code>zxcvbn-api</code></a> (REST)</li>
<li><a href="https://github.com/cryptosense/ocaml-zxcvbn"><code>ocaml-zxcvbn</code></a> (OCaml bindings for <code>zxcvbn-c</code>)</li>
</ul>
</blockquote>
<p>In today’s era of <a href="https://www.wired.com/story/best-password-managers/">password
managers</a>,
<a href="https://en.wikipedia.org/wiki/WebAuthn">WebAuthn</a> also known as <em>passkeys</em>,
and <a href="https://haveibeenpwned.com/PwnedWebsites">many pwned accounts</a>,
passwords may seem like a funny sort of outdated concept. They have
definitely provided good entertainment over the years from <a href="https://xkcd.com/936/">XKCD: Password
Strength</a> comics to the 20-year old <a href="https://knowyourmeme.com/memes/hunter2">hunter2
meme</a>:</p>
<p>
<img src="https://re.factorcode.org/images/2025-12-05-hunter2.jpg" alt="" width="736" height="261" />
</p>
<p>I have wanted a <a href="https://factorcode.org">Factor</a> implementation of this for
a long time – and finally <a href="https://github.com/mrjbq7/re-factor/commit/fa677e6663413c57dc4203b6ac2d961efa9c8f78">built zxcvbn in
Factor</a>!</p>
<p>We can use it to check out some potential passwords:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="kn">USE:</span> <span class="nn">zxcvbn</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"F@ct0r!"</span> zxcvbn.
</span></span><span class="line"><span class="cl">Score:
</span></span><span class="line"><span class="cl"> 1/4 (very guessable)
</span></span><span class="line"><span class="cl">Crack times:
</span></span><span class="line"><span class="cl"> Online (throttled): <span class="m">4 </span>months
</span></span><span class="line"><span class="cl"> Online (unthrottled): <span class="m">8 </span>hours
</span></span><span class="line"><span class="cl"> Offline (slow hash): <span class="m">30 </span>seconds
</span></span><span class="line"><span class="cl"> Offline (fast hash): less than a <span class="nb">second
</span></span></span><span class="line"><span class="cl">Suggestions:
</span></span><span class="line"><span class="cl"> Add another word <span class="nb">or </span>two. Uncommon words are better.
</span></span><span class="line"><span class="cl"> Capitalization doesn't help very much.
</span></span><span class="line"><span class="cl"> Predictable substitutions <span class="nb">like </span>'@' instead <span class="nb">of </span>'a' don't help very much.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"john2025"</span> zxcvbn.
</span></span><span class="line"><span class="cl">Score:
</span></span><span class="line"><span class="cl"> 1/4 (very guessable)
</span></span><span class="line"><span class="cl">Crack times:
</span></span><span class="line"><span class="cl"> Online (throttled): <span class="m">3 </span>months
</span></span><span class="line"><span class="cl"> Online (unthrottled): <span class="m">6 </span>hours
</span></span><span class="line"><span class="cl"> Offline (slow hash): <span class="m">23 </span>seconds
</span></span><span class="line"><span class="cl"> Offline (fast hash): less than a <span class="nb">second
</span></span></span><span class="line"><span class="cl">Warning:
</span></span><span class="line"><span class="cl"> Common names <span class="nb">and </span>surnames are easy to guess.
</span></span><span class="line"><span class="cl">Suggestions:
</span></span><span class="line"><span class="cl"> Add another word <span class="nb">or </span>two. Uncommon words are better.
</span></span></code></pre></div><p>That’s not so good, maybe we should use the <a href="https://docs.factorcode.org/content/article-random.passwords.html">random.passwords
vocabulary</a>
instead!</p>
<p>This is available on my
<a href="https://github.com/mrjbq7/re-factor/blob/master/zxcvbn/zxcvbn.factor">GitHub</a>.</p>
John Benediktsson: AsyncIO Performance
2025-12-01T15:00:00.000000Z
<p><a href="https://factorcode.org">Factor</a> has <a href="https://en.wikipedia.org/wiki/Green_thread">green
threads</a> and a long-standing
feature request to be able to utilize native threads more efficiently for
concurrent tasks. In the meantime, the cooperative threading model allows for
asynchronous tasks which is particularly useful when waiting for I/O such as
used by <a href="https://en.wikipedia.org/wiki/Network_socket">sockets over a computer
network</a>.</p>
<p>And while it might be true that <a href="https://kristoff.it/blog/asynchrony-is-not-concurrency/">asynchrony is not
concurrency</a>, there
are a lot of other things one could say about concurrency and multi-threaded or
multi-process performance. Today I want to discuss an article that <a href="https://github.com/willmcgugan">Will
McGugan</a> wrote about the <a href="https://textual.textualize.io/blog/2023/03/08/overhead-of-python-asyncio-tasks/">overhead of Python
asyncio
tasks</a>
and the good discussion that followed on <a href="https://news.ycombinator.com/item?id=35073136">Hacker
News</a>.</p>
<p>Let’s go over the benchmark in a few programming languages – including
<a href="https://factorcode.org">Factor</a>!</p>
<h2 id="python">Python</h2>
<p>The article presents this benchmark in <a href="https://python.org">Python</a> that does
no work but measures the relative overhead of the
<a href="https://docs.python.org/3/library/asyncio.html">asyncio</a> task infrastructure
when creating a large number of asynchronous tasks:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">asyncio</span> <span class="kn">import</span> <span class="n">create_task</span><span class="p">,</span> <span class="n">wait</span><span class="p">,</span> <span class="n">run</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">process_time</span> <span class="k">as</span> <span class="n">time</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">time_tasks</span><span class="p">(</span><span class="n">count</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Time creating and destroying tasks."""</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">nop_task</span><span class="p">()</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Do nothing task."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">tasks</span> <span class="o">=</span> <span class="p">[</span><span class="n">create_task</span><span class="p">(</span><span class="n">nop_task</span><span class="p">())</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">count</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">wait</span><span class="p">(</span><span class="n">tasks</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">elapsed</span> <span class="o">=</span> <span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">elapsed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">count</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100_000</span><span class="p">,</span> <span class="mi">1_000_000</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">100_000</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">create_time</span> <span class="o">=</span> <span class="n">run</span><span class="p">(</span><span class="n">time_tasks</span><span class="p">(</span><span class="n">count</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="n">create_per_second</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="p">(</span><span class="n">create_time</span> <span class="o">/</span> <span class="n">count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">count</span><span class="si">:</span><span class="s2">9,</span><span class="si">}</span><span class="s2"> tasks </span><span class="se">\t</span><span class="s2"> </span><span class="si">{</span><span class="n">create_per_second</span><span class="si">:</span><span class="s2">0,.0f</span><span class="si">}</span><span class="s2"> tasks per/s"</span><span class="p">)</span>
</span></span></code></pre></div><p>Using the latest <a href="https://www.python.org/downloads/release/python-3140/">Python
3.14</a>, this is
reasonably fast on my laptop taking about 13 seconds:</p>
<pre tabindex="0"><code>$ time python3.14 foo.py
100,000 tasks 577,247 tasks per/s
200,000 tasks 533,911 tasks per/s
300,000 tasks 546,127 tasks per/s
400,000 tasks 488,219 tasks per/s
500,000 tasks 466,636 tasks per/s
600,000 tasks 469,972 tasks per/s
700,000 tasks 434,126 tasks per/s
800,000 tasks 428,456 tasks per/s
900,000 tasks 404,905 tasks per/s
1,000,000 tasks 376,167 tasks per/s
python3.14 foo.py 12.69s user 0.27s system 99% cpu 12.971 total
</code></pre><h2 id="factor">Factor</h2>
<p>We could translate this directly to <a href="https://factorcode.org">Factor</a> using the
<a href="https://docs.factorcode.org/content/article-concurrency.combinators.html">concurrency.combinators
vocabulary</a>.</p>
<p>In particular, the
<a href="https://docs.factorcode.org/content/word-parallel-map,concurrency.combinators.html">parallel-map</a>
word starts a new thread applying a
<a href="https://docs.factorcode.org/content/article-quotations.html">quotation</a> to
each element in the
<a href="https://docs.factorcode.org/content/article-sequences.html">sequence</a> and then
waits for all the
<a href="https://docs.factorcode.org/content/article-threads.html">threads</a> to finish:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">USING:</span> <span class="nn">concurrency.combinators</span> <span class="nn">formatting</span> <span class="nn">io</span> <span class="nn">kernel</span> <span class="nn">math</span> <span class="nn">ranges</span> <span class="nn">sequences</span>
</span></span><span class="line"><span class="cl"><span class="nn">tools.time</span> <span class="k">;
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">time-tasks</span> <span class="nf">( </span><span class="nv">n</span> <span class="nf">-- )
</span></span></span><span class="line"><span class="cl"> <iota> [ ] parallel-map <span class="nb">drop </span><span class="k">;
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">run-tasks</span> <span class="nf">( -- )
</span></span></span><span class="line"><span class="cl"> <span class="m">100,000 1,000,000 100,000 </span><range> [
</span></span><span class="line"><span class="cl"> <span class="nb">dup </span>[ time-tasks ] benchmark <span class="m">1e9 </span><span class="nb">/ dupd /
</span></span></span><span class="line"><span class="cl"> <span class="s">"%7d tasks \t %7d tasks per/s\n"</span> printf <span class="nb">flush
</span></span></span><span class="line"><span class="cl"> ] <span class="nb">each </span><span class="k">;
</span></span></span></code></pre></div><p>After making <a href="https://github.com/factor/factor/commit/07d901db390655f8dcb56ee12b103b3572660031">an improvement to our parallel-map
implementation</a>
that uses a <a href="https://docs.factorcode.org/content/article-concurrency.count-downs.html">count-down
latch</a>
for more efficient waiting on a group of tasks, this runs <strong>2.5x</strong> as fast as
Python:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> gc [ run-tasks ] time
</span></span><span class="line"><span class="cl"> <span class="m">100000 </span>tasks <span class="m">1246872 </span>tasks per/s
</span></span><span class="line"><span class="cl"> <span class="m">200000 </span>tasks <span class="m">1209500 </span>tasks per/s
</span></span><span class="line"><span class="cl"> <span class="m">300000 </span>tasks <span class="m">1141121 </span>tasks per/s
</span></span><span class="line"><span class="cl"> <span class="m">400000 </span>tasks <span class="m">1121304 </span>tasks per/s
</span></span><span class="line"><span class="cl"> <span class="m">500000 </span>tasks <span class="m">1119707 </span>tasks per/s
</span></span><span class="line"><span class="cl"> <span class="m">600000 </span>tasks <span class="m">1135459 </span>tasks per/s
</span></span><span class="line"><span class="cl"> <span class="m">700000 </span>tasks <span class="m">956541 </span>tasks per/s
</span></span><span class="line"><span class="cl"> <span class="m">800000 </span>tasks <span class="m">1091807 </span>tasks per/s
</span></span><span class="line"><span class="cl"> <span class="m">900000 </span>tasks <span class="m">944753 </span>tasks per/s
</span></span><span class="line"><span class="cl"><span class="m">1000000 </span>tasks <span class="m">1137681 </span>tasks per/s
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Running time: <span class="m">5.142044833 </span>seconds
</span></span></code></pre></div><p>That’s pretty good for a comparable dynamic language, and especially since we
are still running in <a href="https://support.apple.com/en-us/102527">Rosetta 2</a> on
<a href="https://www.apple.com/os/macos/">Apple macOS</a> translating Intel x86-64 to
Apple Silicon aarch64 on the fly!</p>
<p>It also turns out that 75% of the benchmark time is spent in the garbage
collector, so probably there are some big wins we can get if we look more
closely into that.</p>
<h2 id="go">Go</h2>
<p>We could translate that benchmark into <a href="https://go.dev/doc/go1.25">Go 1.25</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"fmt"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"sync"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"time"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">timeTasks</span><span class="p">(</span><span class="nx">count</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">nopTask</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">done</span><span class="w"> </span><span class="kd">func</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nf">done</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">start</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">wg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o">&</span><span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">count</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nx">count</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="nf">nopTask</span><span class="p">(</span><span class="nx">wg</span><span class="p">.</span><span class="nx">Done</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">Sub</span><span class="p">(</span><span class="nx">start</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">100_000</span><span class="p">;</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o"><=</span><span class="w"> </span><span class="mi">1_000_000</span><span class="p">;</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">100_000</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">createTime</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nf">timeTasks</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">createPerSecond</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="p">(</span><span class="mf">1.0</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="p">(</span><span class="nb">float64</span><span class="p">(</span><span class="nx">createTime</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nx">n</span><span class="p">)))</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%7d tasks \t %7d tasks per/s\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">n</span><span class="p">,</span><span class="w"> </span><span class="nx">createPerSecond</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>And show that it is about <strong>11x</strong> times faster than Python using multiple CPUs.</p>
<pre tabindex="0"><code>$ time go run foo.go
100000 tasks 3889083 tasks per/s
200000 tasks 5748283 tasks per/s
300000 tasks 6324955 tasks per/s
400000 tasks 6265341 tasks per/s
500000 tasks 6301852 tasks per/s
600000 tasks 5572898 tasks per/s
700000 tasks 6239860 tasks per/s
800000 tasks 6276241 tasks per/s
900000 tasks 6226128 tasks per/s
1000000 tasks 6243859 tasks per/s
go run foo.go 2.44s user 0.71s system 270% cpu 1.165 total
</code></pre><p>If we limit <code>GOMAXPROCS</code> to one CPU, it runs only <strong>7.5x</strong> times faster than Python:</p>
<pre tabindex="0"><code>$ time GOMAXPROCS=1 go run foo.go
100000 tasks 2240106 tasks per/s
200000 tasks 2869379 tasks per/s
300000 tasks 2745897 tasks per/s
400000 tasks 3759142 tasks per/s
500000 tasks 3090267 tasks per/s
600000 tasks 3489138 tasks per/s
700000 tasks 3608874 tasks per/s
800000 tasks 3200636 tasks per/s
900000 tasks 3682102 tasks per/s
1000000 tasks 3259778 tasks per/s
GOMAXPROCS=1 go run foo.go 1.65s user 0.08s system 99% cpu 1.735 total
</code></pre><h2 id="javascript">JavaScript</h2>
<p>We could build the same benchmark in <a href="https://en.wikipedia.org/wiki/JavaScript">JavaScript</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">time_tasks</span><span class="p">(</span><span class="nx">count</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">nop_task</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">performance</span><span class="p">.</span><span class="nx">now</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">start</span> <span class="o">=</span> <span class="nx">performance</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="kd">let</span> <span class="nx">tasks</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">count</span><span class="p">).</span><span class="nx">map</span><span class="p">(</span><span class="nx">nop_task</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="kr">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">(</span><span class="nx">tasks</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">elapsed</span> <span class="o">=</span> <span class="nx">performance</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span> <span class="o">-</span> <span class="nx">start</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">elapsed</span> <span class="o">/</span> <span class="mf">1e3</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">run_tasks</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">count</span> <span class="o">=</span> <span class="mi">100000</span><span class="p">;</span> <span class="nx">count</span> <span class="o"><</span> <span class="mi">1000000</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">count</span> <span class="o">+=</span> <span class="mi">100000</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">ct</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">time_tasks</span><span class="p">(</span><span class="nx">count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`</span><span class="si">${</span><span class="nx">count</span><span class="si">}</span><span class="sb">: </span><span class="si">${</span><span class="nb">Math</span><span class="p">.</span><span class="nx">round</span><span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="p">(</span><span class="nx">ct</span> <span class="o">/</span> <span class="nx">count</span><span class="p">))</span><span class="si">}</span><span class="sb"> tasks/sec`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">run_tasks</span><span class="p">()</span>
</span></span></code></pre></div><p>And it runs pretty fast on <a href="https://nodejs.org/en/blog/release/v25.2.1">Node
25.2.1</a> – about <strong>26x</strong> times faster
than Python!</p>
<pre tabindex="0"><code>$ time node foo.js
100000: 9448038 tasks/sec
200000: 11555322 tasks/sec
300000: 18286318 tasks/sec
400000: 10017217 tasks/sec
500000: 12587060 tasks/sec
600000: 14198956 tasks/sec
700000: 13294620 tasks/sec
800000: 12045403 tasks/sec
900000: 11135513 tasks/sec
1000000: 13577663 tasks/sec
node foo.js 0.82s user 0.10s system 185% cpu 0.496 total
</code></pre><p>But it runs even faster on <a href="https://bun.com/blog/bun-v1.3.3">Bun 1.3.3</a> –
about <strong>36x</strong> times faster than Python!</p>
<pre tabindex="0"><code>$ time bun foo.js
100000: 9771222 tasks/sec
200000: 13388075 tasks/sec
300000: 13242548 tasks/sec
400000: 13130144 tasks/sec
500000: 16530496 tasks/sec
600000: 16979009 tasks/sec
700000: 16781272 tasks/sec
800000: 17098919 tasks/sec
900000: 17111784 tasks/sec
1000000: 18288515 tasks/sec
bun foo.js 0.37s user 0.02s system 111% cpu 0.353 total
</code></pre><p>I’m sure other languages perform both better and worse, but this gives us some
nice ideas of where we stand relative to some useful production programming
languages. There is clearly room to grow, some potential low-hanging fruit, and
known features such as supporting native threads that could be a big
improvement to the status quo!</p>
<p>PRs welcome!</p>
John Benediktsson: Cosine FizzBuzz
2025-11-22T15:00:00.000000Z
<p>After revisiting <a href="https://re.factorcode.org/2011/08/fizzbuzz.html">FizzBuzz</a> yesterday to discuss a
<a href="https://re.factorcode.org/2025/11/lazy-fizzbuzz.html">Lazy FizzBuzz</a> using infinite lazy lists, I
thought I would not return to the subject for awhile. Apparently, I was wrong!</p>
<p><a href="https://susam.net/about.html">Susam Pal</a> just wrote a really fun article about
<a href="https://susam.net/fizz-buzz-with-cosines.html">Solving Fizz Buzz with
Cosines</a>:</p>
<blockquote>
<p>We define a set of four functions { <code>s0</code>, <code>s1</code>, <code>s2</code>, <code>s3</code> } for
integers <code>n</code> by:</p>
<p><code>s0(n) = n</code></p>
<p><code>s1(n) = Fizz</code></p>
<p><code>s2(n) = Buzz</code></p>
<p><code>s3(n) = FizzBuzz</code></p>
</blockquote>
<p>And from that, they derive a formula which is essentially a finite <a href="https://en.wikipedia.org/wiki/Fourier_series">Fourier
series</a> for computing the <em>nth</em>
value in the <em>FizzBuzz</em> sequence, showing a nice fixed periodic cycling across
<code>n mod 15</code>, resolving at each value of <code>n</code> to either the integers <code>0, 1, 2, 3</code>:</p>
<p>
<img src="https://re.factorcode.org/images/2025-11-22-cosine-fizzbuzz.png" alt="" width="848" height="644" />
</p>
<p>I recommend reading the whole article, but I will jump to an implementation of
the formula in <a href="https://factorcode.org">Factor</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">::</span> <span class="nf">fizzbuzz</span> <span class="nf">( </span><span class="nv">n</span> <span class="nf">-- </span><span class="nv">val</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"> 11/15
</span></span><span class="line"><span class="cl"> 2/3 n <span class="nb">* </span>pi <span class="nb">* </span>cos 2/3 <span class="nb">* +
</span></span></span><span class="line"><span class="cl"> 2/5 n <span class="nb">* </span>pi <span class="nb">* </span>cos 4/5 <span class="nb">* +
</span></span></span><span class="line"><span class="cl"> 4/5 n <span class="nb">* </span>pi <span class="nb">* </span>cos <span class="nb">+ </span>round <span class="nb">>integer
</span></span></span><span class="line"><span class="cl"> { n <span class="s">"Fizz"</span> <span class="s">"Buzz"</span> <span class="s">"FizzBuzz"</span> } <span class="nb">nth </span><span class="k">;
</span></span></span></code></pre></div><p>And we can use that to compute the first few values in the sequence:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="m">1 </span>..= <span class="m">100 </span>[ fizzbuzz <span class="m">. </span>] <span class="nb">each
</span></span></span><span class="line"><span class="cl"><span class="m">1
</span></span></span><span class="line"><span class="cl"><span class="m">2
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="m">4
</span></span></span><span class="line"><span class="cl"><span class="s">"Buzz"</span>
</span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="m">7
</span></span></span><span class="line"><span class="cl"><span class="m">8
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="s">"Buzz"</span>
</span></span><span class="line"><span class="cl"><span class="m">11
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="m">13
</span></span></span><span class="line"><span class="cl"><span class="m">14
</span></span></span><span class="line"><span class="cl"><span class="s">"FizzBuzz"</span>
</span></span><span class="line"><span class="cl"><span class="m">16
</span></span></span><span class="line"><span class="cl"><span class="m">17
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="m">19
</span></span></span><span class="line"><span class="cl"><span class="s">"Buzz"</span>
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></div><p>Or, even some arbitrary values in the sequence:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="m">67 </span>fizzbuzz <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m">67
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="m">9,999,999 </span>fizzbuzz <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="m">10,000,000 </span>fizzbuzz <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="s">"Buzz"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="m">1,234,567,890 </span>fizzbuzz <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="s">"FizzBuzz"</span>
</span></span></code></pre></div><p>Thats even more fun than using <a href="https://docs.factorcode.org/content/article-lists.lazy.html">lazy
lists</a>!</p>
John Benediktsson: Lazy FizzBuzz
2025-11-21T15:00:00.000000Z
<p>I wrote about <a href="https://re.factorcode.org/2011/08/fizzbuzz.html">FizzBuzz</a> many years ago. It’s a
silly programming task often cited and even
<a href="https://rosettacode.org/wiki/FizzBuzz">included</a> on
<a href="https://rosettacode.org">RosettaCode</a>. The task is described as:</p>
<blockquote>
<p>Write a program that prints the integers from <code>1</code> to <code>100</code> (inclusive).</p>
<p>But:</p>
<ul>
<li>for multiples of three, print <code>"Fizz"</code> instead of the number;</li>
<li>for multiples of five, print <code>"Buzz"</code> instead of the number;</li>
<li>for multiples of both three and five, print <code>"FizzBuzz"</code> instead of the number.</li>
</ul>
</blockquote>
<p>This has been solved <a href="https://en.wikipedia.org/wiki/Ad_nauseam">ad nauseum</a>,
but a few days ago <a href="https://evanhahn.com/">Evan Hawn</a> wrote about solving <a href="https://evanhahn.com/fizz-buzz-without-conditionals-or-booleans/">Fizz
Buzz without conditionals or
booleans</a>
using <a href="https://python.org">Python</a> and the
<a href="https://docs.python.org/3/library/itertools.html#itertools.cycle">itertools.cycle</a>
function to create an infinitely iterable solution.</p>
<p>Let’s build this in <a href="https://factorcode.org">Factor</a>!</p>
<p>There are several ways to implement this, including
<a href="https://docs.factorcode.org/content/article-generators.html">generators</a>,
but we will be using the <a href="https://docs.factorcode.org/content/article-lists.lazy.html">lists.lazy
vocabulary</a> to
provide a <em>lazy</em> and <em>infinite</em> stream of values. In particular, by
combining a stream of integers with a cycle of <code>"Fizz"</code> and a cycle of
<code>"Buzz"</code>.</p>
<p>The <a href="https://docs.factorcode.org/content/article-lists.circular.html">lists.circular
vocabulary</a>
extends <a href="https://docs.factorcode.org/content/article-circular.html">circular
sequences</a> to
support the <a href="https://docs.factorcode.org/content/article-lists.html">lists
protocol</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="kn">USE:</span> <span class="nn">lists.circular</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> { <span class="m">1 2 3 </span>} <circular> <span class="m">10 </span>ltake list>array <span class="m">.
</span></span></span><span class="line"><span class="cl">{ <span class="m">1 2 3 1 2 3 1 2 3 1 </span>}
</span></span></code></pre></div><p>Using that, we can create an <em>infinite</em> FizzBuzz list:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">lfizzbuzz</span> <span class="nf">( -- </span><span class="nv">list</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"> <span class="m">1 </span>lfrom
</span></span><span class="line"><span class="cl"> { <span class="s">""</span> <span class="s">""</span> <span class="s">"Fizz"</span> } <circular>
</span></span><span class="line"><span class="cl"> { <span class="s">""</span> <span class="s">""</span> <span class="s">""</span> <span class="s">""</span> <span class="s">"Buzz"</span> } <circular>
</span></span><span class="line"><span class="cl"> lzip [ <span class="nb">concat </span>] lmap-lazy lzip <span class="k">;
</span></span></span></code></pre></div><p>We can print out the first few values quite simply:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> lfizzbuzz <span class="m">20 </span>ltake [ <span class="nb">first2 </span><span class="s">"%2d: %s\n"</span> printf ] leach
</span></span><span class="line"><span class="cl"> 1:
</span></span><span class="line"><span class="cl"> 2:
</span></span><span class="line"><span class="cl"> 3: Fizz
</span></span><span class="line"><span class="cl"> 4:
</span></span><span class="line"><span class="cl"> 5: Buzz
</span></span><span class="line"><span class="cl"> 6: Fizz
</span></span><span class="line"><span class="cl"> 7:
</span></span><span class="line"><span class="cl"> 8:
</span></span><span class="line"><span class="cl"> 9: Fizz
</span></span><span class="line"><span class="cl">10: Buzz
</span></span><span class="line"><span class="cl">11:
</span></span><span class="line"><span class="cl">12: Fizz
</span></span><span class="line"><span class="cl">13:
</span></span><span class="line"><span class="cl">14:
</span></span><span class="line"><span class="cl">15: FizzBuzz
</span></span><span class="line"><span class="cl">16:
</span></span><span class="line"><span class="cl">17:
</span></span><span class="line"><span class="cl">18: Fizz
</span></span><span class="line"><span class="cl">19:
</span></span><span class="line"><span class="cl">20: Buzz
</span></span></code></pre></div><p>And if we wanted a more traditional stream alternating between numbers and
labels:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> lfizzbuzz <span class="m">100 </span>ltake [ <span class="nb">first2 </span>[ <span class="nb">nip </span>] <span class="nb">unless-empty </span><span class="m">. </span>] leach
</span></span><span class="line"><span class="cl"><span class="m">1
</span></span></span><span class="line"><span class="cl"><span class="m">2
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="m">4
</span></span></span><span class="line"><span class="cl"><span class="s">"Buzz"</span>
</span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="m">7
</span></span></span><span class="line"><span class="cl"><span class="m">8
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="s">"Buzz"</span>
</span></span><span class="line"><span class="cl"><span class="m">11
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="m">13
</span></span></span><span class="line"><span class="cl"><span class="m">14
</span></span></span><span class="line"><span class="cl"><span class="s">"FizzBuzz"</span>
</span></span><span class="line"><span class="cl"><span class="m">16
</span></span></span><span class="line"><span class="cl"><span class="m">17
</span></span></span><span class="line"><span class="cl"><span class="s">"Fizz"</span>
</span></span><span class="line"><span class="cl"><span class="m">19
</span></span></span><span class="line"><span class="cl"><span class="s">"Buzz"</span>
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></div><p>While not the ultimate <a href="https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition">FizzBuzz Enterprise
Edition</a>,
this seems like a fun way to improve upon the simple <em>meant for whiteboards</em>
implementation that is most often shared.</p>