The GPU loves arrays of structures AoS, since all vertex data fits in its triangle assembly cache. Once given to the GPU, the software side doesnt really care for all vertex parameters so this optimisation is pointless. Only relavent when you have instance rendering (leaves, grass) but then you only need an array of vec3’s, not the other parameters so back to normal arrays.
Meanwhile, game engines need operator overloading for adding/multiplying vectors (spatial transforms, lighting, physics) and core zig design philosophy prevents operator overloading.
Blind leading the blind. Disclaimer - I do professional rendering engines.
On the other hand, SIMD loves SoA, and so does the CPU cache. It all depends on what you're doing with your data.
Zig professes to be a C replacement, not a C++ replacement, so leaving out operator overloading is consistent with that design goal. But I agree, I would prefer to program in a language that expresses mathematical relationships more naturally.
> Meanwhile, game engines need operator overloading for adding/multiplying vectors (spatial transforms, lighting, physics) and core zig design philosophy prevents operator overloading.
This is a frustrating decision. My use cases for low level languages overlap closely with my use cases for vectors (etc) with operator overloading. It was one of the first things which put a bad taste in my mouth about Zig.
Not GP, but I've written game engines and rendering engines. Vector operations are just common enough that having to write `.mul` every time is a huge pain, especially when you put many of them together for a large formula. Compare:
We learn to read and think about math a certain way, which is incompatible with Zig. Also, Zig's design philosophy of "reading code over writing code" is incompatible with the kind of small modification-test-cycles required when doing games, and creative programming in general. So Zig is sort of DOA anyway for that kind of thing.
But I've been using Zig for non-game projects and it's been fantastic, so definitely not "Blind leading the blind" for the overall language design, imo.
I know this is already possible with comptime, though I haven't implemented it yet since I haven't needed vector math in what I'm working on currently. Can't decide whether using math names is better or worse than using the full variable names though.
I have a sibling comment -- having thought about this for a very very long time, zig should really implement binary pseudo-operator syntactic sugar. I don't think this violate zig's spirit of 'no hidden function calls' in that I don't think it takes much of a mental lift to "get" that (_ <+> _) means "heyo this is a function call, not a true operator".
At first I was going to say that I disagreed since you couldn't choose what implementation of addition you wanted, but now that I've read your comment where you import the type of addition used, it's growing on me. Would you have operator precedence, or would it be more like Smalltalk's binary operators?
yes! i had this exact idea. i also thought about integrating geometric/clifford algebra using zig's type system so that you could have one mathematical multivector object instead of complex / quaternion types, etc.
That's the other great thing about using comptime, is you can specify which DSL you want to use for which scenario. You're not locked into one implementation.
Andrew talks about it because it introduces hidden control flow where you're expecting simple operators. In Zig anything that deals with control flow is a keyword (including short circuiting and, which is `and` instead of `&&`).
I'd argue though that the real disadvantage to having overloadable arithmetic is that you're limited to one implementation. This is actually my biggest beef with Rust, namely traits/type classes. It locks you into a single implementation when you may want to do something different based on the context. Zig pushes the dispatch decision to the callsite, not a trait subsystem (see how Zig implements hash mays for example). So I'd personally prefer to use a DSL, since it lets me specify what type of dispatch to use.
Overloadable operators are not an instance of hidden control flow. Overloadable operators represent a user-defined function call, and the body of an arbitrary function cannot do anything like return from the calling function or break out of a loop (as long as your language doesn't have exceptions, which Zig doesn't).
For me the answer is very simple: Operators make it easier to read the code which makes it easier to spot bugs. It also makes it easier to turn formulas from textbooks into code.
If 50% of the code you're working with is using vectors and matrices, not having operators for those parts is quite annoying.
Note that you can have vector operators without overloading, e.g. Odin has built in vector and matrix types.
But personally I think it's better to give the user more power instead of only letting the compiler author pick which types to allow operators on. Like how Java overloads + but only on the String class. Why do they get to do it, but not me?
you actually don't want "operator overloading", you want syntactic sugar. I once proposed just a special operator syntax at the parser level, but it got rejected, but if you REALLY wanted it, you could probably do this in about 100-120 lines as a fork of the zig compiler, just hacking (a <_> b) as a special form to be transformed into @"<_>"(a, b). Requiring parentheses elides questions about operator precedence.
const @"<+>" = @import("operator_module").plus;
...
const x = (a <+> b);
I mean as an avid Lisp fan, I feel like Lisp basically answers the question of how much syntax you need in a langauge. I must admit though, not having to deal with operators precedence is really nice
Zig is adding native vectors including operator support, there are some recent issues/prs about this topic.
The general technique of SoA is pretty useful both in games and other applications, but of course I cannot speak to the specific use-case you are describing.
Zig vectors force data into SIMD registers even if that would make the code slower. They're a specialty type. You should only reach for vectors if you would have used SIMD intrinsics in C for example.
Zig vectors do not necessarily force data into SIMD registers; a scalar implementation would work equally well. This is not just a theoretical argument, because Zig code that uses `@Vector` also has to compile for architectures that do not have SIMD instructions.
That being said, the parent commenter is actually referring to other recent proposals as opposed to existing `@Vector` functionality:
So is the argument that any SoA is pointless? Or just for GPU stuff? Because this isn't really talking about all that one way or another.
Also does one really need operator overloading? That feels a little strong. I've gotten by with functions just fine.. Does that make the GPU not like me Mr. wise engineer?
OT: I just spend a few minutes searching for the source of the "Not all CPU operations are created equal" slide of the linked presentation (Andrew Kelley - Practical DOD), its here:
Still the same. I guess it's some sort of wild anti-bot stuff basing on the user agent?
/edit
Yes, as confirmed with cURL, using my browser's "User Agent": 410 blocked. Using some other "User Agent" and it passes along the data. Pretty silly, IMHO.
The GPU loves arrays of structures AoS, since all vertex data fits in its triangle assembly cache. Once given to the GPU, the software side doesnt really care for all vertex parameters so this optimisation is pointless. Only relavent when you have instance rendering (leaves, grass) but then you only need an array of vec3’s, not the other parameters so back to normal arrays.
Meanwhile, game engines need operator overloading for adding/multiplying vectors (spatial transforms, lighting, physics) and core zig design philosophy prevents operator overloading.
Blind leading the blind. Disclaimer - I do professional rendering engines.
On the other hand, SIMD loves SoA, and so does the CPU cache. It all depends on what you're doing with your data.
Zig professes to be a C replacement, not a C++ replacement, so leaving out operator overloading is consistent with that design goal. But I agree, I would prefer to program in a language that expresses mathematical relationships more naturally.
> Meanwhile, game engines need operator overloading for adding/multiplying vectors (spatial transforms, lighting, physics) and core zig design philosophy prevents operator overloading.
This is a frustrating decision. My use cases for low level languages overlap closely with my use cases for vectors (etc) with operator overloading. It was one of the first things which put a bad taste in my mouth about Zig.
Genuine question: why do you think game engines need operator overloading? I mean, what's wrong with generic functions like add, multiply, dot etc.
Not GP, but I've written game engines and rendering engines. Vector operations are just common enough that having to write `.mul` every time is a huge pain, especially when you put many of them together for a large formula. Compare:
(physics_data.velocity + omega * change) * frame_delta_time
to
physics_data.velocity.add(omega.mul(change)).mul(frame_delta_time)
We learn to read and think about math a certain way, which is incompatible with Zig. Also, Zig's design philosophy of "reading code over writing code" is incompatible with the kind of small modification-test-cycles required when doing games, and creative programming in general. So Zig is sort of DOA anyway for that kind of thing.
But I've been using Zig for non-game projects and it's been fantastic, so definitely not "Blind leading the blind" for the overall language design, imo.
I've been thinking about a way around this, and I'd be interested to see if comptime with a DSL wouldn't be too unwieldy. Something like
I know this is already possible with comptime, though I haven't implemented it yet since I haven't needed vector math in what I'm working on currently. Can't decide whether using math names is better or worse than using the full variable names though.I have a sibling comment -- having thought about this for a very very long time, zig should really implement binary pseudo-operator syntactic sugar. I don't think this violate zig's spirit of 'no hidden function calls' in that I don't think it takes much of a mental lift to "get" that (_ <+> _) means "heyo this is a function call, not a true operator".
At first I was going to say that I disagreed since you couldn't choose what implementation of addition you wanted, but now that I've read your comment where you import the type of addition used, it's growing on me. Would you have operator precedence, or would it be more like Smalltalk's binary operators?
forced use of parens, or else syntax error.
yes! i had this exact idea. i also thought about integrating geometric/clifford algebra using zig's type system so that you could have one mathematical multivector object instead of complex / quaternion types, etc.
That's the other great thing about using comptime, is you can specify which DSL you want to use for which scenario. You're not locked into one implementation.
All this just to prevent people from using + - * / and ^. Why?
Andrew talks about it because it introduces hidden control flow where you're expecting simple operators. In Zig anything that deals with control flow is a keyword (including short circuiting and, which is `and` instead of `&&`).
I'd argue though that the real disadvantage to having overloadable arithmetic is that you're limited to one implementation. This is actually my biggest beef with Rust, namely traits/type classes. It locks you into a single implementation when you may want to do something different based on the context. Zig pushes the dispatch decision to the callsite, not a trait subsystem (see how Zig implements hash mays for example). So I'd personally prefer to use a DSL, since it lets me specify what type of dispatch to use.
Overloadable operators are not an instance of hidden control flow. Overloadable operators represent a user-defined function call, and the body of an arbitrary function cannot do anything like return from the calling function or break out of a loop (as long as your language doesn't have exceptions, which Zig doesn't).
Why have operators at all?
Or in C vs For me the answer is very simple: Operators make it easier to read the code which makes it easier to spot bugs. It also makes it easier to turn formulas from textbooks into code.If 50% of the code you're working with is using vectors and matrices, not having operators for those parts is quite annoying.
Note that you can have vector operators without overloading, e.g. Odin has built in vector and matrix types.
But personally I think it's better to give the user more power instead of only letting the compiler author pick which types to allow operators on. Like how Java overloads + but only on the String class. Why do they get to do it, but not me?
Woah there, "=" is an operator! I'm afraid you're going to have to go to jail for using an operator in a no-operator zone.
you actually don't want "operator overloading", you want syntactic sugar. I once proposed just a special operator syntax at the parser level, but it got rejected, but if you REALLY wanted it, you could probably do this in about 100-120 lines as a fork of the zig compiler, just hacking (a <_> b) as a special form to be transformed into @"<_>"(a, b). Requiring parentheses elides questions about operator precedence.
> Why have operators at all?
I mean as an avid Lisp fan, I feel like Lisp basically answers the question of how much syntax you need in a langauge. I must admit though, not having to deal with operators precedence is really nice
Rust should (eventually) support arrays of structures via compile-time reflection: https://fnordig.de/2026/03/25/rust-reflection-and-a-multi-ar...
I didn't realize compile time reflection was back on track, that's really exciting!
Zig is adding native vectors including operator support, there are some recent issues/prs about this topic.
The general technique of SoA is pretty useful both in games and other applications, but of course I cannot speak to the specific use-case you are describing.
Zig vectors force data into SIMD registers even if that would make the code slower. They're a specialty type. You should only reach for vectors if you would have used SIMD intrinsics in C for example.
Zig vectors do not necessarily force data into SIMD registers; a scalar implementation would work equally well. This is not just a theoretical argument, because Zig code that uses `@Vector` also has to compile for architectures that do not have SIMD instructions.
That being said, the parent commenter is actually referring to other recent proposals as opposed to existing `@Vector` functionality:
https://codeberg.org/ziglang/zig/issues/32032
https://codeberg.org/ziglang/zig/issues/35376
Interesting, so zig might have both "vectors" and "vecs"? I guess naming is another thing to fix before 1.0 <g>
So is the argument that any SoA is pointless? Or just for GPU stuff? Because this isn't really talking about all that one way or another.
Also does one really need operator overloading? That feels a little strong. I've gotten by with functions just fine.. Does that make the GPU not like me Mr. wise engineer?
OT: I just spend a few minutes searching for the source of the "Not all CPU operations are created equal" slide of the linked presentation (Andrew Kelley - Practical DOD), its here:
https://6it.dev/blog/infographics-operation-costs-in-cpu-clo...
You URL seems KO, an alternative I found: https://x.com/chessMan786/status/1879092981892067383/photo/1
Hugged to death. Mirror: https://web.archive.org/web/20260608113005/https://andreasho...
Slightly related recent HN post: https://news.ycombinator.com/item?id=48382382
I'm just seeing a "410 Gone" error on the linked site (same happens to the parent URL too).
Works for me
Still the same. I guess it's some sort of wild anti-bot stuff basing on the user agent?
/edit
Yes, as confirmed with cURL, using my browser's "User Agent": 410 blocked. Using some other "User Agent" and it passes along the data. Pretty silly, IMHO.
This is what games do with ECS.
Jfpe?
Jdoemhoe