<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Brett Rowberry’s Blog]]></title><description><![CDATA[I love to write!]]></description><link>https://brettrowberry.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 11 Sep 2026 13:27:20 GMT</lastBuildDate><atom:link href="https://brettrowberry.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Vendor Email Addresses]]></title><description><![CDATA[Imagine you manage Team Awesome at Cool Company. You rely on a third-party vendor, Checkers. They need to send you and your team emails. Let's go through the options, from worst to best.
Individual Em]]></description><link>https://brettrowberry.com/vendor-email-addresses</link><guid isPermaLink="true">https://brettrowberry.com/vendor-email-addresses</guid><category><![CDATA[mailing list]]></category><category><![CDATA[group email]]></category><category><![CDATA[contact info]]></category><category><![CDATA[Vendor Management]]></category><category><![CDATA[IT]]></category><category><![CDATA[Company]]></category><category><![CDATA[email]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Fri, 04 Sep 2026 03:12:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/d20de1d8-6df4-402a-a3bf-c4306645e34a.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine you manage Team Awesome at Cool Company. You rely on a third-party vendor, Checkers. They need to send you and your team emails. Let's go through the options, from worst to best.</p>
<h1>Individual Emails</h1>
<p>Out of convenience, you have your contacts at Checkers email everyone on your team using their individual email address. This is the worst option. Why? If any of those people should no longer receive emails from Checkers, or any additional people should, it's extremely unlikely that you'll be able to get Checkers to update their lists. You're also likely to forget to tell them to update their info, especially if the communication is infrequent. After initial integration, it almost certainly will be.</p>
<h1>Team Mailing List</h1>
<p>If you give Checkers a team mailing list, <code>teamawesome@coolcompany.com</code>, you get to control who receives emails. Three months later, there's a reorg at Cool Company, and Team Awesome ceases to exist. Oof. This isn't a terrible outcome, but when someone in IT without context decides to delete this team mailing list without context, communication is severed.</p>
<h1>Vendor Mailing List</h1>
<p>Here's the best option. Make a group email address named for the vendor, <code>checkers@coolcompany.com</code>. That will survive any reorg at your company. You can have emails forward to any individual or group, including <code>teamawesome@coolcompany.com</code>. It's also unlikely to be deleted so long as people know this vendor is still in use. Cool Company or Checkers could still change their name. Still, that happens a whole lot less often than the other two scenarios above.</p>
<h1>Summary</h1>
<p>When giving email contact info to a vendor, your options are:</p>
<ul>
<li><p>Bad: <code>me@mycompany.com</code></p>
</li>
<li><p>Better: <code>myteam@mycompany.com</code></p>
</li>
<li><p>Best: <code>vendor@mycompany.com</code></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Claude Code & Homebrew]]></title><description><![CDATA[I use Claude Code at work. Like everything else, I try to install it using Homebrew. There was a feature of Claude Code I wanted and Homebrew seemed to not have the version that supported it yet. I di]]></description><link>https://brettrowberry.com/claude-code-homebrew</link><guid isPermaLink="true">https://brettrowberry.com/claude-code-homebrew</guid><category><![CDATA[package manager]]></category><category><![CDATA[macOS]]></category><category><![CDATA[Homebrew]]></category><category><![CDATA[claude-code]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Thu, 03 Sep 2026 04:26:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/da5069b2-e2fd-47b8-b2e3-9e78ea4e0a3c.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I use Claude Code at work. Like everything else, I try to install it using Homebrew. There was a feature of Claude Code I wanted and Homebrew seemed to not have the version that supported it yet. I did a little looking and that's when I learned:</p>
<blockquote>
<p>Homebrew offers two casks. <code>claude-code</code> tracks the stable release channel, which is typically about a week behind and skips releases with major regressions. <code>claude-code@latest</code> tracks the latest channel and receives new versions as soon as they ship.</p>
<p><a href="https://code.claude.com/docs/en/overview#homebrew">https://code.claude.com/docs/en/overview#homebrew</a></p>
</blockquote>
<p>So, I uninstalled <code>claude-code</code> and installed <code>cloud-code@latest</code> and I got the latest version!</p>
<p>There's another important note on that page:</p>
<blockquote>
<p>Homebrew installations do not auto-update. Run <code>brew upgrade claude-code</code> or <code>brew upgrade claude-code@latest</code>, depending on which cask you installed, to get the latest features and security fixes.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Ninja Creami Vanilla Ice Cream Recipe]]></title><description><![CDATA[Ingredients

2 c heavy cream

1 c whole milk

1/2 c white sugar

1/4 c brown sugar

1 Tbsp vanilla extract

pinch of salt


Directions

Combine all ingredients into a bowl and mix.

Pour into two Crea]]></description><link>https://brettrowberry.com/ninja-creami-vanilla-ice-cream-recipe</link><guid isPermaLink="true">https://brettrowberry.com/ninja-creami-vanilla-ice-cream-recipe</guid><category><![CDATA[ice-cream]]></category><category><![CDATA[Vanilla]]></category><category><![CDATA[ninja creami]]></category><category><![CDATA[real food]]></category><category><![CDATA[homemade]]></category><category><![CDATA[dessert]]></category><category><![CDATA[Frozen ]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Wed, 26 Aug 2026 04:02:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/8a02d234-121a-4715-b4bb-5b24c5f98ddb.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Ingredients</h1>
<ul>
<li><p>2 c heavy cream</p>
</li>
<li><p>1 c whole milk</p>
</li>
<li><p>1/2 c white sugar</p>
</li>
<li><p>1/4 c brown sugar</p>
</li>
<li><p>1 Tbsp vanilla extract</p>
</li>
<li><p>pinch of salt</p>
</li>
</ul>
<h1>Directions</h1>
<ol>
<li><p>Combine all ingredients into a bowl and mix.</p>
</li>
<li><p>Pour into two Creami jars.</p>
</li>
<li><p>Freeze 24 hours.</p>
</li>
<li><p>Mix on the <code>Ice Cream</code> setting.</p>
</li>
</ol>
<h1>Tips</h1>
<h2>Immersion Blender</h2>
<p>When I mix the ingredients with an immersion blender, the ice cream's texture seems more like hard ice cream than soft serve.</p>
<h2>Vanilla</h2>
<p>Use the best vanilla extract you have since it's basically the entire flavor of the ice cream. I like homemade rum vanilla.</p>
<h2>1/4 Cup Measuring Cup</h2>
<p>If you use a 1/4 c measuring cup for the white sugar first (two scoops!), it will be clean for scooping the brown sugar. Then, you only have to get one measuring cup dirty.</p>
<h2>Let The Mixture Rest</h2>
<p>I've heard it said that after mixing you should refrigerate the mixture before freezing. This may help in two ways. First, it allows air bubbles to escape, which might help your Creami blend more smoothly. Second, it brings the entire mixture down to refrigerator temperature, which could reduce the time required to freeze, keeping ice crystals small. Smaller ice crystals mean creamier, smoother ice cream.</p>
]]></content:encoded></item><item><title><![CDATA[When is Credit Card Cash Back Worth its Fee?]]></title><description><![CDATA[I have a credit card that offers cash back on purchases. Credit cards provide a time buffer between when a charge is incurred and when funds leave the checking account paying it off. This helps avoid ]]></description><link>https://brettrowberry.com/when-is-credit-card-cash-back-worth-its-fee</link><guid isPermaLink="true">https://brettrowberry.com/when-is-credit-card-cash-back-worth-its-fee</guid><category><![CDATA[credit card]]></category><category><![CDATA[cash back]]></category><category><![CDATA[fees ]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Wed, 29 Jul 2026 02:11:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/ceb5d742-10a9-48bf-bd89-916ed0f91924.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I have a credit card that offers cash back on purchases. Credit cards provide a time buffer between when a charge is incurred and when funds leave the checking account paying it off. This helps avoid overdraft charges. Credit cards also offer fraud protection, and sometimes even warranties.</p>
<p>Some sellers don't charge a fee when paying via cash, debit card, or ACH transfer, but do when using a credit card. The fees I've experience are either flat or a percentage. I've wondered when the cash back becomes worth it. Let's break it down.</p>
<h1>Flat Fees</h1>
<p>My electric utility charges a $5 fee when paying via credit card and my credit card offers 3% cash back on everything (really, it's a Robinhood Gold Card). On a $100 charge, the cash back $3, less than the fee. On a $200 charge, the cash back is $6, exceeding the fee. Finding the break-even point is subtle. It's time for some math!</p>
<p>I'll use lower case letters, e.g. <em>c</em>, for percentage values and capital letters, e.g. <em>C</em>, for dollar amounts. First, I'll define terms:</p>
<ul>
<li><p><em>C</em> cash back, e.g. $3 (say 3% on a $100 purchase)</p>
</li>
<li><p><em>F</em> fee, e.g. $5</p>
</li>
<li><p><em>c</em> cash back percentage, e.g. 3% or 0.03</p>
</li>
<li><p><em>P</em> purchase amount, e.g. $100</p>
</li>
</ul>
<p>The cash back earned isn't on the base amount, it's on the bill plus the fee. We can express this as:</p>
<p><em>C = c(P + F)</em></p>
<p>Using the credit card is worth it when the cash back is at least equal to the fee:</p>
<p><em>C ≥ F</em></p>
<p>With a substitution:</p>
<p><em>c(P + F) ≥ F</em></p>
<p>At what purchase amount does it make sense to use the credit card? Let's isolate <em>P</em> :</p>
<p><em>c(P + F) ≥ F</em><br />cP +cF ≥ F<br />cP ≥ F - cF<br />P ≥ (F - cF) / c<br />P ≥ F (1 - c) / c</p>
<p>Let's test it using the $5 fee and 3% cash back from before:</p>
<p>P ≥ 5 (1 - 0.03) / 0.03<br />P ≥ 161.67</p>
<p>This checks out: 3% of $166.67 ($161.67 plus the $5 fee) is $5.</p>
<p>So, at purchase amounts higher than $161.67, I start making money.</p>
<h1>Percentage Fees</h1>
<p>When I pay my water bill via ACH, there is no fee. However, with a credit card, the fee is 3%. Most of us assume the credit card cash back percentage has to exceed the fee percentage to be worth it. As we established earlier, the cash back is based on the purchase amount plus the fee, not the purchase amount alone. Let's see what the math tells us:</p>
<ul>
<li><p><em>f</em> fee percentage, e.g. 3% or 0.03</p>
</li>
<li><p><em>C</em> cash back, e.g. $3 (say 3% from a $100 purchase)</p>
</li>
<li><p><em>F</em> fee, e.g. $5</p>
</li>
<li><p><em>c</em> cash back percentage, e.g. 3% or 0.03</p>
</li>
<li><p><em>P</em> purchase amount, e.g. $100</p>
</li>
</ul>
<p>How much is the fee?</p>
<p><em>F = fP</em></p>
<p>How much is the cash back?</p>
<p><em>C = c(P + F)<br />C = c(P + fP)<br />C = cP(1 + f)</em></p>
<p>Using a credit card makes sense once the cash back exceeds the fee. Let's isolate <em>c</em>:</p>
<p>C ≥ F<br />cP(1 + f) ≥ fP<br />c(1 + f) ≥ f<br />c ≥ f / (1 + f)</p>
<p>Note that the purchase amount doesn't matter.</p>
<p>Let's evaluate this with a 3% fee:</p>
<p>c ≥ 0.03 / (1 + 0.03)<br />c ≥ 0.02912621359</p>
<p>The cash back percentage doesn't need to be as large as the percentage fee!</p>
<p>Let's test that with an example. Say the bill is $100. With a 3% fee, the charge is $103. A cash back rate of 2.91% yields $3 in cash back and a cash back rate of 2.92% yields $3.01.</p>
<h1>Conclusion</h1>
<p>To determine whether using a credit card is worth it in the face of fees, remember:</p>
<ul>
<li><p>For flat fees, you have to do some math: <em>P ≥ F (1-c) / c</em></p>
</li>
<li><p>For percentage fees, having the cash back percentage equal to the fee percentage is always worth it. To arrive at the precise cash back percentage needed, use <em>c ≥ f / (1 + f).</em></p>
</li>
</ul>
<hr />
<p>Footnote: Why did't I use LaTeX or Mathjax notation? I did. But, the Hashnode editor was very painful, and I experienced data loss. So, Italics it is.</p>
]]></content:encoded></item><item><title><![CDATA[Early Read on Kotlin Community]]></title><description><![CDATA[I want to get into the Kotlin community to accelerate my learning. Where should I go?
Well, this was handy, https://kotlinlang.org/community/. I went through each of these resources. Unless stated oth]]></description><link>https://brettrowberry.com/early-read-on-kotlin-community</link><guid isPermaLink="true">https://brettrowberry.com/early-read-on-kotlin-community</guid><category><![CDATA[Kotlin]]></category><category><![CDATA[community]]></category><category><![CDATA[blog]]></category><category><![CDATA[podcast]]></category><category><![CDATA[youtube]]></category><category><![CDATA[reddit]]></category><category><![CDATA[LinkedIn]]></category><category><![CDATA[Stack Overflow]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Wed, 15 Jul 2026 04:09:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/d2f9bdc7-67c1-4c4c-a61a-5b0aa09e99f6.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I want to get into the Kotlin community to accelerate my learning. Where should I go?</p>
<p>Well, this was handy, <a href="https://kotlinlang.org/community/">https://kotlinlang.org/community/</a>. I went through each of these resources. Unless stated otherwise, I got set up on July 14, 2026.</p>
<ul>
<li><p>Slack. I filled out the form and waited some number of days. I was invited to join on July 10, 2026. I quickly found my way to the #http4k channel. It's a little busier than the #reitit channel of the Clojurians Slack.</p>
</li>
<li><p>X. I followed the Kotlin account. It seems to post more than once per day.</p>
</li>
<li><p>Kotlin Blog. I use NetNewsWire and subscribed. Looks like there are a few posts a week.</p>
</li>
<li><p>Reddit. Also joined. I expect I'll use this less than all of the above. That has more to do with me not being a big Reddit user than anything else.</p>
</li>
<li><p>StackOverflow. I started watching the tag. I can't think of the last time I landed on StackOverflow.</p>
</li>
<li><p>YouTube. Subscribed. I watched the KotlinConf '26 keynote back in June. It was a good overview of what's happening now in the language.</p>
</li>
<li><p>Talking Kotlin. I use Overcast as my podcast player. I subscribed. It looks like the first episode was published January 11, 2017 and there are 145 episodes to date. The cadence seemed to be two a month at the start and now it looks like it's closer to monthly.</p>
</li>
<li><p>LinkedIn. There seem to be some good posts.</p>
</li>
<li><p>Issue Tracker. I don't think I'm going to use this.</p>
</li>
<li><p>Awesome Kotlin. I'll definitely come back to this.</p>
</li>
</ul>
<p>So far, my impression is that the Kotlin community is much more organized and larger and the Clojure and F# communities of which I have been a very happy participant. That probably isn't a surprise to anyone.</p>
]]></content:encoded></item><item><title><![CDATA[Hello, Kotlin!]]></title><description><![CDATA[We're switching from Clojure to Kotlin at work. Is that good? I don't know yet! Here are some things I love about Clojure:

its incredible REPL

EDN

keywords

maps with heterogeneous keys and values
]]></description><link>https://brettrowberry.com/hello-kotlin</link><guid isPermaLink="true">https://brettrowberry.com/hello-kotlin</guid><category><![CDATA[Kotlin]]></category><category><![CDATA[programming language]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Thu, 25 Jun 2026 01:31:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/2af3ec77-74e2-4932-b6a3-427a9b2673db.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We're switching from Clojure to Kotlin at work. Is that good? I don't know yet! Here are some things I love about Clojure:</p>
<ul>
<li><p>its incredible REPL</p>
</li>
<li><p>EDN</p>
</li>
<li><p>keywords</p>
</li>
<li><p>maps with heterogeneous keys and values</p>
</li>
<li><p>structural editing</p>
</li>
<li><p>beautiful, data-oriented <a href="https://github.com/metosin">Metosin libraries</a></p>
</li>
<li><p>the big ideas</p>
</li>
</ul>
<p>My journey learning Kotlin has begun!</p>
]]></content:encoded></item><item><title><![CDATA[Vertical Tabs in Chrome]]></title><description><![CDATA[I've been using Arc Browser for a long time. Why? Because I love vertical tabs in my browser. They allow me to read more of each tab's title when I have a lot of tabs.
What Are Vertical Tabs?
Tabs are]]></description><link>https://brettrowberry.com/vertical-tabs-in-chrome</link><guid isPermaLink="true">https://brettrowberry.com/vertical-tabs-in-chrome</guid><category><![CDATA[mouse]]></category><category><![CDATA[trackpad]]></category><category><![CDATA[mac]]></category><category><![CDATA[vertical-tabs]]></category><category><![CDATA[horizontal-tabs]]></category><category><![CDATA[tabs]]></category><category><![CDATA[browser]]></category><category><![CDATA[arc_browser]]></category><category><![CDATA[Google Chrome]]></category><category><![CDATA[Google Chrome]]></category><category><![CDATA[claude]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Fri, 17 Apr 2026 03:41:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/cf12b583-bb04-46e9-9bf4-666b54035ad6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been using <a href="https://arc.net/">Arc Browser</a> for a long time. Why? Because I love vertical tabs in my browser. They allow me to read more of each tab's title when I have a lot of tabs.</p>
<h2>What Are Vertical Tabs?</h2>
<p>Tabs are tabs. When we say vertical or horizontal tabs, we're talking about how they're displayed. Vertical tabs are arranged in a vertical stack, instead of a horizontal list.</p>
<h2>What's Wrong With Horizontal Tabs?</h2>
<p>As horizontal tabs accumulate, they either have to get narrower (less legible) or be scrolled sideways, which is difficult to do with most mice (but not trackpads!).</p>
<h2>Are Vertical Tabs New?</h2>
<p>Vertical tabs in software applications aren't a new concept. After all, look this macOS Finder window with "tabs" <code>Recents</code>, <code>Shared</code>, etc.:</p>
<img src="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/02a9a97f-39f5-4af6-a3e2-de74502b32b0.png" alt="macOS Finder window showing horizontal tabs" style="display:block;margin:0 auto" />

