frontpage.
newsnewestaskshowjobs

Made with ♥ by @iamnishanth

Open Source @Github

fp.

OpenCiv3: Open-source, cross-platform reimagining of Civilization III

https://openciv3.org/
576•klaussilveira•10h ago•167 comments

The Waymo World Model

https://waymo.com/blog/2026/02/the-waymo-world-model-a-new-frontier-for-autonomous-driving-simula...
889•xnx•16h ago•540 comments

How we made geo joins 400× faster with H3 indexes

https://floedb.ai/blog/how-we-made-geo-joins-400-faster-with-h3-indexes
91•matheusalmeida•1d ago•20 comments

What Is Ruliology?

https://writings.stephenwolfram.com/2026/01/what-is-ruliology/
18•helloplanets•4d ago•9 comments

Unseen Footage of Atari Battlezone Arcade Cabinet Production

https://arcadeblogger.com/2026/02/02/unseen-footage-of-atari-battlezone-cabinet-production/
21•videotopia•3d ago•0 comments

Show HN: Look Ma, No Linux: Shell, App Installer, Vi, Cc on ESP32-S3 / BreezyBox

https://github.com/valdanylchuk/breezydemo
197•isitcontent•11h ago•24 comments

Monty: A minimal, secure Python interpreter written in Rust for use by AI

https://github.com/pydantic/monty
199•dmpetrov•11h ago•91 comments

Show HN: I spent 4 years building a UI design tool with only the features I use

https://vecti.com
307•vecti•13h ago•136 comments

Microsoft open-sources LiteBox, a security-focused library OS

https://github.com/microsoft/litebox
352•aktau•17h ago•175 comments

Sheldon Brown's Bicycle Technical Info

https://www.sheldonbrown.com/
350•ostacke•17h ago•91 comments

Hackers (1995) Animated Experience

https://hackers-1995.vercel.app/
452•todsacerdoti•18h ago•228 comments

Delimited Continuations vs. Lwt for Threads

https://mirageos.org/blog/delimcc-vs-lwt
20•romes•4d ago•2 comments

Dark Alley Mathematics

https://blog.szczepan.org/blog/three-points/
79•quibono•4d ago•18 comments

PC Floppy Copy Protection: Vault Prolok

https://martypc.blogspot.com/2024/09/pc-floppy-copy-protection-vault-prolok.html
52•kmm•4d ago•3 comments

Show HN: If you lose your memory, how to regain access to your computer?

https://eljojo.github.io/rememory/
253•eljojo•13h ago•153 comments

An Update on Heroku

https://www.heroku.com/blog/an-update-on-heroku/
388•lstoll•17h ago•263 comments

Was Benoit Mandelbrot a hedgehog or a fox?

https://arxiv.org/abs/2602.01122
5•bikenaga•3d ago•1 comments

How to effectively write quality code with AI

https://heidenstedt.org/posts/2026/how-to-effectively-write-quality-code-with-ai/
230•i5heu•13h ago•175 comments

Zlob.h 100% POSIX and glibc compatible globbing lib that is faste and better

https://github.com/dmtrKovalenko/zlob
12•neogoose•3h ago•7 comments

Show HN: R3forth, a ColorForth-inspired language with a tiny VM

https://github.com/phreda4/r3
68•phreda4•10h ago•12 comments

Female Asian Elephant Calf Born at the Smithsonian National Zoo

https://www.si.edu/newsdesk/releases/female-asian-elephant-calf-born-smithsonians-national-zoo-an...
24•gmays•6h ago•6 comments

Why I Joined OpenAI

https://www.brendangregg.com/blog/2026-02-07/why-i-joined-openai.html
116•SerCe•7h ago•94 comments

I spent 5 years in DevOps – Solutions engineering gave me what I was missing

https://infisical.com/blog/devops-to-solutions-engineering
135•vmatsiiako•16h ago•59 comments

Understanding Neural Network, Visually

https://visualrambling.space/neural-network/
268•surprisetalk•3d ago•36 comments

Introducing the Developer Knowledge API and MCP Server

https://developers.googleblog.com/introducing-the-developer-knowledge-api-and-mcp-server/
42•gfortaine•8h ago•13 comments

Learning from context is harder than we thought

https://hy.tencent.com/research/100025?langVersion=en
168•limoce•3d ago•87 comments

I now assume that all ads on Apple news are scams

https://kirkville.com/i-now-assume-that-all-ads-on-apple-news-are-scams/
1039•cdrnsf•20h ago•431 comments

FORTH? Really!?

https://rescrv.net/w/2026/02/06/associative
60•rescrv•18h ago•22 comments

Show HN: ARM64 Android Dev Kit

https://github.com/denuoweb/ARM64-ADK
14•denuoweb•1d ago•2 comments

Show HN: Smooth CLI – Token-efficient browser for AI agents

https://docs.smooth.sh/cli/overview
88•antves•1d ago•63 comments
Open in hackernews

Understanding Rust Closures

https://antoine.vandecreme.net/blog/rust-closures/
68•avandecreme•1w ago

Comments

