Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. Human brain is two separate organs, Stanford Medicine-led research finds(stanford.edu ↗)
    67comments
  2. If math is more than proof, we need to better celebrate the rest of it(terrytao.wordpress.com ↗)
    33comments
  3. GPT-6 Astra Solves a WWI German Radio Cipher(prinzai.com ↗)
    42comments
  4. San Francisco Onion Futures Company(onionfutures.com ↗)
    62comments
  5. Android 17 is the first since 3.x to add new APIs without releasing to the AOSP(grapheneos.social ↗)
    402comments
  6. Typesafe-computer-use drives a Mac toward a goal for 1/50th of a cent per step(github.com/awlevin ↗)
    43comments
  7. Apple M6 Pro Achieves the Highest Single-Core CPU Score in Geekbench 7(geekbench.com ↗)
    13comments
  8. SDCC – Small Device C Compiler(sourceforge.net ↗)
    17comments
  9. Cloudflare Quick Tunnels(cloudflare.com ↗)
    277comments
  10. Science Is Open Software(jepedersen.dk ↗)
    34comments
  11. You can run Git on object storage if you re-make packfiles(tigrisdata.com ↗)
    12comments
  12. How to Write with an LLM(sockpuppet.org ↗)
    323comments
  13. Saving another 100TB of RAM(cloudflare.com ↗)
    69comments
  14. Why building a Rust LSP is hard(rust-glancer.github.io ↗)
    30comments
  15. Ctenophores: Wonders of Biology(quantamagazine.org ↗)
    5comments
  16. NASA-IBM Lunar Foundation open-Source Geospatial AI Model(usra.edu ↗)
    2comments
  17. How OpenAI Used Its Own LLMs to Design Its Jalapeño Chip(ieee.org ↗)
    84comments
  18. The first new cat species discovered in 100 years(nationalgeographic.com ↗)
    103comments
  19. Goroutine Leak Profiles(go.dev ↗)
    2comments
  20. OpenJev(openjev.com ↗)
    262comments
  21. Show HN: Cactus Needle 3: 8-29MB automation models can match DeepSeek V4 Flash(cactuscompute.com ↗)
    88comments
  22. Photon-Emission-Guided Laser Fault Injection Enables RP2350 Secure Debug(ledger.com ↗)
    69comments
  23. Minimal Phone 2(minimalcompany.com ↗)
    220comments
  24. Veronese's Dogs(publicdomainreview.org ↗)
    discuss
  25. Cache-to-Cache: Direct Semantic Communication Between LLMs (2025)(arxiv.org ↗)
    12comments
  26. Suppress vulnerabilities applying Kubernetes context to scans(github.com/alegrey91 ↗)
    1comments
  27. Warez: The Infrastructure and Aesthetics of Piracy (2021)(archive.org ↗)
    58comments
  28. Inside ZCode: Silently uploading your Git history to the cloud(ferstar.org ↗)
    98comments
  29. Cyclomatic Complexity in C#(ndepend.com ↗)
    19comments
  30. Stepfun Step 5 Preview (LLM): On AA Pareto frontier(artificialanalysis.ai ↗)
    2comments

The Story of Mel Explained

68 pointsby 11y agojamesseibel.com
25 comments
11y agoHN ↗

Those were the days, when self-modifying code was inevitable.

You should think that self-modifying code has died out by today, but far from it. Each time you open a web site, you could watch this old trick at work. How often do you `document.write` on a web site? To put it without diplomacy, our webware today is at the level of programming an IBM 650 with magnetic drum memory, where self-modifying code is practically mandatory. And Mel is nowhere to be found.

11y agoHN ↗

By and large we know better than to output javascript with document.write. We have structured templating languages even for use in a web page. Not everyone uses them yet, but the better technologies do exist.

11y agoHN ↗

I wish! Using document.write to inject script tags is the most reliable way to insert code to run before another script tag. Here's an example where we might load some scripts then run some code before finally calling some main function.

  <script>
    // Load optimized or debug code.
    if (debugMode) {
      document.write('<script src="build-debug.js"></script>');
    } else {
      document.write('<script src="build-opt.js"></script>');
    }

    // Enable some runtime debug flags.
    if (enableTracing) {
      // This runs *after* loading the script above and
      // before main() is called below.
      document.write('<script>ENABLE_TRACING = true;</script>');
    }
  </script>
  <script>
    // This runs *after* the script tags injected in the section above.
    main();
  </script>
11y agoHN ↗

document.write isn't self modifying code - it's self-generating code at best.

What Mel was doing is the equivalent of document.edit.

11y agoHN ↗

This is a great link. I read this story a while ago, but missed a lot of meaning behind it. This explanation hits the spot explaining all of that.

11y agoHN ↗

The Story of Mel is a story about a ‘Real Programmer’ that came out in the early 1980′s on Usenet

I read this as a story of "coming out" on Usenet... thought it was going to be about sexual/gender identity or something.

11y agoHN ↗