<h2>Tabs in Browsers</h2>
<p>Many browsers have had horizontal tabs for a long time. Apparently, <a href="https://www.buzzfeednews.com/article/josephbernstein/meet-the-man-who-invented-tabs">horizontal tabs in browsers first appeared in 1997 with SimulBrowse (later NetCaptor) by Adam Stiles. Mozilla picked up and popularized it in 2002</a>. I love this snippet from the interview:</p>
<blockquote>
<p><strong>Did you have an "aha!" moment, when you realized that tabbed browsing would be a good thing to put in NetCaptor?</strong></p>
<p><strong>Adam Stiles:</strong> NetCaptor (originally SimulBrowse) was built from the beginning to be a tabbed browser. The HTML editor I was using at the time (HomeSite) had tabs, so I was used to flipping between a bunch of HTML documents. I wanted the same thing in my browser, so I built it. At first it was just an experiment to see if I could do it.</p>
</blockquote>
<p>From developer tools to the mainstream!</p>
<h2>Vertical Tabs in Browsers</h2>
<p>From what I can gather, Opera got vertical tabs in 2005. Chrome had an early version that was scrapped, but it officially got them back on <a href="https://blog.google/products-and-platforms/products/chrome/new-chrome-productivity-features/">April 7, 2026</a>.</p>
<h2>Why Leave Arc?</h2>
<p>If Arc was working for me, why switch back to Chrome? Well, I use Claude at work and I can't get the currently experimental <a href="https://claude.com/claude-for-chrome">Claude for Chrome</a> extension to work with Arc.</p>
<h2>Enabling Vertical Tabs in Google Chrome</h2>
<p>To enable this feature, I had to go to <code>chrome://flags/#vertical-tabs</code> and switch from <code>Default</code> to <code>Enabled</code>. <em>For reference, my installed version of Chrome is Version 147.0.7727.102 (Official Build) (arm64).</em></p>
<img src="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/65d335a0-caf0-40b2-8c50-ee8ccc5c7313.png" alt="" style="display:block;margin:0 auto" />

