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 Group Borrowing: Zero-cost memory safety with fewer restrictions
> any particular reason you went with a go-like `ident type` syntax

I just think that ":" is unnecessary. In my language, the type is mostly used in function declarations and types, eg.

    fun File read(data i8[], pos int, len int) int

    type List(T)
        array T[]
        size int
What would be the advantage of adding ":"?
thomasmg··on Group Borrowing: Zero-cost memory safety with fewer restrictions
Yes, I see your point. In Rust, the owner, and the mutable borrower can change the pointer itself (like C realloc). If multiple "mut" borrows are allowed, then this would be unsafe, so I understand "unstable mut" would solve this problem - but result in a new colouring problem.

My solution to this would be: in a new language, do not allow reallocation. Not for owners, and not for mut borrow. This is what Java does: an ArrayList is a wrapper around an array, and so adding entries will not move the ArrayList object, just the (wrapped) private array. In Java the programmer never sees dangling references. Java prevents the issue by design, at the cost of always paying for the wrapper. If you want to avoid this price, you need to use the array directly.

(I have to admit I was not aware that in Rust, push moves the memory... so thanks a lot for explaining! Always learning something new.)

I don’t have any problem with Rust’s focus on performance. But its design does make life harder for developers than it needs to be. It doesn't match my vision of a programming language that is at the same time easy to use, safe, and nearly as fast as C.

thomasmg··on Group Borrowing: Zero-cost memory safety with fewer restrictions
Well the distinction between mutable and immutable borrows doesn't solve use-after-free. What prevents use-after-free is ownership. There is one owner, and the owner can not free the memory as long as there is a borrower (it doesn't matter whether the borrower is mutable or not). So that's the task of the borrow checker.

For my own programming language [1], I have only mutable borrowers (similar to Java), and a much simpler borrow checker: a method that holds a borrow can not call a method that potentially frees an object of the same type (directly or indirectly). I'm not sure yet if this is sufficient; it's still a borrow checker, just a very simple one. (My language uses reference counting by default, but does support single ownership + borrowing.)

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

thomasmg··on Group Borrowing: Zero-cost memory safety with fewer restrictions
I think you are right. The post talks about mutable vs immutable borrows, and how to have multiple mutable borrows, safely. But doubly-linked list are hard in Rust due to ownership, and not borrowing. (Doubly linked lists could be supported by "splitting" and "merging" ownership: having "half"-owners, and then you can merge ownership.)

I understand the reason for having 1 mutable xor n immutable references... but I think Rust made the wrong choice here: now we see two versions of each method, one with mutable and another without mutable. It's similar to the async coloring problem, but instead of async / not async, in Rust you have mutable and non-mutable. It would simplify things a lot for the programmer (not for the compiler, OK), if all borrows are mutable. Sure the compiler can't always emit noalias, and multi-threading gets slower... But with a sane memory model (as in Java), I think it would be simpler for the programmer.

thomasmg··on Show HN: Regolith – Regex library that prevents ReDoS CVEs in TypeScript
A static analysis of the regular expression has the advantage that many problematic cases can be caught at compile time. Not all: the expression is sometimes generated at runtime. There's also a risk that too many cases might be rejected.

Did you consider a hybrid approach, where static analysis is used to get compiler warnings / errors, combined with limiting the number of operations at runtime? An API change might be needed, so instead of just "matches(regex)" a new method might be needed with a limit "matches(regex, opCountLimit)" and a different return type (true / false / timeout).

thomasmg··on Show HN: Regolith – Regex library that prevents ReDoS CVEs in TypeScript
Right. An example regex that can be slow is CSV parsing [1]:

.*,.*,.*,.*,.* etc.

I believe a timeout is a better (simpler) solution than to try to prevent 'bad' patterns. I use this approach in my own (tiny, ~400 lines) regex library [2]. I use a limit at most ~100 operations per input byte. So, without measuring wall clock time, which can be inaccurate.

[1]: https://stackoverflow.com/questions/2667015/is-regex-too-slo... [2]: https://github.com/thomasmueller/bau-lang/blob/main/src/test...

thomasmg··on Ask HN: What are you working on? (July 2025)
Thanks! I know Rust, Java etc do a good job of array bound check elimination, but I prefer a way to _ensure_ there is no check. I felt this was missing.
thomasmg··on Ask HN: What are you working on? (July 2025)
Thanks! Yes, that makes a lot of sense. I will improve this section!

> what I'd be losing by going from C to Bau

Well, you can add native C code, so in theory you do not miss much. But in practise, yes of course many features are missing still.

thomasmg··on Ask HN: What are you working on? (July 2025)
I'm working on a new memory-safe systems programming language that is supposted to be (almost) as fast as C, Rust etc, but as simple and concise as Python: https://github.com/thomasmueller/bau-lang