Woz also coded the first Apple I in binary as he had no assembler. Of course the 6502 was a beautifully simple design with a minimal set of opcodes.

Mel's story is nuts but from the perspective of today (or even when I started in 1981) but you have to start somewhere and you can't judge what people did in the early days except in the context of the times.

11y agoHN ↗

Didn't the story go that Paul Allen wrote a loader for Altair Basic this way on pen and paper on an airplane?

11y agoHN ↗

I read this interesting story once before and still don't understand why the author insists on typecasting Mel as a "Real Programmer".

It sounds to me like he should have been writing optimizing assemblers instead of wasting his talents doing one-off blackjack programs.

Additionally, Real Programmers write comprehensible code.

11y agoHN ↗

That is the point - the term 'Real Programmer' is meaningless and is merely used to disparage languages / tools / platforms and boost egos. You can look at Mel, a 'Real Programmer', and realize that you can't make value judgements of what true programming is. Programming is using logic to solve problems, regardless of the tools and language.

11y agoHN ↗

In that context, "Real Programmer" means something like "someone who understands every minute detail about every part of the systems he's programming to the point that they can keep track of every variable, every system state, and every operation to make it do whatever they want". It's not about programming style or finesse. It's about raw mastery of the system to deeper levels than those not called "real programmers" could fathom.

11y agoHN ↗

From the Jargon File: http://www.catb.org/jargon/html/R/Real-Programmer.html

"Real Programmer" is derived from the name of Real Programmers Don't Use Pascal [0], which describes "Real Programmers" as being those who use FORTRAN or assembly or something similarly painful to write software in versus someone who used high-level languages. Nowadays it's generally understood to mean anyone who writes code either directly on "bare metal" or very close to it despite the use of higher-level tools; nowadays, the term's used more-or-less ironically (since modern compilers have gotten much better about proper optimizations), but Mel Kaye - the "Mel" of "The Story of Mel" - was (is?) the archetypal definition of a true "Real Programmer".

The term "Real Programmer" predates "The Story of Mel" by about a year; "The Story of Mel" was written as a direct response to "Real Programmers Don't Use Pascal" (namely, its claim that "Real Programmers write in FORTRAN"). Mel makes FORTRAN programmers look like quiche-eating Pascal programmers in comparison.

[0]: https://en.wikipedia.org/wiki/Real_Programmers_Don%27t_Use_P...

11y agoHN ↗

Was the difference in speed between Mel's super-optimized blackjack program and a less optimized equivalent actually noticeable to the user? Or was this level of optimization crazy even back then?

11y agoHN ↗

The machine's main memory was a physically rotating drum. If you think of how slow that must have been, odds are very good that his optimizations made a noticeable difference.

11y agoHN ↗

3600 rpm, with 64 words per track, so reading a word took 260 µs. Minimum cycle time (the address is up next) was 9 × 260 µs = 2.34 ms. Worst case then (just missed it) was (9 + 63) × 260 = 18.75 ms.

11y agoHN ↗

Something I've long been curious about:

    Mel finally gave in and wrote the code,
    but he got the test backwards,
    and, when the sense switch was turned on,
    the program would cheat, winning every time.

This doesn't sound like the sort of bug that occurs because you get a test backwards. Making a blackjack program that wins every time, and one that loses every time, seem like very different beasts. So what mistake did Mel make?

11y agoHN ↗

I always understood it as intentional on Mel's part.

11y agoHN ↗

It seems pretty identical to me. In Blackjack, the easiest way to make someone win is to give them 21, and make sure no one else gets 21.

So if the pseudocode is something like:

    if cheat_switch:
        if active_player == "COMPUTER": #this should be "HUMAN"
            make_current_player_get_21()
        else:
            make_current_player_get_20_or_busts()

Then the computer will always get 21, and the human player will get 20. Assume for the moment that it deals with dealing multiple cards for both the human and computer; this can be done, but isn't worth getting into.

And this could all be switched in the `active_player` check.

11y agoHN ↗

The manual for the game says:

  If SENSE SWITCH 32 is depressed, there is a better than normal chance
  of an ace being dealt as the player's first card.

Presumably the story didn't get that quite right. Sadly the code hasn't turned up.

11y agoHN ↗

Along the same lines as some of the other responses, it's possible that the "test" in question was testing whether the affected player was the human or the computer; getting that particular test backwards would certainly have the described effect.

11y agoHN ↗

To summarize, Mel enabled the index register bit (despite not using the index register) to cause an integer overflow, and because the instruction was at the very top of memory, it had the side-effect of also incrementing the instruction’s opcode, modifying the instruction to change into a JUMP command, in order to exit an infinite loop.

Reading this made me thing of some of the crazy tricks I've pulled in TIS-100. And while it worked well in a game, it would be a nightmare for that to be my day job.

11y agoHN ↗

I am finding the explanation distracts from the prose of the original and is a jarring contrast. Perhaps this would be better as footnotes.