<p>Wait, nothing happened. I called my brother. Turns out this flag enables the feature, but the arrangement of tabs still has to be toggled from horizontal to vertical. To do so, secondary click (right click) on a tab and select <code>Show Tabs Vertically</code>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/62fbc765-ac7f-494c-8a59-b0ff527d27f7.png" alt="" style="display:block;margin:0 auto" />

<p>Voilà! Vertical tabs!</p>
<img src="https://cdn.hashnode.com/uploads/covers/613450e6489de51a6a7aed22/8cd1fa76-3d46-4c61-8b3d-3bcf10c455fb.png" alt="" style="display:block;margin:0 auto" />

<p>As you can imagine, to switch back to horizontal tabs, do a secondary click (right click) on a tab and select <code>Show Tabs Horizontally</code>.</p>
<h2>Aside</h2>
<p>Why do I say secondary click instead of right click? Because I'm an insufferable left-handed Mac user that uses mice, vertical and otherwise, and trackpads ambidextrously. So, to me, they're primary and secondary click, not left and right click.</p>
]]></content:encoded></item><item><title><![CDATA[Transpose a Matrix in Clojure]]></title><description><![CDATA[Imagine rows of letters, numbers, and Greek letters:
[[:a :b]
 [:1 :2]
 [:alpha :beta]]

Now, you want to transpose them. You started with a vector of vectors. Clojure's map function is pretty amazing]]></description><link>https://brettrowberry.com/transpose-a-matrix-in-clojure</link><guid isPermaLink="true">https://brettrowberry.com/transpose-a-matrix-in-clojure</guid><category><![CDATA[transpose]]></category><category><![CDATA[Clojure]]></category><category><![CDATA[Matrix]]></category><category><![CDATA[map]]></category><category><![CDATA[Functional Programming]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Thu, 06 Nov 2025 05:27:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/iar-afB0QQw/upload/4282357e0350e755e23ae2cdd586e1ff.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine rows of letters, numbers, and Greek letters:</p>
<pre><code class="language-plaintext">[[:a :b]
 [:1 :2]
 [:alpha :beta]]
</code></pre>
<p>Now, you want to transpose them. You started with a vector of vectors. Clojure's <a href="https://clojuredocs.org/clojure.core/map"><code>map</code></a> function is pretty amazing::</p>
<blockquote>
<ul>
<li><p>(map f)</p>
</li>
<li><p>(map f coll)</p>
</li>
<li><p>(map f c1 c2)</p>
</li>
<li><p>(map f c1 c2 c3)</p>
</li>
<li><p>(map f c1 c2 c3 &amp; colls)</p>
</li>
</ul>
<p>Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments. Returns a transducer when no collection is provided.</p>
</blockquote>
<p>Normally, I think of this arity of <code>map</code>: <code>(map f coll)</code>. In your case, you have three collections, so you'll make use of <code>(map f c1 c2 c3)</code>. You want to stick with vectors, so you'll use <code>mapv</code>, which has the same semantics.</p>
<p>If you ignore the outer vector, you can use <code>mapv</code> with <code>vector</code>:</p>
<pre><code class="language-clojure">(mapv vector [:a :b] [:1 :2] [:alpha :beta])
;;=&gt; [[:a :1 :alpha]
;;    [:b :2 :beta]]
</code></pre>
<p>You don’t have to omit the outer vector thanks to the magic of <a href="https://clojuredocs.org/clojure.core/apply"><code>apply</code></a>, which allows you to pass a collection of arguments to a function that wants individual arguments:</p>
<pre><code class="language-clojure">(apply mapv vector [[:a :b] [:1 :2] [:alpha :beta]])
;;=&gt; [[:a :1 :alpha]
;;    [:b :2 :beta]]
</code></pre>
<p>This is amazing.</p>
]]></content:encoded></item><item><title><![CDATA[Binary Search in Clojure]]></title><description><![CDATA[I decided to implement linear search before going after binary search. Now, I’m ready!
With linear search, we required the elements be sorted. We didn’t require the elements be bounded. In binary search, the inputs must be bounded because we maintain...]]></description><link>https://brettrowberry.com/binary-search-in-clojure</link><guid isPermaLink="true">https://brettrowberry.com/binary-search-in-clojure</guid><category><![CDATA[Clojure]]></category><category><![CDATA[Binary Search Algorithm]]></category><category><![CDATA[search]]></category><category><![CDATA[division operator]]></category><category><![CDATA[integer]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Tue, 04 Nov 2025 03:04:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/jPVcZsxRGJo/upload/42b67a1ae45df4e5ecd754ffcf527a10.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I decided to implement <a target="_blank" href="https://brettrowberry.com/linear-search-in-clojure">linear search</a> before going after binary search. Now, I’m ready!</p>
<p>With linear search, we required the elements be sorted. We didn’t require the elements be bounded. In binary search, the inputs must be bounded because we maintain two indexes or pointers that start at the beginning and end of the search space. Because we move one index half-way closer to the other each iteration, the time complexity is O(log n).</p>
<h1 id="heading-solution">Solution</h1>
<p>Loop recur was a nice combination for linear search. So, we’ll use it again here.</p>
<pre><code class="lang-clojure">(<span class="hljs-keyword">defn</span> <span class="hljs-title">binary-search</span>
  [x xs]
  (<span class="hljs-name"><span class="hljs-builtin-name">loop</span></span> [low <span class="hljs-number">0</span>
         high (<span class="hljs-name"><span class="hljs-builtin-name">dec</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">count</span></span> xs))]
    (<span class="hljs-name"><span class="hljs-builtin-name">when</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">&lt;=</span></span> low high)
      (<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [mid (<span class="hljs-name"><span class="hljs-builtin-name">quot</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">+</span></span> low high) <span class="hljs-number">2</span>)
            mid-val (<span class="hljs-name">xs</span> mid)]
        (<span class="hljs-name"><span class="hljs-builtin-name">cond</span></span>
          (<span class="hljs-name"><span class="hljs-builtin-name">=</span></span> x mid-val) mid
          (<span class="hljs-name"><span class="hljs-builtin-name">&lt;</span></span> x mid-val) (<span class="hljs-name"><span class="hljs-builtin-name">recur</span></span> low (<span class="hljs-name"><span class="hljs-builtin-name">dec</span></span> mid))  <span class="hljs-comment">;; x in left half, scoot high index</span>
          <span class="hljs-symbol">:else</span>         (<span class="hljs-name"><span class="hljs-builtin-name">recur</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> mid) high) <span class="hljs-comment">;; x in right half, scoot low index</span>
          )))))
</code></pre>
<h1 id="heading-challenges">Challenges</h1>
<h2 id="heading-two-are-better-than-one">Two Are Better Than One</h2>
<p>One of the hardest parts for me in figuring this out was that I forgot two indexes are necessary. I tried using a single index and it never converged.</p>
<h2 id="heading-integer-division">Integer Division</h2>
<p>In addition, my <code>mid</code> formula was wrong!</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [low <span class="hljs-number">1</span>
      high <span class="hljs-number">10</span>]
  [(/ (<span class="hljs-name"><span class="hljs-builtin-name">+</span></span> low high) <span class="hljs-number">2</span>)      <span class="hljs-comment">;; 11/2</span>
   (<span class="hljs-name"><span class="hljs-builtin-name">quot</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">+</span></span> low high) <span class="hljs-number">2</span>)]) <span class="hljs-comment">;; 5</span>
</code></pre>
<p>Sometimes, <code>/</code> returns a <code>clojure.lang.Ratio</code> while <code>quot</code> always returns a <code>java.lang.Long</code>. I’ve never used <code>quot</code> before. In C, <code>/</code> truncates toward 0 when both inputs are <code>int</code>s, which is what we need.</p>
<h1 id="heading-tests">Tests</h1>
<pre><code class="lang-clojure">(<span class="hljs-name">are</span> [x xs i] (<span class="hljs-name"><span class="hljs-builtin-name">=</span></span> (<span class="hljs-name">binary-search</span> x xs) i)
  <span class="hljs-number">1</span> [] <span class="hljs-literal">nil</span>
  <span class="hljs-number">1</span> [<span class="hljs-number">1</span>] <span class="hljs-number">0</span>
  <span class="hljs-number">1</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span>] <span class="hljs-number">0</span>
  <span class="hljs-number">-1</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-literal">nil</span>
  <span class="hljs-number">1</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-number">0</span>
  <span class="hljs-number">3</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-number">1</span>
  <span class="hljs-number">5</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-number">2</span>
  <span class="hljs-number">7</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-number">3</span>
  <span class="hljs-number">9</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-number">4</span>
  <span class="hljs-number">10</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-literal">nil</span>
  <span class="hljs-number">25</span> (<span class="hljs-name"><span class="hljs-builtin-name">vec</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">range</span></span> <span class="hljs-number">101</span>)) <span class="hljs-number">25</span>
  <span class="hljs-number">75</span> (<span class="hljs-name"><span class="hljs-builtin-name">vec</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">range</span></span> <span class="hljs-number">101</span>)) <span class="hljs-number">75</span>)
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Linear Search in Clojure]]></title><description><![CDATA[I consider myself a classically trained computer scientist. However, I don’t regularly practice implementing algorithms at home. I hope to do more of that! At work, I do much higher level things, like partnering with a product manager, establishing a...]]></description><link>https://brettrowberry.com/linear-search-in-clojure</link><guid isPermaLink="true">https://brettrowberry.com/linear-search-in-clojure</guid><category><![CDATA[algorithms]]></category><category><![CDATA[linearsearch]]></category><category><![CDATA[Clojure]]></category><category><![CDATA[search]]></category><category><![CDATA[sorted]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Sun, 02 Nov 2025 03:43:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/d9ILr-dbEdg/upload/992039f07e98b875e23135fffb035ae2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I consider myself a classically trained computer scientist. However, I don’t regularly practice implementing algorithms at home. I hope to do more of that! At work, I do much higher level things, like partnering with a product manager, establishing and maintaining monitoring and alerting, setting up on-call rotations, capacity planning, etc. However, I wanted to see if I could implement a binary search algorithm. Then I thought, can I do a linear search?</p>
<p>First, what do I mean by search? Find the location, or index, of a desired item in a sorted collection.</p>
<p>We’ll assume the collection is sorted in ascending order (1, 2, 3, … and not 10, 9, 8, …). This doesn’t actually matter for linear search. It does matter for binary search! The best case for a linear search algorithm is O(1), when the desired item is the first in the collection. The worst case is O(n), when the desired item is the last in the collection or isn’t present at all. One thing I really want in my implementation is early return.</p>
<p>Since most of my algorithmic training was done in C (probably C89 since variable declarations for iterators had to happen outside of for loops), I thought I’d start with <code>while</code>. This turned out to be very painful! I included a little test suite.</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">ns</span></span> sorting
  (<span class="hljs-symbol">:require</span> [clojure.test <span class="hljs-symbol">:refer</span> [are]]))

(<span class="hljs-keyword">defn</span> <span class="hljs-title">linear-search-while</span>
  [x xs]
  (<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [i (<span class="hljs-name"><span class="hljs-builtin-name">atom</span></span> <span class="hljs-number">0</span>)]
    (<span class="hljs-name"><span class="hljs-builtin-name">while</span></span>
     (<span class="hljs-name"><span class="hljs-builtin-name">and</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">not=</span></span> x (<span class="hljs-name"><span class="hljs-builtin-name">get</span></span> xs @i))     <span class="hljs-comment">;; haven't found it yet</span>
          (<span class="hljs-name"><span class="hljs-builtin-name">&lt;</span></span> @i (<span class="hljs-name"><span class="hljs-builtin-name">dec</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">count</span></span> xs)))) <span class="hljs-comment">;; haven't gotten to the end yet</span>
      (<span class="hljs-name"><span class="hljs-builtin-name">swap!</span></span> i inc))
    (<span class="hljs-name"><span class="hljs-builtin-name">if</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">=</span></span> x (<span class="hljs-name"><span class="hljs-builtin-name">get</span></span> xs @i))          <span class="hljs-comment">;; find it?</span>
      @i
      <span class="hljs-literal">nil</span>)))

(<span class="hljs-name">are</span> [x xs i] (<span class="hljs-name"><span class="hljs-builtin-name">=</span></span> (<span class="hljs-name">linear-search-while</span> x xs) i)
  <span class="hljs-number">1</span> [] <span class="hljs-literal">nil</span>
  <span class="hljs-number">1</span> [<span class="hljs-number">1</span>] <span class="hljs-number">0</span>
  <span class="hljs-number">1</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-number">0</span>
  <span class="hljs-number">5</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-number">2</span>
  <span class="hljs-number">9</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-number">4</span>
  <span class="hljs-number">-1</span> [<span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">5</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span>] <span class="hljs-literal">nil</span>)
</code></pre>
<p>I got the stopping condition in the while loop wrong several times. First, we want to stop when we’ve found <code>x</code>. Second, we want to stop once we’ve exhausted the collection. I can’t think of a time I had less fun writing Clojure. Mutation, manually keeping track of an index, fiddling with a while loop. This is the worst. It does work, though! One thing that jumped out to me implementing this the use of <code>nil</code> instead of a sentinel value, like -1, that is common when coding in something like C.</p>
<p>What’s like a while loop but way better? Loop and recur! With a while loop, you say what must be true to continue. With loop recur, you say when to try another iteration and with what input. So, here’s a version that uses that.</p>
<pre><code class="lang-clojure">(<span class="hljs-keyword">defn</span> <span class="hljs-title">linear-search-loop-recur-cond</span>
  [x xs]
  (<span class="hljs-name"><span class="hljs-builtin-name">loop</span></span> [i <span class="hljs-number">0</span>]
    (<span class="hljs-name"><span class="hljs-builtin-name">cond</span></span>
      (<span class="hljs-name"><span class="hljs-builtin-name">&gt;=</span></span> i (<span class="hljs-name"><span class="hljs-builtin-name">count</span></span> xs)) <span class="hljs-literal">nil</span>    <span class="hljs-comment">;; we're at the end, not found</span>
      (<span class="hljs-name"><span class="hljs-builtin-name">=</span></span> x (<span class="hljs-name"><span class="hljs-builtin-name">nth</span></span> xs i)) i       <span class="hljs-comment">;; found it</span>
      <span class="hljs-symbol">:else</span> (<span class="hljs-name"><span class="hljs-builtin-name">recur</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> i))))) <span class="hljs-comment">;; try again at the next spot</span>
</code></pre>
<p>This is so much better!</p>
<p>Here’s another way to do it.</p>
<pre><code class="lang-clojure">(<span class="hljs-keyword">defn</span> <span class="hljs-title">linear-search-loop-recur-when</span>
  [x xs]
  (<span class="hljs-name"><span class="hljs-builtin-name">loop</span></span> [i <span class="hljs-number">0</span>]
    (<span class="hljs-name"><span class="hljs-builtin-name">when</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">&lt;</span></span> i (<span class="hljs-name"><span class="hljs-builtin-name">count</span></span> xs))  <span class="hljs-comment">;; don't run off the end</span>
      (<span class="hljs-name"><span class="hljs-builtin-name">if</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">=</span></span> x (<span class="hljs-name"><span class="hljs-builtin-name">nth</span></span> xs i))  <span class="hljs-comment">;; find it?</span>
        i                   <span class="hljs-comment">;; found it</span>
        (<span class="hljs-name"><span class="hljs-builtin-name">recur</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> i)))))) <span class="hljs-comment">;; try again at the next spot</span>
</code></pre>
<p>It’s the same number of lines. I like both.</p>
]]></content:encoded></item><item><title><![CDATA[Clojure +, +', and unchecked-add]]></title><description><![CDATA[+
In Clojure core there’s a handy function, +. I’ll bet you know what it does:
(+ 1 2 3)
;;=> 6

Let’s introduce a handy function as we explore:
(defn value-and-type
  [& args]
  (map (juxt identity type) args))

Let’s look at the largest supported L...]]></description><link>https://brettrowberry.com/clojure-plus-plus-prime-and-unchecked-add</link><guid isPermaLink="true">https://brettrowberry.com/clojure-plus-plus-prime-and-unchecked-add</guid><category><![CDATA[unchecked]]></category><category><![CDATA[overflow]]></category><category><![CDATA[underflow]]></category><category><![CDATA[Math]]></category><category><![CDATA[Clojure]]></category><category><![CDATA[Java]]></category><category><![CDATA[exception]]></category><category><![CDATA[throw]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Thu, 09 Oct 2025 03:33:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759980823884/d9daf835-1082-4c94-af1b-bd7f56cd950d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-kw">+</h1>
<p>In Clojure core there’s a handy function, <code>+</code>. I’ll bet you know what it does:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">+</span></span> <span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">3</span>)
<span class="hljs-comment">;;=&gt; 6</span>
</code></pre>
<p>Let’s introduce a handy function as we explore:</p>
<pre><code class="lang-clojure">(<span class="hljs-keyword">defn</span> <span class="hljs-title">value-and-type</span>
  [&amp; args]
  (<span class="hljs-name"><span class="hljs-builtin-name">map</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">juxt</span></span> identity type) args))
</code></pre>
<p>Let’s look at the largest supported <code>Long</code>:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span> Long/MAX_VALUE)
<span class="hljs-comment">;;=&gt; ([9223372036854775807 java.lang.Long])</span>
</code></pre>
<p>What happens if we exceed it?</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span> (<span class="hljs-name"><span class="hljs-builtin-name">+</span></span> <span class="hljs-number">1</span> Long/MAX_VALUE))
<span class="hljs-comment">;;=&gt; Execution error (ArithmeticException) at java.lang.Math/addExact (Math.java:931).</span>
<span class="hljs-comment">;;   long overflow</span>
</code></pre>
<p>It throws!</p>
<h1 id="heading-kyc">+'</h1>
<p>The fact that <code>+</code> throws on overflow is why <code>+'</code> exists:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span> (<span class="hljs-name">+'</span> <span class="hljs-number">1</span> Long/MAX_VALUE))
<span class="hljs-comment">;;=&gt; ([9223372036854775808N</span>
<span class="hljs-comment">;;     clojure.lang.BigInt])</span>
</code></pre>
<p>Instead of overflowing, it promoted from a <code>Long</code> to a <code>BigInt</code>. In addition to <code>+'</code>, there are <code>-'</code>, <code>*'</code>, <code>inc'</code>, and <code>dec'</code>.</p>
<h1 id="heading-unchecked-add">unchecked-add</h1>
<p>Now for <code>unchecked-add</code>. Notice how it wraps around:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span>
 Long/MIN_VALUE
 (<span class="hljs-name"><span class="hljs-builtin-name">unchecked-add</span></span> Long/MAX_VALUE <span class="hljs-number">1</span>))
<span class="hljs-comment">;;=&gt; ([-9223372036854775808 java.lang.Long]</span>
<span class="hljs-comment">;;    [-9223372036854775808 java.lang.Long])</span>
</code></pre>
<p>In addition to <code>unchecked-add</code>, there are <code>unchecked-subtract</code>, <code>unchecked-multiply</code>, <code>unchecked-inc</code>, <code>unchecked-dec</code>, and <code>unchecked-negate</code>.</p>
<h1 id="heading-summary">Summary</h1>
<p>If you’re dealing with a <code>Long</code>, on overflow:</p>
<ul>
<li><p><code>+</code> throws</p>
</li>
<li><p><code>+'</code> promotes to <code>BigInt</code></p>
</li>
<li><p><code>unchecked-add</code> wraps around</p>
</li>
</ul>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">+</span></span> Long/MAX_VALUE <span class="hljs-number">1</span>)
<span class="hljs-comment">;;=&gt; Execution error (ArithmeticException) at java.lang.Math/addExact (Math.java:931).</span>
<span class="hljs-comment">;;   long overflow</span>
(<span class="hljs-name">+'</span> Long/MAX_VALUE <span class="hljs-number">1</span>)
<span class="hljs-comment">;;=&gt; 9223372036854775808N</span>
(<span class="hljs-name"><span class="hljs-builtin-name">unchecked-add</span></span> Long/MAX_VALUE <span class="hljs-number">1</span>)
<span class="hljs-comment">;;=&gt; -9223372036854775808</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Clojure Ratios]]></title><description><![CDATA[Computers do math really quickly. Yet, computers struggle with all kinds of things with math. Take, for example, the simple fraction: 2/3. This should be easy to store right? In most languages, it isn’t.
We’re going to use 2/3 throughout all our exam...]]></description><link>https://brettrowberry.com/clojure-ratios</link><guid isPermaLink="true">https://brettrowberry.com/clojure-ratios</guid><category><![CDATA[Clojure]]></category><category><![CDATA[ratio]]></category><category><![CDATA[binary]]></category><category><![CDATA[Math]]></category><category><![CDATA[computing]]></category><category><![CDATA[Precision]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Tue, 07 Oct 2025 04:17:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759807867158/0c9ae250-94f1-49c8-9be0-92a93790bc03.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Computers do math really quickly. Yet, computers struggle with all kinds of things with math. Take, for example, the simple fraction: 2/3. This should be easy to store right? In most languages, it isn’t.</p>
<p>We’re going to use 2/3 throughout all our examples. We’ll use the literal <code>2/3</code> instead of <code>(/ 2 3)</code> because it’s more compact, and is equivalent:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">=</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span> (/ <span class="hljs-number">2</span> <span class="hljs-number">3</span>))
<span class="hljs-comment">;;=&gt; true</span>

