←back to thread

The programmers who live in Flatland

(blog.redplanetlabs.com)
107 points winkywooster | 5 comments | | HN request time: 0s | source
1. GMoromisato ◴[] No.46183777[source]
Robust macros allow you to create domain-specific abstractions. That's cool, but there are plenty of other ways. Even functions are a way to create abstractions. And with anonymous functions, you can easily create higher-order abstractions.

The only thing AST-level macros help with is creating custom syntax to cut down on boilerplate. That's very cool, but it comes with a cost: now you have to learn new syntax.

I love Lisp. I've written tiny Lisp interpreters for most of my games (Chron X, Transcendence) and even GridWhale started out with a Lisp-like language.

In my experience, Lisp is great when you have a single programmer who understands and controls the whole source tree. Once a program exceeds the capacity of a single programmer, more conventional languages work better.

replies(1): >>46183862 #
2. wrs ◴[] No.46183862[source]
I’m writing a lot of Rust lately, which is rapidly becoming regarded as a conventional language, and I sure do appreciate all those things I use every day that end in exclamation points.
replies(1): >>46184166 #
3. GMoromisato ◴[] No.46184166[source]
I'm curious here, because I don't know Rust. What's the difference between a macro and a function call from the caller's perspective? Do I (as the caller) need to know I'm calling a macro? Why?

Why is println! a macro when it's a function in almost all other languages?

replies(2): >>46184325 #>>46191238 #
4. wrs ◴[] No.46184325{3}[source]
GCC can type-check printf (matching format string to arguments) because the compiler doesn’t just treat it like a function. But that requires special-case code in the C compiler itself that is basically opaque magic.

Rust doesn’t need that, it’s mostly Rust code in the standard library, with only a small bit of compiler magic triggered by the macro. (Println! isn’t the best example because it does have that small bit of magic; most macros are just plain Rust code.)

Here’s a very impressive set of macros that I use daily. [0] This lets you do “printf logging” on an embedded device, with the human readable strings automatically pulled out into a separate section of the ELF file so the actual log stream data is tiny.

I did a similar thing for C a while ago, as a pre- and post- build step. It worked, but much less well, and was a maintenance nightmare.

Edit: and yeah, I think you do need to know you’re calling a macro, because macros aren’t limited to “normal” syntax or semantics. The ! is a signal that you’re escaping the usual bounds of the language. Like this. [1]

[0] https://defmt.ferrous-systems.com/macros

[1] https://docs.embassy.dev/embassy-stm32/git/stm32f301k6/macro...

5. syklemil ◴[] No.46191238{3}[source]
I think another macro, `json!()` works better as an example for that: inside the `json!()` you write something very similar to actual JSON. So when you see a `!` you know that there might be something out-of-the-ordinary following: https://docs.rs/serde_json/latest/serde_json/macro.json.html

Incidentally it also means that formatters like `rustfmt` won't apply the usual rules. For the macros that don't really deviate from ordinary Rust syntax, that can be a bit annoying.