There is a playground which is using a C compiler and WASM, and so is quite fast, while running fully in the browser. Theres also a (online) conversion tool to convert and compare source code. There are some benchmarks as well.

Writing my own (concise, simple) programming language was a dream for me since I'm 20 or so. Feedback would be great!

thomasmg··on Klong: A Simple Array Language
Thanks! So here is an explanation:

> The same baseless accusations of “unreadable”, “write-only” and “impossible to learn” are leveled at all Iversonian languages, k included.

I argue that these accusations are far from baseless. Sure, I can not cite a study, but neither does he. So I assume it's word against word.

> Readability is a property of the reader, not the language.

In my view this is an oversimplification. Having a steep learning curve clearly prevents adoption. The language design actively contributes to the problem. I'm just not sure on why. Could it be that the authors of these languages do not _want_ them to be used by others?

thomasmg··on Klong: A Simple Array Language
I appreciate the features of these languages (J, K, and Klong), but I do not understand the reason why they have such a hard to read syntax. I think it is a pity; I could see myself using it otherwise. Maybe it is by design, but I do not understand it.
thomasmg··on Klong: A Simple Array Language
> If you try to use it like your favorite functional/procedural/OO programming language, you will only get frustrated.

For me personally, the sentence could be shortened to just: "If you try to use it, you will only get frustrated."

thomasmg··on Modern Minimal Perfect Hashing: A Survey
> using it like gperf is certainly not a special case.

Well... let's put it like this: in this survey, "parsers" (where I am one of the co-authors) are not mentioned explicitly in the "Applications" section. They are a subset of "Hash Tables and Retrieval". There are many other uses: Approximate Membership, Databases, Bioinformatics, Text Indexing, Natural Language Processing. Yes, parsers are mentioned in "The Birth of Perfect Hashing". Maybe we can conclude that parsers are not the "main" use case nowadays.

> when you compile those data structures, the load time is instant.

Well, in this case I would recommend to use a static lookup table in the form of source code. That way, it is available for the compiler at compile time, and doesn't need to be loaded and parsed at runtime: it is available as a data structure at runtime. All modern MPHF implementations in this survey support this usage. But, yes, they are not optimized for this use case: you typically don't have millions of keywords in a programming language.

thomasmg··on Modern Minimal Perfect Hashing: A Survey
From what you describe, I think you have a somewhat special use case: it sounds like you are compiling it. The experiments done in the survey are not: instead, the hash function is used in the form of a data structure, similar to a Bloom filter ("deserialized" in your words). Do you use it for a parser? How many entries do you have? The survey uses millions of entries. "Startup time in the query time": I'm not quite sure what you mean, I'm afraid. Could you describe it?

I'm also not sure what you mean with "check for false positives"... each entry not in the set returns a random value, maybe for you this is a "false positive"? A typical solution for this is to add a "fingerprint" for each entry (just a hash value per entry) - that way there is still some false positive probability, which may or may not be acceptable (it is typically considered acceptable if the hash function is cryptographically secure, and the fingerprint size is big enough: e.g. 128 bits of the SHA-256 sum). Depending on the data, it may be faster to compare the value (eg. in a parser).

thomasmg··on Modern Minimal Perfect Hashing: A Survey
Using a brute-force approach can quickly find a minimal perfect hash table. Eg. the RecSplit approach can be used for this case, to first split into 4 sections, and then use another one for each section. Or, in this case, the same one for each section:

    (hash(c + 4339104) & 7) * 4 + (hash(c + 201375) & 3)
For a generic hash function (eg the Murmur hash, or the simple one here:

    long hash(long x) {
        x = ((x >>> 16) ^ x) * 0x45d9f3b;
        x = ((x >>> 16) ^ x) * 0x45d9f3b;
        x = (x >>> 16) ^ x;
        return x;
    }
As described in the linked paper, the fastest way to find such a MPHF for larger sets is nowadays Consensus-RecSplit.

[1] https://stackoverflow.com/questions/664014/what-integer-hash...

thomasmg··on Show HN: Fast Random Library for C++17
So I'm a bit confused, the paper says "'Randen' ... outperforming ... PCG" but now you wrote "though slower than pcg64"? In the paper itself, PCG is faster but "these microbenchmark results are quite irrelevant in practice — which actual application repeatedly calls a random generator and ignores the results?" I wonder, was the paper peer-reviewed? (I'm not saying it should have been..., just wondering.)

My guess is that yes, Randen is fast, but it is not quite as fast as PCG or other pseudo-random number generators.

Whether or not it is relevant, that's another story. I can not agree to your claim "there are vanishingly few use cases" for insecure random number generators.

thomasmg··on Bloom Filters
Yes, I know it is not designed to be a error-correction code, and other codes (turbo code, fountain code), are a lot more efficient. But I wanted to mention it because it's related to the topic.

> You can make it work over data with positions by adding a position number

Yes, that's what I did in my experiments. I personally found it really simple to implement; I'm not sure how easy it is to implement a "real" error correction code.

