-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MathType for scope limited operator overloading #8567
Comments
I think something like this is worth considering, as it would make a lot of graphics processing code (among other things) much nicer looking. However, an additional restriction that one might have to accept is that But even with this additional restriction, I think this proposal could have a very good power-to-weight ratio. Fixed-sized vectors and matrices are used all over the place, as the popularity of #7295 attests, but I always felt a bit queasy about hard-coding such functionality into the language. Also, xref #7157. |
Related issue recently discussed in a spec meeting and ultimately rejected. I would assume a new proposal in the same ballpark would need to argue that the two proposals are different enough (i.e. the reasoning that caused the original proposal to be rejected does not apply to the current one). |
This would be a significantly more complicated feature than infix functions. While I don't have a 100% concrete proposal to present, here are some of the things that will probably be needed:
As @zzyxyzz suggest, this feature would be easiest to implement if we restrict math types to having a known size at compile time and this would cover the majority of use cases. We may be able to support dynamically sized math types at run time, but it would be more complex, need new ideas and I'm not sure it would be worth it. Another list of ideas for this:
I personally have not written many programs where I need dynamically sized math types in non-garbage collected languages, so I'm not sure what the typical needs are for these use cases. So feel free to comment if you have better ideas. Even if no explicit support for dynamically sized math types is added, a crafty individual may decide to construct such a system as the one I outlined above using a Isn't this proposal complicated?I acknowledge that this will be quite a complicated feature to get right. However, if this proposal is ultimately rejected, then zig needs to figure out how its going to tackle the problems I outlined in my original post. If zig keeps adding primitives for every hardware feature under the sun, its going to turn into another "kitchen sink" language. |
I can not find anything about matrices in the issue. Can you link this please?
vector and matrices are no hardware features. They also need significant effort to optimize and error messages, so most/all? languages put them into libraries. "architecture specific math hardware" is not yet under discussion and likely requires hooks into std for architecture-specific stuff to be existent, since there are too many (ie special crypto stuff). "fixed point math" could also be implemented as library, since the user must define the layout (besides size) anyway. Same goes for "complex numbers". "quaternions" same, since they are quite abit more complex. "floating point formats besides the built-in ones" are not typical use cases and I also dont hear an argument why these cant be implemented in a library. Since they must be created from specific size arguments, this is a very strong argument not to make an own type. "big int types" are already in stdlib, so that one is wrong. My standpoint is that everything, which is more than 1 type to define the element does not belong into the compiler. If it is sufficient simple to do efficient, it can go into stdlib. I would expect complex numbers to be defined as comptime generated struct of 2 numbers with type and not inbuild compiler type.
I dont like putting types behind indirection, if the element is defineable with exactly 1 type without length (common use case). |
Sorry, the proposal with strong support only suggest adding vectors. I made this statement because languages like glsl let you define matrices like
I consider
I'm not suggesting floats get moved, that's why I said theoretically. I just wanted to emphasize that this would aim to be a flexible solution that could support a wide variety use cases. Yes, many of the use cases I outline are not under serious consideration. However, some of them seem to be, that's why I wanted to present a generalized solution to the problem that does not favor specific use cases over others. My interpretation of zig's philosophical ideas and what's a core feature is of course subjective. I may simply be in the minority in seeing things this way. And that's okay, it's unrealistic to expect zig to cater to the whims of every user if it brings unwanted complexity to the majority of users. |
Ultimately, this issue boils down to "add operator overloading but work out the problems people have with it". I personally do not have the energy and motivation to see this through from conceptualization to implementation, so it's rude of me to expect others to do this for me. As operator overloading has been rejected in various forms in the past, I'm not sure I can provided a compelling enough argument or enough innovation over anything else that has already been presented. As a result I'm going to close this issue for now. I don't want to waste the zig's devs time discussing something they have rejected for the nth time just with a different coat of paint. Sorry to the people who are supportive of this, but I really don't want to waste mine or anyone else time here. If the zig dev's are still open to the idea of operator overloading and think it's issues may still be solveable, feel free to reopen this issue. Otherwise it's probably best for everybody's use of time that this issue remains closed for the time being. |
Proposal Summary
Add a new way to define math types that have limited access to overloading arithmetic operators. The
MathType
would be similar to a struct except it would be allowed to overload arithmetic operators as long as both parameters are alsoMathType
.I don't want to start discussing implementation details in depth yet so the specifics and syntax are all placeholder. Instead I want to focus on discussing why I think it is worthy of consideration even though zig values no hidden control flow. Specifically I think zig is already beginning to compromising on some of its design goals by trying to workaround the lack of operator overloading.
The problem
What we want to solve
There are many different math types that we want to be able to use conveniently in our programs, some of the most common ones:
c_longdouble
might get you this, but it's not portable across platforms or C compilers))The situation is further complicated by the fact that these types are often composed of each other. For example, the elements of vector and matrix are scalar types (integers, real, complex) which in turn need a representation for the given application/platform (eg: i32, fixed point, floating point).
There are already several different proposals to add some of these types to the language to different degrees:
x < y
should be valid for simd vector but not a math (Euclidean) vector)The simple solution to the problem
The most straight forward solution to this problem is to implement these types through
struct
and function call interface.Pros:
Cons:
f32
with fixed point type) you need to rewrite all your equations with the equivalent function calls and hope you don't mess anything up. Then if you still want to be able to use the inbuilt type you have to work support for it into your interface too.x + y
,x.add(y)
,x.plus(y)
,add(x, y)
, how are errors handled?). This means it's not really feasible to mix math types from different libraries. If you had a custom floating point type you wanted to use inside a matrix library you may be forced to rewrite one or both of these libraries.Currently zig does not seem to be adopting this approach fully, instead it's taking a mixed approach.
Current status quo solution: add more builtin types
For many of disadvantages listed above, zig wants to have these math types use operators the same way as primitive types. Zig doesn't allow operator overloading, however built-in types are allowed to overload arithmetic operators. So the current solution seems to be add more built-in types, for example:
For several reasons I don't like this approach and think it does not align with many of zig's goals in trying to be a C replacement.
It makes the language big. I think one of the biggest appeals of C is that it's small. That is the core feature set is stuff that's basically universal to all programs and architectures. While useful, I don't think these math types deserve a place as core types in the language. I think it's much more elegant to introduce one feature, the
MathType
, instead of adding a dozen more core types. I'm not saying zig shouldn't add these as part of its standard library, but that they don't deserve language@builtins
and special syntax like many of the proposals I linked above might suggest.It is inflexible and arbitrary. Unless zig adds all these math types in their most general form (which would only exasperate my first point), it's going to end up favoring some architectures and applications. For example embedded programmers are probably going to be the primary users of fixed-point math and rarely use any of the other math types I listed. Conversely, desktop programmers rarely need fixed point math but will heavily use floating point, vector and matrix types.
Even if the math type you need is support, if for whatever reason the implementation doesn't work how you need it, then the replacement that you write does not have the privilege of operator overloading like the built-in type. See this great comment discussing the implementation fixed points, from this it is easy to see how a built in type could be unsatisfactory given all the implementation details you need to consider.
What's the criteria for a builtin type in zig? Having an llvm intrinsic seems too arbitrary to me.
It makes the language harder to implement. The more complex the primitive types are, the harder it will be to port zig to alternative architectures. For zig to be a serious C replacement for me, it needs to be supported everywhere. For it to be supported everywhere it needs to be easy to write a zig compiler. I fear many design decisions in zig may be too llvm centric. Things often seem to get added because llvm make it easy, but I don't see it ask very often how hard it would be to implement without llvm or for architectures that llvm does not support. So support for alternative architectures may choose to omit core types, or even worse just never get written.
One place C is uncontested is small embedded microcontrollers. These micros are the stuff you find inside sd cards, micros that cost $0.03, or various other platforms. Is this an arena zig wants to compete in or is it only focused on higher performance targets? If zig wants to compete here, it needs to be as easy as possible to write a zig compiler for these architectures.
Has many of the disadvantages of operator overloading anyway. Without operator overloading you can be pretty confident that
x * y
is a relatively simple operation. However, with zig adding more and more built-in types this is no longer the case. For example if zig would allow you to define matrix types of dimensionn
, then this multiplication could be potential beO(n³)
(depending on the algorithm). It also changes the semantics of these operators:x * y != y * x
. If you truly want to understand what's happening, you have to hunt down where the type is define which is the same thing for operator overloading. In fact, I think explicit operator overloading syntax with aMathType
would be better because the implementation is just library code, as opposed to built-in types were the implementation details may be hidden away.In a way hidden control flow exists even for types like
f32
. If my platform doesn't have hardware floating point, thenx * y
is really going to be a function call anyway__float32_mul(x, y)
. It's not like the compiler can inline hundreds of opcodes every time there's a basic floating point operation.It may simply be I have misunderstood what zig aims to be and these are considered acceptable trade offs. Or maybe platforms like 8051 are considered too niche for zig, so it doesn't matter that they are difficult to support or that zig's feature set does not represent their hardware well. Zig is still a fine language if it can only support llvm targets, but zig looses a lot of its appeal as a C replacement to me if that's the case.
Why I think a MathType would be a good solution
MathType
, you restrict its reach on what types can use overloading. Stuff likestd::cout << "hello world"
would not be possible because string literals are notMathType
.Postscript
Sorry for writing so much. Half of this issues isn't so much about operator overloading itself, but asking why zig is adding ISA types like simd vectors to the language when I think it should be focusing on keeping the core language as small and architecture agnostic as possible.
The text was updated successfully, but these errors were encountered: