HNHacker News
TopNewBestAskShowJobs

thomasmg

654 karma · joined June 19, 2018

Original author of Hypersonic SQL and H2 database (Java relational databases): h2database.com
submissionscomments
thomasmg··on War on Raze
> more overloaded than Perl by someone who maybe isn't so great at clear communications.

I have the same feeling. The root of K is APL, but to avoid special characters (I assume), the same symbol has multiple meanings (overloaded), depending on eg. the position, the data type, and the context. The idea is that "programs should be short enough to fit in your head." The challenge is, similar to Perl and Regex syntax, it's very hard and often cryptic to read.

I do think a concise syntax is useful, for a programming language. But at the same time, the syntax should be readable, and that probably means that each symbol or operator must only have one meaning, and that meaning should be (more or less) obvious.

K is an array language. Even an integer is actually an array of one element. I think that makes sense for a tiny language: This is the simplest possible type system. You can even support strings, when using eg. metadata or using a heuristic like "a string is always zero terminated" (which is what I used for my tiny language).

thomasmg··on Axios compromised on NPM – Malicious versions drop remote access trojan
The point is that you don't need the very latest version. The 20 years old version is enough.
thomasmg··on My “grand vision” for Rust
The syntax in Kotin is: "val name: String? = getName(); if (name != null) { println(name.length) // safe: compiler knows it's not null }" So, there is no explicit type conversion needed.

I'm arguing for integer / and %, there is no need for an explicit "non-zero integer" type: the divisor is just an integer, and the compiler need to have a prove that the value is not zero. For places where panic is fine, there could be a method that explicitly panics in case of zero.

I agree an annotation / effect system would be useful, where you can mark sections of the code "panic-free" or "safe" in some sense. But "safe" has many flavors: array-out-of-bounds, division by zero, stack overflow, out-of-memory, endless loop. Ada SPARK allows to prove absence of runtime errors using "pragma annotate". Also Dafny, Lean have similar features (in Lean you can give a prove).

> I think it's fine for division to be exposed as a panicking operation by default

That might be true. I think division (by non-constants) is not very common, but it would be good to analyze this in more detail, maybe by analyzing a large codebase... Division by zero does cause issues sometimes, and so the question is, how much of a problem is it if you disallow unchecked division, versus the problems if you don't check.

thomasmg··on My “grand vision” for Rust
Thanks a lot! I wasn't aware of Gleam, it really seems simple. I probably wouldn't say "learn in a day", any I'm not sure if it's simpler than Python, but it's statically typed, and this adds some complexity necessarily.
thomasmg··on I built a programming language using Claude Code
I would be very interested in this research... I'm trying to write a language that is simple and concise like Python, but fast and statically typed. My gutfeeling is that more concise than Python (J, K, or some code golfing language) is bad for readability, but so is the verbosity of Rust, Zig, Java.
thomasmg··on My “grand vision” for Rust
Well, the parent wrote "I honestly just don't believe that Rust is more complex to onboard to compared to languages like Python." And you wrote "The language itself is not more complex to onboard." So... to contract Rust with Scala, I think it's clearer to write "The language itself is not more complex to onboard _than Scala_."

To that, I completely agree! Scala is one of the most complex languages, similar to C++. In terms of complexity (roughly the number of features) / hardness to onboard, I would have the following list (hardest to easiest): C++, Scala, Rust, Zig, Swift, Nim, Kotlin, JavaScript, Go, Python.

thomasmg··on My “grand vision” for Rust
> the article was not intended to users but to other language designers.

That might be true, but it shows the direction that Rust is talking: put in the kitchen sink, just like C++ and Scala did. And _that_ is very much important for users.

thomasmg··on My “grand vision” for Rust
Hm, you claim that Rust and Scala are not more complex to onboard than Python... but then you say you never used Python? If that's the case, how do you know? Having used both, I do think Rust is harder to onboard, just because there is more syntax that you need to learn. And Rust is a lot more verbose. And that's before you are exposed to the borrow checker.
thomasmg··on My “grand vision” for Rust
> the only feasible compiler solutions to preventing division-by-0 errors are either: defining the behaviour, which always ends up surprising people later on, or; incredibly cumbersome or underperformant type systems/analyses which ensure that denominators are never 0.

I don't think it's very cumbersome if the compiler checks if the divisor could be zero. Some programming languages (Kotlin, Swift, Rust, Typescript...) already do something similar for possible null pointer access: they require that you add a check "if s == null" before the access. The same can be done for division (and remainder / modulo). In my own programming language, this is what I do: you can not have a division by zero at runtime, because the compiler does not allow it [1]. In my experience, integer division by a variable is not all that common in reality. (And floating point division does not panic, and integer division by a non-zero constant doesn't panic either). If needed, one could use a static function that returns 0 or panics or whatever is best.

[1] https://github.com/thomasmueller/bau-lang/blob/main/README.m...

thomasmg··on Ask HN: What Are You Working On? (March 2026)
Objects and structs are described in "Types" [1]. There are no typed unions currently (maybe I'll add them, not sure yet), but there are "Traits" [2].

[1] https://github.com/thomasmueller/bau-lang#types [2] https://github.com/thomasmueller/bau-lang#traits

thomasmg··on Ask HN: What Are You Working On? (March 2026)
Since about two years I'm working on a new systems programming language [1] that is supposed to be nearly as fast as C, memory safe, and as concise and easy to learn as Python. Right now I'm trying to integrate Perceus, the ref-count optimization of Keka.

[1] https://github.com/thomasmueller/bau-lang

thomasmg··on Best performance of a C++ singleton
Optimizing requires a (performane) problem, and often needs a benchmark.

In my view, the article is not about optimizing, but about understanding how things work under the hood. Which is interesting for some.

thomasmg··on Microgpt
I asked ChatGPT to translate (the free version), pasting the source code. The resulting Java code came back a second later.
thomasmg··on Microgpt
I got a convertion to Java. It worked (at least I think...) in the first try.

Then I want to convert this to my own programming language (which traspiles to C). I like those tiny projects very much!

thomasmg··on Two Bits Are Better Than One: making bloom filters 2x more accurate
Your blogpost is great! Except for one detail: you have used modulo n. If n is not known at compile time, multiply+shift is much faster [1]. Division and modulo (remainder) are slow, except on Apple silicon (I don't know what they did there). BTW for blocked Bloom filters, there are some SIMD variants that seem to be simpler than yours [2] (maybe I'm wrong, I didn't look at the details, just it seems yours uses more code). I implemented a register-based one in one in Java here [3].

Bulk insertion: yes, if there are many keys, bulk insertion is faster. For xor filters, I used radix sort before insertion [4] (I should have documented the code better), but for fuse filters and blocked Bloom filters it might not be worth it, unless if the filter is huge.

[1] https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-... [2] https://github.com/FastFilter/fastfilter_cpp/blob/master/src... [3] https://github.com/FastFilter/fastfilter_java/blob/master/fa... [4] https://github.com/FastFilter/fastfilter_cpp/blob/master/src...

thomasmg··on -fbounds-safety: Enforcing bounds safety for C
Yes. The problem is that most memory errors (out of bounds + use after free etc.) result in a vulnerability. Only a minority of the logic errors do.

For operating systems kernels, browsers etc, vulnerabilities have a much, much bigger impact than logic errors: vulnerabilities need to be fixed immediately, and released immediately. Most logic errors don't need to be fixed immediately (sure, it depends on the issue, and on the type of software.)

I would probably say "for memory unsafe languages, 80% of the _impact_ is due to memory vulnerabilities"

thomasmg··on Picol: A Tcl interpreter in 500 lines of code
Yes. His work is really inspiring, eg. the text editor less than 1000 lines, tiny language in less than 1000 lines etc. When I read this on HN, I converted his text editor to my hobby programming language [1] (330 lines), and then wrote a chess engine with terminal UI [2] (400 lines), Tetris clone [3] in 140 lines. I also have a QR code generator and parser [4] (700 lines, still in Java only), a PDF generator (200 lines), and now also a tiny programming language [5].

[1] https://github.com/thomasmueller/bau-lang/blob/main/src/test... [2] https://github.com/thomasmueller/bau-lang/blob/main/src/test... [3] https://github.com/thomasmueller/bau-lang/blob/main/src/test... [4] https://github.com/thomasmueller/bau-lang/blob/main/src/test... [5] https://thomasmueller.github.io/bau-lang/at.html

thomasmg··on Show HN: Sameshi – a ~1200 Elo chess engine that fits within 2KB
I tried to describe this in [1]: "Unsigned integer are intentionally not supported to simplify learning and using the language, to avoid surprising behavior and edge cases, and to reduce security issues and error-handling pitfalls. When needed, unsigned behavior is available through explicit operations. This design does not affect performance or memory usage."

I understand this may not sound very convincing yet... it is hard to describe... basically, unsigned types sound simple, but they are not.

[1] https://thomasmueller.github.io/bau-lang/features.html

thomasmg··on Show HN: Sameshi – a ~1200 Elo chess engine that fits within 2KB
Cool! I just recently implemented a chess engine in ~400 (readable) lines, with all rules, first in Java and then ported to my own programming language "Bau" [1]. This is including a terminal UI. I'll measure the ELO, but I was never able to beat it :-) The castling moves are specially tricky to implement I think. I enjoyed the challenge as well.

[1] https://github.com/thomasmueller/bau-lang/blob/main/src/test...

thomasmg··on Text classification with Python 3.14's ZSTD module
LLMs are good at predicting the next token. Basically you use them to predict what are the probabilities of the next tokens to be a, b, or c. And then use arithmetic coding to store which one matched. So the LLM is used during compression and decompression.
thomasmg··on TikTok users can't upload anti-ICE videos. The company blames tech issues
China: for Taiwan, they are in the planning phase. (Vietnam, Hong Kong, Tibet, Aksai Chin, Korea, Scarborough Shoal do not count in your view of course). Not saying they are worse than the US.
thomasmg··on Binary fuse filters: Fast and smaller than xor filters (2022)
Yes exactly!
thomasmg··on Binary fuse filters: Fast and smaller than xor filters (2022)
Right, it would be wasteful if it's done for each entry separately. But that is not needed. (I should probably write an article about this and a better implementation).

The "succinct counting (blocked) Bloom filters" have two components: the regular Bloom filter for querying, and the count storage. The count storage is not "strictly" needed for querying: you will never get a false _negative_ is increments / decrements in the count storage are deferred. So updating the count storage can be done asynchronously. Both increments and decrements, if you want. So these can be buffered, eg 100 increments / decrements at a time. Sure, the false-positive rate is slightly higher than needed if the decrements are deferred, but with a large filter this effect is small.

So that means, you can buffer increments / decrements in the count storage. You still want to do the "or" operations in the the Bloom filter part synchronously, so that you don't get false negatives. And then, it is no longer just 30-40 cycles, but 3000-4000 cycles, or 30'000-40'000 cycles, or so. I understand this would not be trivial to implement, but also not very complex. I never really had a real-world use case so far, so I didn't work on a full implementation yet.

thomasmg··on Floating-Point Printing and Parsing Can Be Simple and Fast
Schubfach, Ryū, Dragonbox etc support round-tripping and shortest-width, which (it sounds like) is not important for you. The idea of round-tripping is that if you convert a double to a string and then parse that, you get the exact same value. Shortest-width is to correctly round and generate the shortest possible text. I tried to implement a version that does _just_ round-tripping but is not shortest-width, it is around 290 lines for both parsing and toString [1]

[1] https://github.com/thomasmueller/bau-lang/blob/main/src/test...

thomasmg··on Binary fuse filters: Fast and smaller than xor filters (2022)
Yes the count storage update is a bit slow. It could be implemented as a background thread, so that it is not blocking. It depends on the use case wheter this is a problem. The 'blocked' variant might be faster to optimize I assume, if this is needed.
thomasmg··on Binary fuse filters: Fast and smaller than xor filters (2022)
Yes, non-blocked is also possible. This would need a bit less space, and would be a bit slower. The counts > 1 (per bit that is set) are stored spearately, yes.
thomasmg··on Binary fuse filters: Fast and smaller than xor filters (2022)
Yes, you would need a dynamic filter (eg. regular Bloom filter or cuckoo filter) for this, due to the insertions.

Static filters are good for eg. leaked password lists, LSM trees (LevelDB, RocksDB), and so on.

thomasmg··on Binary fuse filters: Fast and smaller than xor filters (2022)
There are many variants. It really depends on what features you need. Cuckoo filters were mentioned. If you want to add and remove entries and the regular counting Bloom filter are not good enough, I would look at the "succinct counting blocked Bloom filter" [1]: they only need about twice the space than regular Bloom filters. Sure, cuckoo filters need less memory, but they can fail basically any time, while these can not.

Tiny filters: Some time ago I worked on tiny statistics [2]. This includes some 64-bit HyperLogLog implementations; some use linear counting, which is basically a 64-bit Bloom filter, until some limit, and only then switch to HyperLogLog. This is great for distinct counts of columns in databases (cardinality estimation). This project also includes 64-bit approximate counts and histograms.

[1] https://github.com/FastFilter/fastfilter_java/blob/master/fa... [2] https://github.com/thomasmueller/tinyStats

thomasmg··on Binary fuse filters: Fast and smaller than xor filters (2022)
I'm one of the authors. Feel free to ask anything.
thomasmg··on The super-slow conversion of the U.S. to metric (2025)
The PDF standard uses base 85 encoding (Ascii 85).
← PreviousPage 2 of 10Next →