amelius•1w ago
Closures are the bread and butter of functional programming, but Rust made closures a complicated mess.
Klonoar•1w ago
If you understand the borrow checker, closures are just not that much on top of things.

In fact I can’t remember the last time I had to fight with them.

convolvatron•1w ago
I really wanted just yesterday to create a dyn AsyncFnMut, which apparently still needs async-trait to build the stable. but I was pretty much unable to figure out how to make that work with a lambda. saying this is all trivial once you understand the borrow machinery is really understating it.
kibwen•1w ago
> saying this is all trivial

The comment above isn't saying that closures are trivial. Once you understand the borrow checker, you understand that it's a miracle that closures in Rust can possibly work at all, given Rust's other dueling goals of being a GC-less language with guaranteed memory safety despite letting closures close over arbitrary references. Rust is in uncharted territory here, drawing the map as it goes.

speed_spread•1w ago
Async is the stuff that messes up everything. Closures are not complicated.
SkiFire13•1w ago
Closures are pretty simple in relation to their captures lifetimes, but they do have a lot of complexity in how the lifetimes of their argument and return type are computed. The compiler has to basically infer them, and that can easily go very wrong. The only reason it works most of the time is because closures are immediately passed to functions whose trait bound specify the expected signature of the closure, but once you deviate a little bit from the common case things start to break down. For example if the bound is `F: SomeTrait` where `SomeTrait` is implemented for `FnOnce(&' i32) -> &i32` the inference will break. Similarly if you store the closure in a local variable before passing it to the function. This used to come up pretty often for "async" closures that were supposed to take a reference as input, since it's impossible to specify their correct trait bound using directly the `Fn*` traits. There are a bunch of related issues [1] in the rustc repo if you search for closure and higher ranked lifetimes.

[1]: https://github.com/rust-lang/rust/issues?q=is%3Aopen%20is%3A...

