4 ms·
I cant think of a single real use case for variadic generics. When you're talking about functions operating on mixed, variable length, types, what meaningful l
by BobbyJo 3y ago
I cant think of a single real use case for variadic generics.
When you're talking about functions operating on mixed, variable length, types, what meaningful logic can you actually apply, that doesn't fall into requiring the types to implement an interface anyway?
When you're talking about struct/classes/etc, what do you need over and above defining a class/record/dataclass? It would seem to me, you're just skipping the part where you give your tuple a name, but is that even a good idea to do?
To be clear, I did not find the examples in the post convincing, as they represent mostly wrappers/adapters for implementing or consuming arbitrary types, but there are no examples for how that might actually be useful downstream.
- oddlama 3y agoI can think of plenty real world usecases. Take for example a network interface that can send or receive predefined packet structs. Imagine each packet requires a size header. When you want to send multiple packets at once, you now want to optimize that and only write a single initial header to the interface, preceding the data. With variadic generics, you can enable a syntax like `interface.write_packets(packet1, packet2, packet3, /* ... */);` which writes the packets in the desired optimized way. It can internally construct a serializable data tuple from the variadic generics and add the correct header only to the beginning. Without variadic generics a similar syntax is only possible with macros, which means that it cannot be implemented as a reusable trait. > It would seem to me, you're just skipping the part where you give your tuple a name, but is that even a good idea to do? Sometimes you explicitly don't want to require naming the tuple for flexibility, like in the example above.
- paulddraper 3y ago!!! Consider having multiple (heterogenous) Promises and wanting to wait for all to complete, and return the results.
- norir 3y ago> I cant think of a single real use case for variadic generics. Even if you could think of one, I personally think the rust community does a poor job of weighing the tradeoff between supporting a niche feature and adding complexity to the language. Rust is already so huge that all but the most dedicated have little hope of understanding even half of the language features. I'm not sure I understand the incentive structure that makes it this way, but it is hard for me to see how rust avoids becoming the next c++ unless they learn how to say no. Honestly I believe it's already too late and that rust's best ideas will be adopted by a smaller language with better ergonomics, compiler performance and learnability that will eat its lunch.
- Georgelemental 3y agoThe status quo is that people who would like to use variadics but can't, instead settle for complicated ad-hoc macros. Those are far worse for "ergonomics, compiler performance and learnability."
- MrBuddyCasino 3y agoInstead of extending the language with ever more niche features, they could pull a Zig and make macros not suck.
- SkiFire13 3y agoZig's `comptime` is not a silver bullet though: - it is duck typed, which to be fair macros are also, but variadic generics would be type checked at the definition; - it interacts badly with traits, that is if you allow both querying for implemented traits and creating new trait `impl`s then this can create cycles in the execution of comptime blocks, meaning the compiler needs to compute a fixpoint or arbitrarily give an error.
- Georgelemental 3y agoAlso, Rust has lifetimes which are erased prior to monomorphisation—so specializing based on them is unsound. Any `comptime` equivalent in Rust would have to limit the access of `comptime` blocks to lifetime information in some way.
- jandrewrogers 3y agoI think the utility is strongly dependent on the kind of code you write and the sophistication of the metaprogramming your code will benefit from. Many C++ programmers made similar comments when it was introduced with C++11 and a few still maintain it has no real use case. However, for C++ library writers it was a game changer. In practice, they replace a lot of use cases for code generators. It took me a while to get into variadic generics, but now that I understand them I would feel crippled using a language without them. A lot of the value is to derive complex structs programmatically that may never be realized concretely but feed other metaprogramming algorithms that slice and dice them and make decisions based on the properties of the individual types. You don’t want to name them because (1) there may be hundreds from an unbounded set and (2) your may never need to reference them directly, so it saves a mountain of code and eliminates a massive amount of edge cases. At their best, you can use them to express insanely complex things with surprisingly little code. It is not the kind of feature you use profligately in a code base. But when you need them, you really need them. Most of what they can express in ordinary code would otherwise require complex code generators, compiler magic, or outrageous amounts of boilerplate.
- amluto 3y agoI used variadic templates to implement, drumroll please, a variant library that wasn’t as awful as what came before. Rust has enums, which are so much better it isn’t even funny.
- lmm 3y ago> When you're talking about functions operating on mixed, variable length, types, what meaningful logic can you actually apply, that doesn't fall into requiring the types to implement an interface anyway? Anything higher-order. At the most basic level you want to be able to take a bundle of values and a bundle of functions and apply the functions to the values, or take a bundle of functions and another bundle of functions and make a bundle of composed functions. You will probably complain that these examples are trivial, but if we don't have the syntax or vocabulary to handle the trivial cases then how can we even start to think about the more complex cases? > When you're talking about struct/classes/etc, what do you need over and above defining a class/record/dataclass? It would seem to me, you're just skipping the part where you give your tuple a name, but is that even a good idea to do? It is, if only because you want to be able to transform existing records generically rather than having to concretely write out every specialised possible version of your record. For example, think of writing a generic "patch" method for use in the "update" route of a CRUD webservice - something that lets you call it with an existing record (e.g. a user) and some representation of a few deeply nested fields of that record (e.g. the postal code that's on that user's address) and get an updated version of the record, without having to write out the type for that "patch" input longhand. This is a basic, trivial thing that people do in TypeScript every day, but you still can't even write a type for it in Rust, yet alone implement it.
- Georgelemental 3y agoFrom the post: > I think variadics aren’t necessarily useful for application developers, or people working on libraries with mostly concrete types (eg web libraries). But for people working on libraries with lots of type manipulation, variadic generics have obvious benefits. They let you go from manipulating types to collections of types. One example is in SQL libraries. If you have a trait `DatabaseColumnStorable` for types you can store in a database column (integers, strings, etc), then with variadics you could have a `struct DatabaseRow<...Columns: DatabaseColumnStorable>(...Columns)` to represent rows of a database table in a type-safe manner.
- Ygg2 3y agoAny time you see traits going impl Trait for (T1) impl Trait for (T1, T2) impl Trait for (T1, T2, T3) ... And bunch of macro invocations in the body on (T1), (T1, T2), etc. Someone, somewhere cursed there weren't variadics there.
- kolektiv 3y agoI'm writing a library at the moment with exactly this kind of issue (not quite that formulation, but morally equivalent). The whole thing would be a lot simpler (and remove the need for procedural macros to generate all of the types and impls) with variadic generics. Would I use variadic generics regularly? Probably not. But in places where they'd be useful - boy, would they really be useful!
- dathinab 3y agoalso some probably isn't good at using macros because you can make that a single macro which kinda is a bit like variadics. Through it still is limited to some specific number of your size (typical 16 or 32). Anyway not having varadic generics by itself is in most cases just a small inconvenience with limited benefits and there are many far more important priorities IMHO. The main benefit for varadic generics is that they might unblock some other improvements on top of them.
- SkiFire13 3y agoFor a quick example, Bevy needs to implement some trait for functions with a variable number of inputs. However it doesn't stop there, it also needs to store some state for each input, in other words it need to map that `fn(...T)` into a `(...State<T>)`. How do you model this with generics? When I tried to think about this every way I found to express this didn't allow the consumer code to call any methods on those `State`s, essentially making this useless.
- jcelerier 3y agoIn https://GitHub.com/celtera/avendish https://GitHub.com/celtera/avendish it's used to do operations on (heterogeneous) I/O ports of data flow objects (simply represented by variables of basic types.. float, int, string, etc.). This library would be entirely impossible in c++ without that feature.
- nicoburns 3y agoWith variadics the types would still implement an interface, they just allow you to work with those types t compile time rather than type-erasing them into a dynamic trait object.