<span class="hljs-number">2</span>/<span class="hljs-number">3</span>
<span class="hljs-comment">;;=&gt; 2/3</span>
</code></pre>
<p>If you’ve programmed in most languages, you probably expected output like <code>0.6666667</code>. In Clojure, we need to force that with a cast:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">float</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>)
<span class="hljs-comment">;;=&gt; 0.6666667</span>
</code></pre>
<p>After casting, we can see they’re not equal:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">=</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span> (<span class="hljs-name"><span class="hljs-builtin-name">float</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>))
<span class="hljs-comment">;;=&gt; false</span>
</code></pre>
<p>So, what was that <code>2/3</code> we saw? Let’s inspect its type, and its value. I don’t want to write that more than once, so here’s a cool little helper function:</p>
<pre><code class="lang-clojure">(<span class="hljs-keyword">defn</span> <span class="hljs-title">value-and-type</span>
  [&amp; args]
  (<span class="hljs-name"><span class="hljs-builtin-name">map</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">juxt</span></span> identity type) args))
</code></pre>
<p>Here it is in action:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span> (<span class="hljs-name"><span class="hljs-builtin-name">float</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>))
<span class="hljs-comment">;;=&gt; ([2/3 clojure.lang.Ratio]</span>
<span class="hljs-comment">;;    [0.6666667 java.lang.Float])</span>
</code></pre>
<p>Aha! The <code>2/3</code> is a special Clojure <code>Ratio</code> type. What can we do with a <code>Ratio</code>?</p>
<p>Determine whether a value is one:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">ratio?</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>)
<span class="hljs-comment">;;=&gt; true</span>

(<span class="hljs-name"><span class="hljs-builtin-name">ratio?</span></span> <span class="hljs-number">3</span>/<span class="hljs-number">3</span>)
<span class="hljs-comment">;;=&gt; false</span>
</code></pre>
<p>Note that <code>rational?</code> is a little more inclusive:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">rational?</span></span> <span class="hljs-number">3</span>/<span class="hljs-number">3</span>)
<span class="hljs-comment">;;=&gt; true</span>
</code></pre>
<p>Inspect its numerator and denominator:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">numerator</span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>)
<span class="hljs-comment">;;=&gt; 2</span>

(<span class="hljs-name">denominator</span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>)
<span class="hljs-comment">;;=&gt; 3</span>
</code></pre>
<p>Do math operations without losing precision:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span>
 (<span class="hljs-name"><span class="hljs-builtin-name">*</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span> <span class="hljs-number">3</span>)
 (<span class="hljs-name"><span class="hljs-builtin-name">*</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">float</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>) <span class="hljs-number">3</span>))
<span class="hljs-comment">;;=&gt; ([2N clojure.lang.BigInt]</span>
<span class="hljs-comment">;;    [2.0000000596046448 java.lang.Double])</span>
</code></pre>
<p>That is pretty great!</p>
<p>You can attempt to turn a floating point number into a ratio. Beware!</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span>
 (<span class="hljs-name"><span class="hljs-builtin-name">rationalize</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>)
 (<span class="hljs-name"><span class="hljs-builtin-name">rationalize</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">float</span></span> <span class="hljs-number">2</span>/<span class="hljs-number">3</span>)))
<span class="hljs-comment">;;=&gt; ([2/3 clojure.lang.Ratio]</span>
<span class="hljs-comment">;;    [416666679084301/625000000000000</span>
<span class="hljs-comment">;;     clojure.lang.Ratio])</span>
</code></pre>
<p>You may have guessed the following would fare better because our computers are binary, and you’d be right:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span>
 (<span class="hljs-name"><span class="hljs-builtin-name">rationalize</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">float</span></span> <span class="hljs-number">1</span>/<span class="hljs-number">2</span>))
 (<span class="hljs-name"><span class="hljs-builtin-name">rationalize</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">float</span></span> <span class="hljs-number">3</span>/<span class="hljs-number">2</span>)))
<span class="hljs-comment">;;=&gt; ([1/2 clojure.lang.Ratio]</span>
<span class="hljs-comment">;;    [3/2 clojure.lang.Ratio])</span>
</code></pre>
<p>However, for even <code>2/3</code>, <code>BigInt</code> can save the day!</p>
<pre><code class="lang-clojure">(<span class="hljs-name">value-and-type</span>
 (<span class="hljs-name"><span class="hljs-builtin-name">rationalize</span></span> (/ <span class="hljs-number">2</span>N <span class="hljs-number">3</span>N)))
<span class="hljs-comment">;;=&gt; ([2/3 clojure.lang.Ratio])</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Repeating Digits in Clojure]]></title><description><![CDATA[My son asked me if I could make the computer double numbers, like

2 4 6 → 22 44 66

I started with a really ugly solution:
(map
 (fn [x]
   (parse-long (clojure.string/join
                ""
                [(str x) (str x)])))
 [2 4 6])
;;=> (22 4...]]></description><link>https://brettrowberry.com/repeating-digits-in-clojure</link><guid isPermaLink="true">https://brettrowberry.com/repeating-digits-in-clojure</guid><category><![CDATA[concatentation]]></category><category><![CDATA[Clojure]]></category><category><![CDATA[code golf]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Sat, 20 Sep 2025 03:48:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/gGFw3jVE31w/upload/abad06ff0b6e8748f9ff7b95a2fc45f2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>My son asked me if I could make the computer double numbers, like</p>
<blockquote>
<p>2 4 6 → 22 44 66</p>
</blockquote>
<p>I started with a really ugly solution:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">map</span></span>
 (<span class="hljs-name"><span class="hljs-builtin-name">fn</span></span> [x]
   (<span class="hljs-name">parse-long</span> (<span class="hljs-name">clojure.string/join</span>
                <span class="hljs-string">""</span>
                [(<span class="hljs-name"><span class="hljs-builtin-name">str</span></span> x) (<span class="hljs-name"><span class="hljs-builtin-name">str</span></span> x)])))
 [<span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">6</span>])
<span class="hljs-comment">;;=&gt; (22 44 66)</span>
</code></pre>
<p>I wanted to see how ChatGPT could improve my answer. Here’s what it came up with:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">map</span></span>
 #(<span class="hljs-name">parse-long</span> (<span class="hljs-name"><span class="hljs-builtin-name">format</span></span> <span class="hljs-string">"%d%d"</span> % %))
 [<span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">6</span>])
</code></pre>
<p>This is really elegant. I’ve used format strings extensively in C, C#, F#, Clojure, and a handful of other languages I don’t know very well, but I never thought about putting the same value in a format string more than once.</p>
<pre><code class="lang-clojure"><span class="hljs-comment">;; Of course</span>
(<span class="hljs-name">#</span>(<span class="hljs-name"><span class="hljs-builtin-name">format</span></span> <span class="hljs-string">"%d%d"</span> %<span class="hljs-number">1</span> %<span class="hljs-number">2</span>) <span class="hljs-number">2</span> <span class="hljs-number">2</span>)
<span class="hljs-comment">;;=&gt; "22"</span>

<span class="hljs-comment">;; Wow, never thought of it like this</span>
(<span class="hljs-name">#</span>(<span class="hljs-name"><span class="hljs-builtin-name">format</span></span> <span class="hljs-string">"%d%d"</span> %<span class="hljs-number">1</span> %<span class="hljs-number">1</span>) <span class="hljs-number">2</span>)
<span class="hljs-comment">;;=&gt; "22"</span>
</code></pre>
<p>Here’s a second solution ChatGPT came up with:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">map</span></span>
 #(<span class="hljs-name">parse-long</span> (<span class="hljs-name"><span class="hljs-builtin-name">str</span></span> % %))
 [<span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">6</span>])
</code></pre>
<p>Bravo! I felt extra silly with my <code>clojure.string.join</code> after seeing this. I forgot <code>str</code> is multi-arity with a variadic arity. I also didn’t know it had a 0-arity. Here’s the actual implementation:</p>
<pre><code class="lang-clojure">(<span class="hljs-keyword">defn</span> <span class="hljs-title">str</span>
  <span class="hljs-string">"With no args, returns the empty string. With one arg x, returns
  x.toString().  (str nil) returns the empty string. With more than
  one arg, returns the concatenation of the str values of the args."</span>
  {<span class="hljs-symbol">:tag</span> String
   <span class="hljs-symbol">:added</span> <span class="hljs-string">"1.0"</span>
   <span class="hljs-symbol">:static</span> <span class="hljs-literal">true</span>}
  (<span class="hljs-comment">^String</span> [] <span class="hljs-string">""</span>)
  (<span class="hljs-comment">^String</span> [<span class="hljs-comment">^Object</span> x]
   (<span class="hljs-name"><span class="hljs-builtin-name">if</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">nil?</span></span> x) <span class="hljs-string">""</span> (<span class="hljs-name"><span class="hljs-builtin-name">.</span></span> x (<span class="hljs-name">toString</span>))))
  (<span class="hljs-comment">^String</span> [x &amp; ys]
     ((<span class="hljs-name"><span class="hljs-builtin-name">fn</span></span> [<span class="hljs-comment">^StringBuilder</span> sb more]
          (<span class="hljs-name"><span class="hljs-builtin-name">if</span></span> more
            (<span class="hljs-name"><span class="hljs-builtin-name">recur</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">.</span></span> sb  (<span class="hljs-name">append</span> (<span class="hljs-name"><span class="hljs-builtin-name">str</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">first</span></span> more)))) (<span class="hljs-name"><span class="hljs-builtin-name">next</span></span> more))
            (<span class="hljs-name"><span class="hljs-builtin-name">str</span></span> sb)))
      (<span class="hljs-name"><span class="hljs-builtin-name">new</span></span> StringBuilder (<span class="hljs-name"><span class="hljs-builtin-name">str</span></span> x)) ys)))
</code></pre>
<p>Here’s a third solution from ChatGPT. I quite like it:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">for</span></span> [n [<span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">6</span>]]
  (<span class="hljs-name">parse-long</span> (<span class="hljs-name"><span class="hljs-builtin-name">str</span></span> n n)))
</code></pre>
<p>I almost never use <code>for</code>, but I should. It’s pretty amazing!</p>
<p>I didn’t want to be bested by the LLM, so i came up with another solution using <code>repeat</code>:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">map</span></span> #(<span class="hljs-name"><span class="hljs-builtin-name">apply</span></span> str (<span class="hljs-name"><span class="hljs-builtin-name">repeat</span></span> <span class="hljs-number">2</span> %)) [<span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">6</span>])
</code></pre>
<p>One benefit of this solution is the ability to parameterize the repetitions. For example, if I wanted to repeat the digit five times instead of twice:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [repetitions <span class="hljs-number">5</span>]
  (<span class="hljs-name"><span class="hljs-builtin-name">map</span></span>
   #(<span class="hljs-name"><span class="hljs-builtin-name">apply</span></span> str (<span class="hljs-name"><span class="hljs-builtin-name">repeat</span></span> repetitions %))
   [<span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">6</span>]))
<span class="hljs-comment">;;=&gt; ("22222" "44444" "66666")</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Sliding Windows in Clojure]]></title><description><![CDATA[I was doing a little Clojure programming and my son asked me if the computer could

make it go 1 2 3, 2 3 4, 3 4 5, …

I thought, hmm, that’s a sliding window.
Here was my first thought:
(->> (range 1 4)
     (map (fn [x] [x (inc x) (inc (inc x))])))...]]></description><link>https://brettrowberry.com/sliding-windows-in-clojure</link><guid isPermaLink="true">https://brettrowberry.com/sliding-windows-in-clojure</guid><category><![CDATA[Sliding Windows]]></category><category><![CDATA[Clojure]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Thu, 18 Sep 2025 04:08:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/UQ470wQWx4o/upload/f223d446055ff91b735374ac8dca9d9c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was doing a little Clojure programming and my son asked me if the computer could</p>
<blockquote>
<p>make it go 1 2 3, 2 3 4, 3 4 5, …</p>
</blockquote>
<p>I thought, hmm, that’s a sliding window.</p>
<p>Here was my first thought:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">-&gt;&gt;</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">range</span></span> <span class="hljs-number">1</span> <span class="hljs-number">4</span>)
     (<span class="hljs-name"><span class="hljs-builtin-name">map</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">fn</span></span> [x] [x (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> x) (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> x))])))
<span class="hljs-comment">;;=&gt; ([1 2 3] [2 3 4] [3 4 5])</span>
</code></pre>
<p>I asked if he wanted it as just one list. He asked me to show him, so I thought… I’m mapping over this and need to concatenate the lists. Wait, that’s literally <code>mapcat</code>:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">-&gt;&gt;</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">range</span></span> <span class="hljs-number">1</span> <span class="hljs-number">4</span>)
     (<span class="hljs-name"><span class="hljs-builtin-name">mapcat</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">fn</span></span> [x] [x (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> x) (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> x))])))
<span class="hljs-comment">;;=&gt; (1 2 3 2 3 4 3 4 5)</span>
</code></pre>
<p>He said he preferred the little lists to the one big one. Good thinking.</p>
<p>Then I thought, can we make it shorter? I could use <code>iterate</code> instead of the vector literal:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">-&gt;&gt;</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">range</span></span> <span class="hljs-number">1</span> <span class="hljs-number">4</span>)
     (<span class="hljs-name"><span class="hljs-builtin-name">map</span></span> #(<span class="hljs-name"><span class="hljs-builtin-name">take</span></span> <span class="hljs-number">3</span> (<span class="hljs-name"><span class="hljs-builtin-name">iterate</span></span> inc %))))
<span class="hljs-comment">;;=&gt; ((1 2 3) (2 3 4) (3 4 5))</span>
</code></pre>
<p>Looking at this, it’s really easy to parameterize:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [window-size <span class="hljs-number">3</span>
      number-of-windows <span class="hljs-number">3</span>]
  (<span class="hljs-name"><span class="hljs-builtin-name">-&gt;&gt;</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">range</span></span> <span class="hljs-number">1</span> (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> number-of-windows))
       (<span class="hljs-name"><span class="hljs-builtin-name">map</span></span> #(<span class="hljs-name"><span class="hljs-builtin-name">take</span></span> window-size (<span class="hljs-name"><span class="hljs-builtin-name">iterate</span></span> inc %)))))
<span class="hljs-comment">;;=&gt; ((1 2 3) (2 3 4) (3 4 5))</span>
</code></pre>
<p>Then I thought, the first number in a little collection forms the basis for the next little collection. I also like this way best because it starts with a literal vector <code>[1 2 3]</code>:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">-&gt;&gt;</span></span> [<span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">3</span>]
     (<span class="hljs-name"><span class="hljs-builtin-name">iterate</span></span> #(<span class="hljs-name"><span class="hljs-builtin-name">map</span></span> inc %))
     (<span class="hljs-name"><span class="hljs-builtin-name">take</span></span> <span class="hljs-number">3</span>))
<span class="hljs-comment">;;=&gt; ([1 2 3] (2 3 4) (3 4 5))</span>
</code></pre>
<p>It can be parameterized as well:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [number-of-windows <span class="hljs-number">3</span>]
  (<span class="hljs-name"><span class="hljs-builtin-name">-&gt;&gt;</span></span> [<span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">3</span>]
       (<span class="hljs-name"><span class="hljs-builtin-name">iterate</span></span> #(<span class="hljs-name"><span class="hljs-builtin-name">map</span></span> inc %))
       (<span class="hljs-name"><span class="hljs-builtin-name">take</span></span> number-of-windows)))
<span class="hljs-comment">;;=&gt; ([1 2 3] (2 3 4) (3 4 5))</span>
</code></pre>
<p>After doing all that, I realize that this isn’t a sliding window at all! In a true sliding window problem, you don’t know what the elements will be. THIS is a sliding window:</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [window-size <span class="hljs-number">3</span>
      step-size <span class="hljs-number">1</span>]
  (<span class="hljs-name"><span class="hljs-builtin-name">partition</span></span> window-size step-size (<span class="hljs-name"><span class="hljs-builtin-name">range</span></span> <span class="hljs-number">1</span> (<span class="hljs-name"><span class="hljs-builtin-name">inc</span></span> <span class="hljs-number">5</span>))))
<span class="hljs-comment">;;=&gt; ((1 2 3) (2 3 4) (3 4 5))</span>
</code></pre>
<p>In any case, Clojure is awesome for this type of work.</p>
]]></content:encoded></item><item><title><![CDATA[VS Code: Simple Browser]]></title><description><![CDATA[Updated September 16, 2025 to indicate that Flares have a singleton mode as explained by PEZ.
I just learned about Calva Flares. Then I wondered, is there something built into VS Code for viewing webpages? There is! It’s called Simple Browser and was...]]></description><link>https://brettrowberry.com/vs-code-simple-browser</link><guid isPermaLink="true">https://brettrowberry.com/vs-code-simple-browser</guid><category><![CDATA[simple-browser]]></category><category><![CDATA[calva-flares]]></category><category><![CDATA[VS Code]]></category><category><![CDATA[webview]]></category><category><![CDATA[Clojure]]></category><category><![CDATA[calva]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Fri, 12 Sep 2025 04:01:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/8pc4Z3XEBO8/upload/7f7d4ba92719784dabf3f2c08f1b2ede.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Updated September 16, 2025 to indicate that Flares have a singleton mode as explained by PEZ.</em></p>
<p>I just learned about <a target="_blank" href="https://brettrowberry.com/calva-flares?showSharer=true">Calva Flares</a>. Then I wondered, is there something built into VS Code for viewing webpages? There is! It’s called <code>Simple Browser</code> and <a target="_blank" href="https://github.com/microsoft/vscode/pull/109276">was added way back in 2021</a>!</p>
<p>For my use case of viewing the <a target="_blank" href="https://clojure.org/api/cheatsheet">Clojure Cheatsheet</a> without leaving VS Code, all I have to do is:</p>
<p>Open the <a target="_blank" href="https://code.visualstudio.com/api/ux-guidelines/command-palette">Command Palette</a> and select <code>Simple Browser: Show</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757649050892/d6cd0ee0-26f1-438e-9436-6abc7af6f8f3.png" alt class="image--center mx-auto" /></p>
<p>Type or paste in the URL</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757649066899/a8ec1345-e89d-4d37-93b4-31f204510cde.png" alt class="image--center mx-auto" /></p>
<p>And the page appears!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757649081774/ba2f4d2c-dc5b-4440-acc9-dcc9a3142847.png" alt class="image--center mx-auto" /></p>
<p>Simple Browser beats out Flares by having an address bar, back, forward, reload, and open in browser controls. But, Simple Browser is a singleton.</p>
<p>With Flares, I can open as many as I want, and I can have a singleton in the sidebar if I add the key-value pair <code>:sidebar-panel? true</code>.</p>
<p>It’s nice to have options!</p>
]]></content:encoded></item><item><title><![CDATA[Calva Flares]]></title><description><![CDATA[Updated September 16, 2025 after PEZ showed me how to use the sidebar panel.
I was playing with some Clojure code in Calva for Visual Studio Code and stumbled onto a feature. In my Primary Side Bar, I have the Calva view. I noticed the Inspector prev...]]></description><link>https://brettrowberry.com/calva-flares</link><guid isPermaLink="true">https://brettrowberry.com/calva-flares</guid><category><![CDATA[flares]]></category><category><![CDATA[VS Code]]></category><category><![CDATA[Clojure]]></category><category><![CDATA[calva]]></category><category><![CDATA[webview]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Fri, 12 Sep 2025 03:19:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/6KSbdozttrQ/upload/f5bb0e05ee927f1304926129f7f2707b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Updated September 16, 2025 after PEZ showed me how to use the sidebar panel.</em></p>
<p>I was playing with some <a target="_blank" href="https://clojure.org/">Clojure</a> code in <a target="_blank" href="https://calva.io/">Calva</a> for <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> and stumbled onto a feature. In my <a target="_blank" href="https://code.visualstudio.com/docs/configure/custom-layout#_primary-side-bar">Primary Side Bar</a>, I have the Calva view. I noticed the <code>Inspector</code> previously, but it wasn’t until now that I noticed <code>Flare</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757645884729/cfbc3589-469b-408b-a598-8c96ed4c5a9f.png" alt class="image--center mx-auto" /></p>
<p>I decided to see what it is. Here are the official docs on <a target="_blank" href="https://calva.io/flares/">Flares</a>. One of the examples shows how to display a webpage. Here’s the code snippet shown:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">tagged-literal</span> 'flare/html {<span class="hljs-symbol">:url</span> <span class="hljs-string">"https://calva.io/"</span>,
                             <span class="hljs-symbol">:title</span> <span class="hljs-string">"Calva homepage"</span>
                             <span class="hljs-symbol">:key</span> <span class="hljs-string">"example"</span>})
