Having to define these operators as functions with unique text names is extremely ugly and serves no purpose that I can see.
Something like this could actually fulfill Andrews goal of not having any hidden control flow, as the function would be plainly visible.
The other thing of course would be, what then the valid function names would be? Definitely not `*` but probably `×` or whatever.
Haskell.
const @"..." = @import("my_operator.zig").add;
For example. Then in the code the parser transforms (a ... b)
to @"..."(a, b) vec4 c = a * 4 + b;
instead of vec4 c = vec4_add(vec4_mul(a, 4), b);
i.e. infix vs postfix order, with simple * and +/- operators etc. I would very much like to appeal to the Zig authors to see the beauty in the former expression compared to the latter, for a huge class of real-world mathematical applications.vec4 c = a * 4 + b;
vec4 c = vec4_add(vec4_mul(a, 4), b);
vec4 c = vec4_fma(4, a, b);
Another possible route is to require that all types contained within the exported types are also numerical, or have some specific set of operators defined.
Also, you mentioned matrices in the previous comment, but multiplication between matrices is not commutative.
New types also don't have to inherit the properties of the operators they use.
In any case, my point was that there are multiple avenues to explore in providing operators in a way that don't compromise the compiler's ability to optimize numerical code.
- hidden control flow (function calls should look like function calls, an operation should never mask a function call)
- global weirdness. If a library changes the language, how does that affect some other code you're pulling in? Where do you effect those changes?
https://godbolt.org/z/ccYPaz1Pj
For this example (AVR), this is the int multiply function __mulhi3:
00: 00 24 eor r0, r0
02: 55 27 eor r21, r21
04: 00 c0 rjmp .+0
06: 08 0e add r0, r24
08: 59 1f adc r21, r25
0a: 88 0f add r24, r24
0c: 99 1f adc r25, r25
0e: 00 97 sbiw r24, 0x00
10: 01 f0 breq .+0
12: 76 95 lsr r23
14: 67 95 ror r22
16: 00 f0 brcs .+0
18: 71 05 cpc r23, r1
1a: 01 f4 brne .+0
1c: 80 2d mov r24, r0
1e: 95 2f mov r25, r21
20: 08 95 retAn operator is either a function call or some simple built-in operation.
Thus not hidden.
That syntactic elements that consist of symbols rather than alnum and that are used as prefix or infix operators are necessarily “not a function call” is just a rule that can be changed.
In theory, yes. In practice, an operator is a simple built-in operation 99.999% of the time, which lures programmers into thinking that's how it always is.
It's like a self-driving car that's safe 99.999% of the time but still requires you to continuously pay attention to take over at a second's notice.
Humans just don't work like that.
Noo it isn’t. Many languages use something like `+` for string concatenation. Maybe list concatenation.
You can restrict operator definitions to expressions containing other operators. Operators are now guaranteed to expose only as much control flow as the underlying operators would already expose.
> - global weirdness. If a library changes the language, how does that affect some other code you're pulling in? Where do you effect those changes?
I'm not sure what you mean. Behaviour depends on language semantics. You don't specify why operators are uniquely weird on this compared to literally any other function call when language semantics or library behaviour changes.
In any case, if something practical is done here I'd be interested. Aesthetically I prefer the "vectors and matrices are first class types" (and maybe complex numbers could be too), but I guess Andrew isn't so sympathetic to these types being part of the standard language :/
Vectors are already first-class types via @Vector, aren't they?
I'll hope for some future news of Zig having vector and complex number support! It will be a great day for fast ray/path tracers :)
It ends up slightly more verbose in usage, but the statements themselves remain concise. Unfortunately I got a real job that isn't using Zig, so I've stopped working on this. Others can feel free to take up the torch, though.
It would be nice, for sure, to be able to define some infix combinators.
Anyway, it’s bad enough that arithmetic has pressured almost all programming languages to adopt operator precedence. (No operator precedence other than either go-left or go-right is so much simpler. Which would also mitigate some of the complaining about custom operators since then they just become infix functions.)
I think the major problem here is shoehorning everything into a “symbol soup” on a 2D matrix. I do get that it has plenty advantages (can be typed without special program, easier version control, etc), but I would like to see a resurrection of interest in visual language. I’m not meaning something as visual as scratch or so, but some special blocks could come in handy.
Actually, I don't even want operator overloading in general (leading to stuff like the C++ stream API), it's JUST for vector stuff (ideally with swizzles); same for all the shading languages.
Perhaps it's doable to make a little domain-specific language (DSL) in Zig for this purpose?
With vector extensions (and as floh [hi!] points out, also matrices please) I'm 100% ready seriously consider transitioning from C++, given the smooth C integration.