Tom Moertel
blog.moertel.com · Personal blog · on HN since 2007
Tom Moertel writes about programming techniques, including functional programming, recursion-to-iteration, type-based design, Git tricks, and old game hacks.
What HN saysHN returns to it often for the Atari 2600 game-programming hack, which commenters call ingenious, and for older web-safety posts like Google Web Accelerator and unsafe links.
63HN people shared it
28linked it in comments
52stories submitted
2.0Kstory points
3 months agolast shared
2007people per year2026
Most-shared posts
- 1A Great Old-Timey Game-Programming Hack11 people · 1.1K points · first shared 2013 · 143 comments on HN
- 2A type-based solution to the “strings problem” (2006)8 people · 1 points · first shared 2013 · discussion on HN
- 3A type-based solution to the "strings problem"6 people · 7 points · first shared 2007 · 1 comments on HN
- 4Never store passwords in a database6 people · first shared 2009
- 5The second-order-diff Git trick5 people · 184 points · first shared 2013 · 41 comments on HN
- 6Coders guide to good coffee4 people · 198 points · first shared 2007 · 96 comments on HN
- 7Recursion to Iteration, Part 4: The Trampoline (2013)4 people · 122 points · first shared 2013 · 17 comments on HN
- 8Tricks of the trade: Recursion to Iteration4 people · 4 points · first shared 2013 · 1 comments on HN
- 9A coder’s guide to coffee (2002)3 people · 53 points · first shared 2013 · 62 comments on HN
- 10Wondrous oddities: R's function-call semantics (2006)3 people · 3 points · first shared 2020 · 1 comments on HN
- 11Sampling with SQL2 people · 178 points · first shared 2024 · 43 comments on HN
- 12How to change symlinks atomically (2005)2 people · 70 points · first shared 2016 · 63 comments on HN
- 13Wondrous Oddities: R's function call semantics [2006]2 people · 29 points · first shared 2007 · 4 comments on HN
- 14On the Nature and Purpose of Code2 people · 2 points · first shared 2026 · discussion on HN
- 15Homepage2 people · first shared 2017
What HN people wrote when they linked it
sillysaurusx · 2026-04-16
Beautiful. I don't suppose you have public, detailed installation steps for how to go from "nothing exists" to "Pandoc can push posts to https://blog.moertel.com/"? :)
The best I was able to do was http://github.com/shawwn/wiki, which has been broken since 2020. You can't spell Haskell without Hell.
If you wouldn't mind pulling up a `claude` in your repo and running `/init` and showing the result, that'd give me at least a vague idea of what to do.
tmoertel · 2026-08-14
> Please, no. Don't blog about things you don't understand yet.
Do you really mean this? Or do you mean "When you blog, be honest. Don't pretend to understand things you don't."?
Blogging about things you are learning about, especially if you invite feedback, is a great way to learn and to build a shared understanding within a larger community.
But I agree 100% on the fake-it-till-you-make-it posts on blogs and LinkedIn. That stuff is a blight on the web.
ADDED a concrete example: Consider this post: https://blog.moertel.com/posts/2026-07-23-on-the-nature-and-purpose-of… Do you think that posts like this are useful? Or net harmful?
EvanAnderson · 2020-12-15
That stack trick is ingenious. I've done next to no 2600 programming but I've done enough 6502 to appreciate that one.
I am remound of the perennial HN favorite: http://blog.moertel.com/posts/2013-12-14-great-old-timey-game-programm…
JimDabell · 2020-09-15
It was a recurring problem in the Rails world because the reaction from DHH was to tell people the preloaders were "evil" instead of telling people to follow the HTTP specification.
http://blog.moertel.com/posts/2005-10-25-google-web-accelerator-vs-uns…
barbs · 2016-11-15
If you haven't read this already, you might enjoy this article: A Great Old-Timey Game-Programming Hack:
http://blog.moertel.com/posts/2013-12-14-great-old-timey-game-programm…
holman · 2014-04-13
As mentioned, these are cribbed from my Git & GitHub Secrets talk: http://zachholman.com/talk/git-github-secrets/
If you're interested in the arcane side of Git and GitHub, you might also be interested in the follow-up talk I've given a few times the last half-year or so, which details a bunch of other new things: http://zachholman.com/talk/more-git-and-github-secrets/
I'm more of a fan of the second talk, myself. My favorite thing I discovered while making the second talk was the "second-order-diff Git trick", which Tom Moertel came up with here: http://blog.moertel.com/posts/2013-02-18-git-second-order-diff.html
al2o3cr · 2013-12-30
This sort of "bending" of opcodes designed to make saving registers on the stack easier (MOVEM was a common part of most 68k functions' preamble) seems like it was a favorite trick:
http://blog.moertel.com/posts/2013-12-14-great-old-timey-game-programm…
(above ran on HN a couple weeks back)
zem · 2013-01-21
http://blog.moertel.com/articles/2006/10/18/a-type-based-solution-to-t… is a very good read on the subject. basically, the compiler can have different types of strings, depending on where they come from, and how they are created. it can then make sure that different types of strings are never mixed without an explicit conversion operation. it is up to the programmer, of course, to see to it that that conversion operation involves sanitising, but the compiler will make sure you don't do
string a = get_input_from_user();
string b = sql_lookup(database, a);
insert_into_output_html(b);
requiring instead
UserInputString a = get_input_from_user();
SQLResultString b = sql_lookup(database, ConvertUserInputToSQLQueryInput(a))
insert_into_output_html(ConvertSQLResultToHtml(b));
chriswarbo · 2021-08-05
> > It's possible to implement anything correctly with dynamic types but the point is static typing makes it easier to do so
> This is where the argument became circular and we can basically stop.
I think any appeal to "easier" is inherently subjective. I've certainly tried to avoid making any such claims. Instead, I've mostly tried to argue that static types can forbid certain programs from ever running, and we can use that to forbid things like vulnerable SQL queries.
> > It's possible to implement anything correctly with dynamic types
> but apparently chriswarbo does not.
I never said any such thing; besides which, it's trivially the case that anything implemented with static types could also be implemented with dynamic types, since static types only exist at compile time (they are "erased" during compilation), and hence every running program is dynamically typed.
In fact, I don't think I've said anything about correct implementations at all. My point is that static types can forbid incorrect implementations. When it comes to security, that is much more important; i.e. I would much rather bang my head against a screen filled with compiler errors, than expose some insecure program to the harsh reality of the Internet.
> The parent claim (by chriswarbo) was that, for example, SQL injection attacks were, in fact, incontrovertible proof that SQL injection attacks "are classic type errors".
I've not claimed that (in fact, I'm stuggling to parse what that sentence might…
thethirdone · 2017-03-09
http://blog.moertel.com/ does a decent job of explaining some practical aspects for de-recursivying, but I'll give you a basic explanation of that plus a more theoretical answer showing that any computatble function can be written using only while loops and a stack.
Practical:
If we right all of are programs and tail-recursive (returning a recursive call or constant at the end of the prgram) programs they are easy to transform into simple while loops with no stack. The idea is instead of calling another function just restart the current one with the updated arguments.
EX:
f(n,x)=f(n-1,x+1)
f(0,x)=x
goes to
while(n > 0){
n--;
x++
}
Other techniques such as trampolining and continuation passing style also help translate recursive functions into iterative ones.
Theorectical:
Think about Brainfuck or Turing machines, these computing frameworks can compute any computable function using only what amounts to while loops and infinite memory.
Given then that we can produce arbitrary control flow using only while loops, we can reproduce how recursive calls are computed in computers with stack frames (provided by our stack).
nandemo · 2012-08-20
I follow the guidelines quoted below. I use an old electric kettle: not very fancy, you just plug it in and it boils the water. There's no temperature control settings, but there's no need: the water comes out about 92C, which is just right. Note that 175F=80C is not hot enough, it's "supposed" to be over 90C. But try it for yourself a couple of times and see if you can tell the difference.
I use a plastic pour-over filter and a manual burr grinder by Kyocera, which costs around U$25. I use coffee ground in the same day or in the previous day. In my experience this is what makes the biggest difference.
I usually buy beans at an import shop that has good turnout, so I know the beans are fresh. But last time I ended up buying at Starbucks and it was... awesome. Really.
If you follow these three guidelines and do nothing
more, you will enjoy coffee better than you can find
in most specialty coffee shops:
1. Buy only whole-bean coffee roasted within the last
few days.
2. Grind it fresh, just before brewing.
3. Brew it in a French press or a pour-over filter using
fresh water, off the boil.
http://blog.moertel.com/pages/coders-guide-to-coffee
fhoxh · 2011-06-22
It is one of your primary duties to safeguard the best interest of your organization. Incontrovertibly, the best interest is not served by storing passwords in plaintext as this can result in grave harm to your organization.
Accordingly, while I would not share any details with the outside world, I would advise you to strongly push the issue internally, from the position of an educator.
Here are four articles that may assist you in composing a stronger series of arguments:
https://www.owasp.org/index.php/Broken_Authentication_and_Session_Mana…
http://cwe.mitre.org/data/definitions/256.html
http://blog.moertel.com/articles/2006/12/15/never-store-passwords-in-a…
http://marknelson.us/2011/02/06/gawker-considered-stupid-criminally-st…
You will want to further notate that the effort of implementing non-plaintext authentication really isn't terribly significant.
What troubles me is this "most senior" programmer of yours. If storing passwords in plaintext is OK with him/her, meaning that he/she has a weak background in security engineering, I can't imagine that there aren't many additional severe security issues (SQL injection, XSS, CSRF, etc...). Most concerning of all though is that this "most senior" programmer seems disinterested in due diligence and is instead actively arguing against widely known best practices.
If, after your strong push, management still is not motivated, personally, I would resign. I would not want to be professionally affiliated…
Avshalom · 2024-03-21
For those who haven't run into anything about this corner of R before:
https://blog.moertel.com/posts/2006-01-20-wondrous-oddities-rs-functio…
davidthewatson · 2023-02-24
Your comment resonates with me being a fan of subtractive methods.
I shared an office with the nice, modern gentleman who wrote this:
https://blog.moertel.com/posts/2002-04-25-coders-guide-to-coffee.html
Another of my office mates was a barista. To me, this is like reading, "Shop class is soul craft" because coffee is definitely art in the hands of an experienced aficionado.
After a decade of personal experiments with coffee devices you'd recognize, I've settled on a cheap and simple Mr. Coffee burr grinder and Bodum pour-over. I don't pre-soak my filter, just grind-and-go with a Sumatra bean from Fresh Thyme.
My experience has been that coffee is phenomenological to the point that it seems to resist attempts at empiricism, similar to audiophile pursuits; like software, it's prone to Heisenbugs!
b3morales · 2021-08-21
Further reading about the relationship between recursion, iteration, and accumulators: https://blog.moertel.com/posts/2013-05-11-recursive-to-iterative.html
This transformation is one you can apply in your own source as well. An example from that link, the recursive
def factorial(n):
if n < 2:
return 1
return n * factorial(n - 1)
can be rewritten iteratively:
def factorial1d(n, acc=1):
while n > 1:
(n, acc) = (n - 1, acc * n)
return acc
lil1729 · 2016-08-22
http://www.weirdnet.nl/apple/rename.html
Yes, I know it is fixed. But who knows what one runs into!
And this: http://blog.moertel.com/posts/2005-08-22-how-to-change-symlinks-atomic…
gnuvince · 2013-07-01
> What is the type system providing you in that scenario?
Though the data flowing in and out of a web application is usually in string form, that doesn't mean that it needs to be treated as such in your application. You'll convert the string to a richer, more specific datatype and the static type system will help you correctly manipulate the data.
A nice blog post on the subject is [1] where the author explains how you can represent different kinds of strings (raw strings, SQL strings, etc.) using the type system.
[1] http://blog.moertel.com/posts/2006-10-18-a-type-based-solution-to-the-…
peter-fogg · 2013-05-25
This reminds me quite a bit of this article: http://blog.moertel.com/posts/2006-10-18-a-type-based-solution-to-the-… although Haskell's type system is likely much better for expressing this sort of constraint.
anonymouz · 2013-04-27
There are some things you can enforce with a type system that you cannot practically implement with unit tests.
For example in [1] it is described how a type system can be used to help you keep track which kind of string contains what data (SQL, XML, user input...) to catch problems with injection attacks at compile time.
[1] http://blog.moertel.com/posts/2006-10-18-a-type-based-solution-to-the-…
tel · 2013-04-14
To bring this into sharper detail, notice that there's the "OverloadedStrings" compiler directive at the top of the file. That means that "hello " and "!" are of type Html, different from String. Strings can only be concatenated with Html after they've been escaped.
For more elaboration, see http://blog.moertel.com/posts/2006-10-18-a-type-based-solution-to-the-…
JadeNB · 2011-08-24
> Not that I've tried this approach myself, but I'd be curious to hear from anyone who has.
Tom Moertel (http://blog.moertel.com/articles/2006/10/18/a-type-based-solution-to-t… has.
gwern · 2011-08-22
For those curious, the way one would do this in a language with a better type system (or objects) would be some sort of opaque object/type which you can't peer into, and which provides a function/method to extract the String within and which also sanitizes it along the way.
So for Java, you might have a class with the String stored as a private variable and the obvious getter/setter methods. In Haskell, you'd have a newtype with similar functions. (Can this be done in C? I don't know.)
A close approximation to Joel's example (string sanitation) in Haskell with newtypes: http://blog.moertel.com/articles/2006/10/18/a-type-based-solution-to-t…
temptemptemp13 · 2011-04-06
The passwords can be stolen and then you royally screwed your users who trusted you.
http://blog.moertel.com/articles/2006/12/15/never-store-passwords-in-a…
http://stackoverflow.com/questions/287517/encrypting-hashing-plain-tex…
http://www.usenix.org/publications/login/2001-11/pdfs/singer.pdf
chaosmachine · 2009-11-26
eru · 2009-07-08
run4yourlives · 2009-05-27
For reference I give you: Reddit and their password losing debacle. (http://blog.moertel.com/articles/2006/12/15/never-store-passwords-in-a…
paganel · 2011-08-30
> Sorry, but this is bull. If you take any information, even if it's an email and password, data security is either tops on your list or you're abusing your users (even "only a hundred"; one is too many!). There is literally zero middle ground on this: you do it or you shouldn't be building web applications
http://blog.moertel.com/articles/2006/12/15/never-store-passwords-in-a…
Needless to say, almost 5 years have passed and they're still around :) their traffic probably a couple of orders of magnitude higher. I was there when it happened, and yes, probably some Russian hacker or whatnot has my password from there, but that's not such a big deal because reddit doesn't know my name, doesn't have my CC number or any details related to my life.
Now, were this to happen to a company that has a lot more information available about each and every one of us stored in one central place (think Google or FB), then things could get really nasty. And I'm not talking about stupid mistakes like the one from above, I'm talking about MITM attacks orchestrated by (vicious) Governments, or cyber-warfare, or just plain old NSA not having to bother to collect information from a myriad of places anymore, when they can just go directly to the source.
jonny_noog · 2010-09-29
That would be right assuming passwords were always encrypted - and we know that unfortunately even some of the biggest sites have been bitten by not encrypting passwords in their database[1] - but that's not actually the case I was thinking of when I said "brute forced".
Here's one possible scenario: let's say that I happened to be a member of a website that unfortunately allows an attacker to hit their login form as many times as they like and as fast as they like with various username/password combinations, and by brute forcing this login page in this way, they manage to determine what my username/password actually is. Now the attacker does know my username/password for one website I belong to and - if they're smart and determined - it may occur to them that now they know one of my usernames/passwords they might use these details as a starting point in trying to brute force other accounts that I may have on other websites.
I used to run these kinds of brute force attacks against websites back in the day when I had nothing better to do and before I had to work for a living. Often I was quite successful, but I wasn't targeting specific users and even back then I could tell that websites were getting more savvy in terms of detecting and defeating such attacks. So no doubt it would be harder to pull this kind of thing off now and it would probably depend a lot on which website(s) you targeted. But surely it wouldn't be impossible.
[1]…