openuntil3am•1w ago
Closures are a complicated mess. Functional programming languages hide the mess with garbage collection.
andrewflnr•1w ago
This isn't the right framing IMO. Closures actually aren't complicated with GC for the same reason structs with references aren't complicated, at least as far as the programmer is concerned. You could say functional languages "hide the mess" there too, but even if you take that perspective, it's nothing to do with closures in particular. Closures are just one of the things that need memory, and memory management is tricky without GC.
armchairhacker•1w ago
Machine code and LLVM are complicated messes. Higher-level language hide a lot, but sometimes issues pop up, even in Rust e.g. inline heuristics (https://nnethercote.github.io/perf-book/inlining.html).
ordu•1w ago
Well... Rust is not a functional language, so it is not surprising that its closures are complicated.
SkiFire13•1w ago
Functional programming languages usually don't support linear/affine types, non-gc references and mutations.

Their closures are essentially the equivalent of Rust's `Rc<dyn Fn(...) -> ...>` with some sugar for expressing the function type and hiding all the `.clone()`s needed.

It's easy to get simplier results if you support less features and use cases.

andy_xor_andrew•1w ago
if I'm not mistaken (and I very well may be!) my primary confusion with closures comes from the fact that: the trait they implement (FnOnce / Fn / FnMut) depends entirely upon what happens inside the closure.

It will automatically implement the most general, relaxed version (FnMut I think?) and only restrict itself further to FnOnce and Fn based on what you do inside the closure.

So, it can be tricky to know what's going on, and making a code change can change the contract of the closure and therefore where and how it can be used.

(I invite rust experts to correct me if any of the above is mistaken - I always forget the order of precedence for FnOnce/Fn/FnMut and which implies which)

KolmogorovComp•1w ago
This is correct. But it’s not really surprising, it’s type inference.
gpm•1w ago
It isn't really type inference. Each closure gets a unique type. Rather it's an automatic decision of what traits (think roughly "superclasses" I guess if you aren't familiar with traits/typeclasses) to implement for that type.
chowells•1w ago
So you're saying... it's type inference of type classes, just like in Haskell?
csomar•1w ago
I am not sure how Haskell works but I think what the previous poster meant is that the types get determined at compile time. Closures are akin to macros except you can't see the expanded code.
gpm•1w ago
No, I don't think so, not unless there's some feature of Haskell type classes I'm completely unaware of.

If anything it's closer to SFINAE in C++ where it tries to implement methods but then doesn't consider it an error if it fails. Then infers type-classes based on the outcome of the SFINAE process. Or the macro analogy another poster made isn't bad (with the caveat that it's a type system aware macro - which at least in rust is strange).

umanwizard•1w ago
The least restrictive for the caller is Fn (you can call it whenever), then FnMut (you can call it only if you have exclusive access to it, as many times as you want), then FnOnce (you can call it only if you have exclusive owned access, and calling it once destroys it).

The least restrictive for the function itself is the opposite order: FnOnce (it can do anything to its environment, including possibly consuming things without putting them back into a consistent state), followed by FnMut (it has exclusive access to its environment, and so is allowed to mutate it, but not destroy it), followed by Fn (it has only shared access to its environment and therefore is not allowed to mutate it).

Since these orders are inverses of each other, functions that are easier to write are harder to call and vice versa. That’s why they implement the trait with the minimum amount of power possible, so that they can be called in more places.

yoshuaw•1w ago
> I always forget the order of precedence for FnOnce/Fn/FnMut

The way I remember the ordering is by thinking about the restrictions the various Fn traits provide from a caller's perspective:

  1. FnOnce can only ever be called once and cannot be called concurrently. This is the most restrictive.

  2. FnMut can be called multiple times but cannot be called concurrently. This is less restrictive than FnOnce.

  3. Fn can be called multiple times and can even be called concurrently. This is the least restrictive.
So going from most to least restrictive gives you `FnMut: FnOnce` and `Fn: FnMut`.
umanwizard•1w ago
Fn can only be called concurrently if its environment is Sync, which is often true but not necessarily.

It’s more precise to say that Fn can be called even when you only have shared access to it, which is a necessary, but not sufficient, condition for being able to be called concurrently.

pwdisswordfishy•1w ago
I'm not sure myself, does Fn correspond to reentrancy or is there some detail I am missing?
armchairhacker•1w ago
`Fn`, `FnMut`, and `FnOnce` can also implement and not implement `Sync` (also `Send`, `Clone`, `Copy`, lifetime bounds, and I think `use<...>` applies to `impl Fn...` return types).

EDIT: https://news.ycombinator.com/item?id=46750011 also mentioned `AsyncFn`, `AsyncFnMut`, and `AsyncFnOnce`.

krukah•1w ago
Easiest mnemonic to remember precedence is simply ordering by the length of their names.

FnOnce

FnMut

Fn

bobbylarrybobby•1w ago
The three Fn* types correspond to the three ways you can refer to a value: &T, &mut T, T. Fn captures its environment by shared reference, FnMut by exclusive reference, and FnOnce by value, and everything flows from that. Calling a Fn is the same as using a reference. Calling a FnMut is the same as using a mutable reference (you can do it as many times as you want but no two uses may overlap in time). And calling a FnOnce is the same as moving a value (you can do it at most once).
csomar•1w ago
My issue is that there is no easy way to know the signature generated by the closure (unlike a function) until you read the compiler errors and even then it's some cryptic mess because closures are anonymous structs. Or maybe I missed some LSP config/extension?
Sytten•1w ago
And now we have the Async version of each of those, which makes me very happy and reduces the shenanigans and lifetime issues.

Also worthy of note is that there is talk to add a syntax for explicit captures.

OptionOfT•1w ago
I wish there was more customizability with regards to captures.

the move keywords captures everything. Sometimes I want a little bit more flexibility, like C++ lambdas.

avandecreme•1w ago
This article discusses making captures more flexible: https://smallcultfollowing.com/babysteps/blog/2025/10/22/exp...

I agree it would be nice, in particular to make it easier to understand when learning the concept.

BlackFly•1w ago
The biggest friction I experience with respect to rust closures is their inability to be generic: I cannot implement a method that takes a closure generic over its argument(s).

So then I'm forced to define a trait for the function, define a struct (the closure) to store the references I want to close over, choose the mutability and lifetimes, instantiate it manually and pass that. Then the implementation of the method (that may only be a few lines) is not located inline so readability may suffer.

wtetzner•1w ago
Do you have an example of this? I'm not sure I follow it exactly.
tuetuopay•1w ago
You most definitely can.

    fn foo<F, T>(f: F)
    where
        F: Fn(T),
        T: ToString,
    {
        f("Hello World")
    }
Or did I not understand what you meant?
armchairhacker•1w ago
Something like this isn’t possible

    fn foo(f: impl for<T: ToString> Fn(T)) {
        f(“Hello World”);
        f(3.14);
    }

    fn main() {
        f(|x| println!("{}", x.to_string());
    }
The workaround:

    trait FnToString {
        fn call(&self, x: impl ToString);
    }

    fn foo(f: impl FnToString) {
        f.call("Hello World");
        f.call(3.14);
    }

    struct AnFnToString;
    impl FnToString for AnFnToString {
        fn call(&self, x: impl ToString) {
            println!("{}", x.to_string());
        }
    }

    fn main() {
        foo(AnFnToString);
    }
tuetuopay•1w ago
Ha, yes, I see what you mean now. That's not really the closure's fault but monomorphization of the foo function. The specific thing you want to do would require boxing the value, or do more involved typing.
stevefan1999•1w ago
As a side note, there is a libffi wrapper on Rust that is exactly leveraging this code and data separation of closures in Rust: https://docs.rs/libffi

I've been using this on my vibewasm project to provide host function conversion to keep a C callable function in the front surface but doing my own custom wasm calling convention while capturing a persistent context pointer to the wasm store.

There is a side effect though: it is essentially unsound as you have to leak the object to the libffi closure which is a form of JIT -- dynamic code generation, it is, meaning Rust will have no way of knowing the lifetime of the pointer, or you have to always keep the libffi closure alive, meaning it is a permanent leak. I tried mitigate this by storing the closure in the wasm store, and we use that as the ultimate closure lifetime by designation -- any libffi function callback post store destruction is undefined behavior though.