</code></pre>
<p>Here’s my editor before evaluating that form:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757646534431/219e3e50-81bd-41a7-a8cb-2c163fc80cb9.png" alt class="image--center mx-auto" /></p>
<p>After evaluating, a new tab is opened with the Flare:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757646519648/36733a0b-c280-45a1-9718-f6df7732ceac.png" alt class="image--center mx-auto" /></p>
<p>Now how about that <code>Flare</code> under <code>Inspector</code> in the <a target="_blank" href="https://code.visualstudio.com/docs/configure/custom-layout#_primary-side-bar">Primary Sidebar</a>? Add the key-value pair</p>
<pre><code class="lang-clojure"><span class="hljs-symbol">:sidebar-panel?</span> <span class="hljs-literal">true</span>
</code></pre>
<pre><code class="lang-clojure">(<span class="hljs-name">tagged-literal</span> 'flare/html {<span class="hljs-symbol">:url</span> <span class="hljs-string">"https://calva.io/"</span>,
                             <span class="hljs-symbol">:title</span> <span class="hljs-string">"Calva homepage"</span>
                             <span class="hljs-symbol">:key</span> <span class="hljs-string">"example"</span>
                             <span class="hljs-symbol">:sidebar-panel?</span> <span class="hljs-literal">true</span>})
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758077681801/27a29d3e-e9f6-4c23-bdf8-12ff993de913.png" alt class="image--center mx-auto" /></p>
<p>There it is, on the left!</p>
<p>This is awesome! I can open a webview in both the sidebar and in tabs so I don’t have to leave my editor.</p>
<p>Here’s an example that I find helpful:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">tagged-literal</span> 'flare/html {<span class="hljs-symbol">:url</span> <span class="hljs-string">"https://clojure.org/api/cheatsheet"</span>,
                             <span class="hljs-symbol">:title</span> <span class="hljs-string">"Cheatsheet"</span>
                             <span class="hljs-symbol">:key</span> <span class="hljs-string">"cheatsheet"</span>})
