5 ms·
I don’t understand this “next evolution” approach to language design. It should be done at some point. People can always develop languages with more or less th
by ozgrakkurt 7mo ago
I don’t understand this “next evolution” approach to language design.
It should be done at some point. People can always develop languages with more or less things but piling more things on is just not that useful.
It sounds cool in the minds of people that are designing these things but it is just not that useful. Rust is in the same situation of adding endless crap that is just not that useful.
Specifically about this feature, people can just use asserts. Piling things onto the type system of C++ is never going to be that useful since it is not designed to be a type system like Rust's type system. Any improvement gained is not worth piling on more things.
Feels like people that push stuff do it because "it is just what they do".
- jandrewrogers 7mo agoMany of the recent C++ standards have been focused on expanding and cleaning up its powerful compile-time and metaprogramming capabilities, which it initially inherited by accident decades ago. It is difficult to overstate just how important these features are for high-performance and high-reliability systems software. These features greatly expand the kinds of safety guarantees that are possible to automate and the performance optimizations that are practical. Without it, software is much more brittle. This isn’t an academic exercise; it greatly reduces the amount of code and greatly increases safety. The performance benefits are nice but that is more on the margin. One of the biggest knocks against Rust as a systems programming language is that it has weak compile-time and metaprogramming capabilities compared to Zig and C++.
- jesse__ 7mo ago> powerful compile-time and metaprogramming capabilities While I agree that, generally, compile time metaprogramming is a tremendously powerful tool, the C++ template metaprogramming implementation is hilariously bad. Why, for example, is printing the source-code text of an enum value so goddamn hard? Why can I not just loop over the members of a class? How would I generate debug vis or serialization code with a normal-ish looking function call (spoiler, you can't, see cap'n proto, protobuf, flatbuffers, any automated dearimgui generator) These things are incredibly basic and C++ just completely shits all over itself when you try to do them with templates
- logicchains 7mo agoDid you read the article? This is called reflection, and is exactly what C++26 introduces.
- jesse__ 7mo agoYeah, like 50 years too late.
- Conscat 7mo ago> Why, for example, is printing the source-code text of an enum value so goddamn hard? Aside from this being trivial in C++26, imo it isn't actually that tricky. Here's a very quick implementation I made awhile ago: https://github.com/Cons-Cat/libCat/blob/3f54e47f0ed182771fce8d0a80366ce63adb36fc/src/libraries/enum/cat/enum#L37 https://github.com/Cons-Cat/libCat/blob/3f54e47f0ed182771fce...
- jesse__ 7mo ago> Aside from this being trivial in C++26 Great, it took them 51 years to make a trivial operation trivial. Call me next millennium when they start to figure out the nontrivial stuff, I guess.
- rienbdj 7mo ago> One of the biggest knocks against Rust as a systems programming language is that it has weak compile-time and metaprogramming capabilities compared to Zig and C++. Aren’t Rust macros more powerful than C++ template metaprogramming in practice?
- tialaramex 7mo agoRust has two separate macro systems. It has declarative "by example" macros which are a nicer way to write the sort of things where you show an intern this function for u8 and ask them to create seven more just like it except for i8, u16, i16, u32, i32, u64, i64. Unlike the C pre-processor these macros understand how loops work (sort of) and what types are, and so on, and they have some hygiene features which make them less likely to cause mayhem. Declarative macros deliberately don't share Rust's syntax because they are macros for Rust so if they shared the same syntax everything you do is escape upon escape sequence as you want the macro to emit a loop but not loop itself etc. But other than the syntax they are pretty friendly, a one day Rust bootstrap course should probably cover these macros at least enough that you don't use copy-paste to make those seven functions by hand. However the powerful feature you're thinking of is procedural or "proc" macros and those are a very different beast. The proc macros are effectively compiler plugins, when the compiler sees we invoked the proc macro, it just runs that code, natively. So in that sense these are certainly more powerful, they can for example install Python, "Oh, you don't have Python, but I'm a proc macro for running Python, I'll just install it...". Mara wrote several "joke" proc macros which show off how dangerous/ powerful it is, you should not use these, but one of them for example switches to the "nightly" Rust compiler and then seamlessly compiles parts of your software which don't work in stable Rust...
- menaerus 7mo agoNo, they are not.
- aldanor 7mo agoIncorrect.
- sidkshatriya 7mo agoOne of the biggest knocks against Rust as a systems programming language is that it has weak compile-time and metaprogramming capabilities compared to Zig and C++ In the space of language design, everything "more powerful" is not necessary good. Sometimes less power is better because it leads to more optimisable code, less implementation complexity, less abstraction, better LSP support. TL;DR More flexibility and complexity is not always good. Though I would also challenge the fact that Rust's metaprogramming model is "not powerful enough". I think it can be.
- germandiago 7mo agoBut compile-time processing is certainly useful in a performance-oriented language. And not only for performance but also for thread safety (eliminates initialization races, for example, for non-trivial objects). Rust is just less powerful. For example you cannot design something that comes evwn close to expression templates libraries.
- aw1621107 7mo ago> For example you cannot design something that comes evwn close to expression templates libraries. You keep saying this and it's still wrong. Rust is quite capable of expression templates, as its iterator adapters prove. What it isn't capable of (yet) is specialization, which is an orthogonal feature.
- Conscat 7mo agoRust cannot take a const function and evaluate that into the argument of a const generic or a proc macro. As far as I can tell, the reasons are deeply fundamental to the architecture of rustc. It's difficult to express HOW FUNDAMENTAL this is to strongly typed zero overhead abstractions, and we see where Rust is lacking here in cases like `Option` and bitset implementations.
- aw1621107 7mo ago> Rust cannot take a const function and evaluate that into the argument of a const generic Assuming I'm interpreting what you're saying here correctly, this seems wrong? For example, this compiles [0]: const fn foo(n: usize) -> usize { n + 1 } fn bar<const N: usize>() -> usize { N + 1 } pub fn baz() -> usize { bar::<{foo(0)}>() } In any case, I'm a little confused how this is relevant to what I said? [0]: https://rust.godbolt.org/z/rrE1Wrx36 https://rust.godbolt.org/z/rrE1Wrx36
- dbdr 7mo agoWhat "endless crap that is just not that useful" has been added to Rust in your opinion?
- ozgrakkurt 7mo agoreturning "impl Trait". async/await unpin/pin/waker. catch_unwind. procedural macros. "auto impl trait for type that implements other trait". I understand some of these kinds of features are because Rust is Rust but it still feels useless to learn. I'm not following rust development since about 2 years so don't know what the newest things are.
- tialaramex 7mo agoRPIT (Return Position impl Trait) is Rust's spelling of existential types. That is, the compiler knows what we return (it has certain properties) but we didn't name it (we won't tell you what exactly it is), this can be for two reasons: 1. We didn't want to give the thing we're returning a name, it does have one, but we want that to be an implementation detail. In comparison the Rust stdlib's iterator functions all return specific named Iterators, e.g. the split method on strings returns a type actually named Split, with a remainder() function so you can stop and just get "everything else" from that function. That's an exhausting maintenance burden, if your library has some internal data structures whose values aren't really important or are unstable this allows you to duck out of all the extra documentation work, just say "It's an Iterator" with RPIT. 2. We literally cannot name this type, there's no agreed spelling for it. For example if you return a lambda its type does not have a name (in Rust or in C++) but this is a perfectly reasonable thing to want to do, just impossible without RPIT. Blanket trait implementations ("auto impl trait for type that implements other trait") are an important convenience for conversions. If somebody wrote a From implementation then you get the analogous Into, TryFrom and even TryInto all provided because of this feature. You could write them, but it'd be tedious and error prone, so the machine does it for you.
- ozgrakkurt 7mo agoLike you said it is possible to not use this feature and it arguably creates better code. It is the right tradeoff to write those structs for libraries that absolutely have to avoid dynamic dispatch. In other cases it is better to give a trait object. A lambda is essentially a struct with a method so it is the same. I understand about auto trait impl and agree but it is still annoying to me