4 ms·
The ergonomics of this are really bad without some kind of implicit parameters and trait resolution. Without trait methods, ad-hoc overloading becomes impossibl
by twanvl 4y ago
The ergonomics of this are really bad without some kind of implicit parameters and trait resolution. Without trait methods, ad-hoc overloading becomes impossible.
You would have to explicitly specify what + operator and what == operator you use everywhere. After all, there could be multiple different additions or comparisons defined for a type, so which one do you mean by `+`?
Another problem is that a data structure's invariant can depend on the trait implementation. For example a tree is balanced with a comparison. This means that the comparison has to be stored in the struct, with the corresponding runtime overhead. With traits you know that there is only a single implementation for any particular type, so if the trait v-table is an argument to every method call there is no risk of different implementations being used at different times.
- zozbot234 4y ago> This means that the comparison has to be stored in the struct, with the corresponding runtime overhead. The runtime overhead is solvable in principle by making the comparison a const-generic parameter of the data structure type. But to do this properly requires dependent types, because the type of that const-generic parameter is taken from an earlier parameter in the same definition. It's a dependent sum type, sometimes called a dependent record.
- nyanpasu64 4y agoFrom my understanding, compile-time dependent types (which is all that's needed to mimic statically dispatched generics) are easy, and C++ templates support them (I haven't tried Rust const generics but I hear they're quite limited). Runtime dependent types are much less common, and (given my limited understanding of dependent types) I could describe trait objects (&dyn Trait) as a dependent pair (ptr, Trait-shaped vtable containing *fn taking ptr's type) (though rustc hard-codes support for trait objects, and its job is easier since it never lets ptr change runtime type while its target is used for a &dyn Trait).
- tialaramex 4y agoRust's const generics today are limited to the built-in integral types (so, char, bool, and the various sizes of signed or unsigned integer) and the constant must actually be an obvious constant, so e.g. a literal, or something you could assign to a const in Rust. So yes that's much less flexible than C++. Some of the flexibility in C++ here is desirable, much of it is either wanking or outright dangerous. C++ will allow a float generic for example, which is obviously a footgun because good luck explaining why Thing<NaN> and Thing<NaN> are different types... Rust expects to sooner or later ship Const generics for user-defined types, but to exclude the nonsense of "float generic" the likely rule goes like this: Your const parameter type must derive PartialEq and Eq. It won't be enough to implement them yourself as your implementation might be nonsense (e.g. misfortunate::Maxwell implements Eq but no Maxwell is equal to anything, including itself) you'll need to use the derive macro which promises the compiler these things actually have working equivalence so that Thing<A> and Thing<B> are the same type if A and B are equivalent.
- logicchains 4y ago>Some of the flexibility in C++ here is desirable, much of it is either wanking or outright dangerous. C++ will allow a float generic for example, which is obviously a footgun because good luck explaining why Thing<NaN> and Thing<NaN> are different types... It's not nonsense, there are legitimate use-cases for floating point template params. A classic example is something like generateInlinedVersionOfFunction<someInt, someFloat>() that generates a class or function with some particular values inlined for efficiency. Using nan as a template parameter is stupid, but it's not especially more dangerous than using nan in general, since any issues specific to its compile-time usage will manifest at compile time, not runtime. It does nobody any favours to just dismiss advanced features Rust doesn't support as dangerous and unnecessary just because most Rust programmers haven't come across a use-case.
- Asooka 4y agoCan't you do that in Rust with a macro?
- 4y ago