thomasmg··on Bloom Filters
So, for this it sounds like you only need one Bloom filter (not multiple), and each subset is an _entry_ in the filter. The total set size doesn't matter; what matters (for the size of the Bloom filter) is the total number of entries you put into the Bloom filter, and the false positive rate. And then, you can do a membership test (with a configurable false positive rate, typical is 1%), to find out if an entry is in the set. BTW you can not use Bloom filters to store and retrieve entries: for that, you need something else (an array, or hash map, or a retrieval data structure; Bloom filter can't be used).
thomasmg··on Bloom Filters
This is a bit similar to count-min sketch, which can be used to calculate frequencies in a stream.

Also interesting are "Invertible Bloom Lookup Tables" (IBLT), https://arxiv.org/pdf/1101.2245 , which allow to add and remove data, and allow to retrieve the remaining data if "little" data remains. That means, it can be used for error correction: all all the _correct_ data (let's say 1 GB of correct data) into a 1 MB IBLT. Let's say a downloader finds that the checksum doesn't match: he can download that 1 MB IBLT, and remove the data from his (invalid) download. What remains is the delta: the error correction data. I know, there are other ways you could do error correction, but this is very fast, and quite interesting technically.

thomasmg··on Bloom Filters
This is described here: https://en.wikipedia.org/wiki/Bloom_filter#Compact_approxima...
thomasmg··on Bloom Filters
Well, what problem do you want to solve? What you describe is not a use case but a possible solution... this smells like an xy problem...
thomasmg··on Bloom Filters
Yes, this is the succinct counting blocked Bloom filter I wrote. I wanted to write a paper about it. It requires twice the space of a blocked Bloom filter (which is about half the space of a regular counting Bloom filter). Reads are very fast, and updates are okish.
thomasmg··on Regex Isn't Hard (2023)
Thanks for reading and taking the time to respond!

> Doesn't this go against the "literals are enclosed in quotes" idea?

Sure, one could argue that other changes would also be useful, but then it would be less concise. I think the main reasons why people like regex are: (a) powerful, (b) concise.

For my V2 proposal, the new rule is: "literals are enclosed in quotes", the rule isn't "_only_ literals are enclosed in quotes" :-) In this case, I think `-` can be quoted as well. I wanted to keep the v2 syntax as close as possible to the existing syntax.

thomasmg··on Regex Isn't Hard (2023)
For me, the main problem of the Regex syntax is the escaping rules: Many characters require escaping: \ { } ( ) [ ] | * + ? ^ $ . And the rules are different inside square brackets. I think it would be better if literal text is enclosed in quotes; that way, much less escaping is needed, but it would still be concise (and sometimes, more concise). I tried to formulate a proposal here: https://github.com/thomasmueller/bau-lang/blob/main/RegexV2....
thomasmg··on Raspberry Pi Lidar Scanner
Well, Trump is the one that almost always frames things in very binary way. If someone contradicts him, it is "fake news". His opposition is typically much less so, and much more rational and thoughtful.

Even many in the opposition agrees with many of his goals (control immigration, protect American industries, shrink the government).

thomasmg··on Geothermal power is a climate moon shot beneath our feet
I mean heat pumps where you drill around 200 meters deep. Whether you want to call those geothermal or ground-source, that is up to you I guess.
thomasmg··on Succinct data structures
For Java, C++, and Rust there is also https://sux.di.unimi.it/ maintained by Sebastiano Vigna, a professor from Italy.

Together with his student (I also helped a bit), he wrote a paper about RecSplit, a minimal perfect hash function (MPHF) algorithm I have invented: https://arxiv.org/abs/1910.06416 - that algorithm uses around 1.56 bits per key. But it is quite slow. In January 2020 I presented the paper at a conference, that was right before the pandemic.

The algorithm with the least memory usage (and much faster as well) is now Consensus-RecSplit: https://arxiv.org/abs/2502.05613 - it can do 1.44 bits per key, which is right at the theoretical minimum (meaning, there is no good way to shrink it further). At least a small part of my original invention is still used there, nice. The fastest current MPHF is probably PtrHash https://arxiv.org/abs/2502.15539 - both papers were published last month (February 2025) by the way.

thomasmg··on Geothermal power is a climate moon shot beneath our feet
In many places it makes sense to heat the earth (yes) in summer using the heat pump (using electricity from photovoltaics) so that efficiency in winter is better.
thomasmg··on Geothermal power is a climate moon shot beneath our feet
Yes. And in Switzerland, I believe most new houses have some other type of heat pump (drilling for geothermal is not allowed everywhere, or too expensive). This all still needs electricity; but many houses now install photovoltaics. (At least where I live.)
thomasmg··on The European VAT Is Not a Discriminatory Tax Against US Exports
The VAT is not complex. And why would an American company be better at invoicing?
← PreviousPage 5 of 10Next →