</code></pre>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Sales Promises]]></title><description><![CDATA[Imagine you’re a salesperson for a boutique car manufacturer and you’re having a sales conversation with a new, important customer:
Customer: Thanks for seeing me. I’m really looking forward to one of your custom cars!Salesperson: Absolutely. You can...]]></description><link>https://brettrowberry.com/sales-promises</link><guid isPermaLink="true">https://brettrowberry.com/sales-promises</guid><category><![CDATA[sales]]></category><category><![CDATA[engineering]]></category><category><![CDATA[Estimation]]></category><category><![CDATA[negotiations]]></category><category><![CDATA[product]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Fri, 01 Aug 2025 21:37:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/vWchRczcQwM/upload/fb9b80f41ff5451803d22735df257429.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine you’re a salesperson for a boutique car manufacturer and you’re having a sales conversation with a new, important customer:</p>
<p><strong>Customer</strong>: Thanks for seeing me. I’m really looking forward to one of your custom cars!<br /><strong>Salesperson</strong>: Absolutely. You can choose a 2-door or 4-door. It will be ready from the factory in 2 months.<br /><strong>Customer</strong>: Actually, I'd like a 6-door.</p>
<p>Let’s sketch out two possible responses:</p>
<ul>
<li><p>promise anything</p>
</li>
<li><p>promise what you can</p>
</li>
</ul>
<h2 id="heading-promise-everything">Promise Everything</h2>
<p><strong>Salesperson</strong>: Absolutely!<br /><strong>Customer</strong>: Great, when can I have it?<br /><strong>Salesperson</strong>: Our 2-door and 4-door cars have a lead time of 2 months. I’m sure we can do the same for a 6-door!</p>
<h2 id="heading-promise-what-you-can">Promise What You Can</h2>
<p><strong>Salesperson</strong>: This relationship is important to us, and your business is important to us. While we do offer a high level of customization, we’ve never offered a 6-door, so I can't say with certainty how long that would take. I can check with my team. I expect it would double the timeline. Alternatively, we could deliver you a 2-door and/or a 4-door in 2 months to meet your immediate needs. If the 6-door remains important, we could revisit that after delivery.<br /><strong>Customer</strong>: I chose you because I heard you offer more customization than your competitors.<br /><strong>Salesperson</strong>: We do. I also want you to understand the tradeoffs involved with this request: a 2-door and/or 4-door in 2 months, or a 6-door with a longer, less certain timeline.<br /><strong>Customer</strong>: I need a car in 3 months. I’ll take a 4-door and keep in touch.</p>
<h2 id="heading-closing">Closing</h2>
<p>I don’t work in sales, so can you really trust my advice? I can’t say. What I can say is that the promise everything route may lead to disappointed customers and will lead to unhappy people at your company.</p>
<p>Is this scenario too simplistic to be useful? Even if it is, there are some lessons you can apply:</p>
<ol>
<li><p>Know what you can reliably deliver in a given timeframe.</p>
</li>
<li><p>Know which changes to your offerings will make a timeframe uncertain.</p>
</li>
<li><p>Don’t estimate on behalf of others doing the work.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Understanding Stacks]]></title><description><![CDATA[In computer science, a stack is what you think it is. A pile. There are two important restrictions:

Only add to the top

Only remove from the top


To illustrate, let’s track how we get dressed using a stack. At first, the stack is empty. Let’s add ...]]></description><link>https://brettrowberry.com/understanding-stacks</link><guid isPermaLink="true">https://brettrowberry.com/understanding-stacks</guid><category><![CDATA[stack]]></category><category><![CDATA[Computer Science]]></category><category><![CDATA[data structure]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Sat, 26 Jul 2025 05:43:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/FO7bKvgETgQ/upload/6c2901576117d3b97a0df55a78ed1a30.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In computer science, a stack is what you think it is. A pile. There are two important restrictions:</p>
<ol>
<li><p>Only add to the top</p>
</li>
<li><p>Only remove from the top</p>
</li>
</ol>
<p>To illustrate, let’s track how we get dressed using a stack. At first, the stack is empty. Let’s add a <code>shirt</code>, a <code>sweater</code>, and a <code>coat</code>. Our stack now looks like this:</p>
<pre><code class="lang-mermaid">flowchart TD
coat ~~~ sweater ~~~ shirt
</code></pre>
<p>Now, we want to go swimming. In real life, and in a stack, we can’t remove the <code>shirt</code> first since the <code>sweater</code> and <code>coat</code> are in the way. The stack we built tells us the order in which to remove the clothes: <code>coat</code>, <code>sweater</code>, <code>shirt</code>.</p>
<p>The only thing we can access is the last thing we put in. Therefore, we say that a stack is last-in, first-out (LIFO). We could also call it first-in, last-out (FILO), but nobody says that.</p>
<p>You can read more at <a target="_blank" href="https://www.geeksforgeeks.org/dsa/applications-advantages-and-disadvantages-of-stack/">https://www.geeksforgeeks.org/dsa/applications-advantages-and-disadvantages-of-stack/</a>.</p>
]]></content:encoded></item><item><title><![CDATA[The Assignment Meeting Squeeze]]></title><description><![CDATA[Say you want someone to do a task for you: fill out a questionnaire, sign off on a document, etc. You can ask them, and they may get around to it.
Try this next time. Tell them what you need and set up a fallback meeting far enough in the future that...]]></description><link>https://brettrowberry.com/the-assignment-meeting-squeeze</link><guid isPermaLink="true">https://brettrowberry.com/the-assignment-meeting-squeeze</guid><category><![CDATA[power-move]]></category><category><![CDATA[task]]></category><category><![CDATA[assignment]]></category><category><![CDATA[meetings]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Fri, 25 Apr 2025 01:46:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/smgTvepind4/upload/bda969feee950d6ea6490cbf3d8166fa.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Say you want someone to do a task for you: fill out a questionnaire, sign off on a document, etc. You can ask them, and they may get around to it.</p>
<p>Try this next time. Tell them what you need and set up a fallback meeting far enough in the future that they can reasonably complete the task. They may start working on it right away! If not, you’ll solve it in the meeting. Win-win.</p>
<p>It’s a real “power move”, like the one below. I am not the Brett from the video.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=ilSkmPPax6c">https://www.youtube.com/watch?v=ilSkmPPax6c</a></div>
]]></content:encoded></item><item><title><![CDATA[Date for a Date]]></title><description><![CDATA[Imagine you’re at work and someone asks you when a new project will be done. Perhaps it’s a request for an on the spot estimate. Further, imagine you have little to no idea.
I’d like to introduce you to a concept that I thought was entirely ridiculou...]]></description><link>https://brettrowberry.com/date-for-a-date</link><guid isPermaLink="true">https://brettrowberry.com/date-for-a-date</guid><category><![CDATA[due-date]]></category><category><![CDATA[date-for-date]]></category><category><![CDATA[d4d]]></category><category><![CDATA[manage-expectations]]></category><category><![CDATA[date]]></category><category><![CDATA[deadlines]]></category><category><![CDATA[deadline]]></category><dc:creator><![CDATA[Brett Rowberry]]></dc:creator><pubDate>Thu, 24 Apr 2025 01:35:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/GjAKNK4ocRc/upload/d56685e1e024aa2d97e73bd35de70131.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine you’re at work and someone asks you when a new project will be done. Perhaps it’s a request for an on the spot estimate. Further, imagine you have little to no idea.</p>
<p>I’d like to introduce you to a concept that I thought was entirely ridiculous but have since embraced: a date for a date.</p>
<p>A date for a date (D4D for short) is a date on which you’ll have an answer. You many not know how long a project will take, but you can probably say how long it will take you to come up with an estimate, and, consequently, a date. So, if today is April 23rd and you’re asked when a project will complete, instead of saying “I don’t know”, say, “I’ll get you a date on April 30th”.</p>
<p>Did I invent this term? No. I picked it up at work, and it’s <a target="_blank" href="https://ell.stackexchange.com/a/46136">fairly common in industry</a>.</p>
]]></content:encoded></item></channel></rss>