Remix.run Logo
▲ bunderbunder a day ago

I’ll admit I interpreted that “you” in pron’s sentence to be a colloquial “you” and not an imperative one. So, more of a statement of their own preference than a strong statement of how things should be.

The point is, it’s a tradeoff. With overloading, exactly which code executes on a specific line becomes a bit more implicit because it depends on extra information from the surrounding context: the types of the arguments.

That comes with the usual tradeoffs. On the one hand, you could argue that the compiler is taking care of it for you, which saves the programmer from having to manually deal with it, and removes some visual clutter from the code.

But you can also argue that letting the choice of function be implicit means that a programmer who wants/needs to keep track of exactly what every line of code is doing needs to carry all that contextual information in their own head, too. For this programmer, it’s adding to the mental burden.

I don’t think it’s a coincidence that Kelley constantly brings up how Zig was inspired by difficulties writing a digital audio workstation with very hard real-time requirements. Part of what he’s doing there is giving a motivating case for why he wants to be an absolute control freak about, e.g., micro-managing exactly when memory is allocated and deallocated. That’s something only a subset of systems programmers need, because not all systems programming is dealing with things like hard real-time.

▲Ygg2 21 hours ago | parent [-]

> The point is, it’s a tradeoff. If it's a trade off it's highly squewed.

>But you can also argue that letting the choice of function be implicit means that a programmer who wants/needs to keep track of exactly what every line of code is doing

Use LSP/IDE then ctrl+click operator. Boom. You see what it's executing.

Idea is to create abstraction that make it easier to operate on a more complex level. If you need that level of micro-managing just stick to assembly.

▲pron 5 hours ago | parent [-]

Neither operators nor overloading are abstractions, and they offer no operation at a higher level. An abstraction is something that creates an equivalence class among multiple implementations, and that's not the case here.

First, operators are clearly not an abstraction because they offer a 1-1 correspondence: Instead of `x + y` you write `plus(x, y)`. It's just a different notation.

Overloading also isn't an abstraction because, as you pointed out, the resolution is statically known, and again, there's a 1-1 relationship. Indeed, it's just name mangling. Instead of writing `plus_int_int(x, y)` you write `plus(x,y)` and the compiler adds the `int_int` for you.

There's no doubt operators and/or overloading have some convenience advantages, but there's also no doubt they have some disadvantages, which is why some languages disallow one or both, regardless of how high or low-level they are. But Zig also has some special reasons to prevent overloading, because the language is built around compile-time introspection. So you can have just a single `plus` for multiple types, but the static dispatch is explicitly controlled by the implementation of `plus`. This means that all resolution is always local or uses unique names.

I'm not saying you have to personally like it. Zig and Rust both aim at different preferences so that people may prefer one over the other. But there is no difference in expressivity (but there very much is between assembly or even C and either one of Zig or Rust). Rust, like C++, chooses to favour implicitness over explicitness, and Zig chooses the opposite. Both have pros and cons, and neither is universally superior to the other.