C++ and D programmers, like you (and Andrei), look down on Rust generics and give examples of all the things that you can't do with Rust generics that are easy to do with C++ templates. But there's an equally strong counterargument, in that Rust generics never give errors at template expansion time and are guaranteed to expand to valid code. This makes code easier to understand, improves the experience for users of your generics, and also simplifies the implementation, leading to potentially better compile times (since you typecheck once instead of after every template expansion). Of course, this is a tradeoff: it's more work for us to implement the features necessary to do the kinds of sophisticated metaprogramming you see in C++ and D, and there will always be some things you can't do in Rust that are easy in C++ and D. But that isn't a slam-dunk argument for untyped templates vs. typed generics any more than easy reflection is a slam-dunk argument for dynamic typing like Python vs. static typing like Java.
I think this demonstrates a significant weakness in Blub as a concept: there is not even a partial ordering of languages by power. The essay only works because Graham picks the two sides of the debate: Lisp, which Graham believes to be the most powerful of languages, and Blub, a theoretical language that can be stipulated to be less powerful than Lisp in all ways.
Outside the essay, "blub" only exists as a slur for a despised language or an insult for another programmer, and it's only useful as a way to start arguments.
> In this regards, Rust is actually the Blub
I'm not so sure. We are aware of the features that they have; we just prefer the strongly-typed versions to the stringly-typed[1] versions.We do desire more meta-programming features, and they will happen. Like all decisions, we don't want to rush into them.
1: This is not _entirely_ accurate, but I'm slightly at a loss for how to exactly characterize this at this particular moment. Rust's metaprogramming guarantees that you always generate valid Rust code, D's does not.
With regards to Rust, do you have any idea when more meta-programming features like variadics and non-type template parameters might be available in the language (are we looking at months, years, or decades)? Rust, has a lot of features that really interest me, but seeing the tuple serialization code brought back bad nightmares of simulating variadic templates using macros in C++ before I had a compiler that supported C++11 variadics. To me, at least personally, it felt like a step backward from C++14, and kind of curtailed my enthusiasm for doing a deep dive into the language. My test for the power of a language's type manipulation is how easy is it to write an implementation of apply(Function f, Tuple t) which will call f with the values of t. I would be most interested to see how Rust will implement this kind of metaprogramming.
It's hard to say because the work for those features hasn't even been started; the MIR refactoring is still underway. Once that's done, RFCs for this stuff will start to appear, and we'll have a better idea of overall schedule. I would say that the current schedule is "longer than months, shorter than a few years".
I myself _really_ want higher kinded types, but at the same time, I would rather wait and do it right than rush and regret thing slater. We have a solid language as it is; the need to get these more advanced features is not particularly urgent, in my opinion. I like to think on the long scale when it comes to the language: if it's going to be around 40 or 50 years, we're in year one. There's plenty of time.
That's kind of a weird litmus test of the power of the language's type manipulation: it only applies to languages where functions take multiple arguments, it's a pretty niche use case (since the workaround in Rust is straightforward), and there's nothing particularly sophisticated about variadic generics (what you need to solve the problem). I could equally say that my litmus test of a language's generics system is whether the compiler prevents errors during template expansion.
Anyway, to answer your question: that's really easy in Rust, as long as you're on nightly. The FnMut trait (and friends) allow you to call functions with tuples as arguments. https://doc.rust-lang.org/std/ops/trait.FnMut.html
(this could easily be a stupid question; I know I've come across as condescending to you before by mistake and if I've somehow done it again please believe that I meant to come across as genuinely curious :)
- They make namespacing of functions easier, eliminating the need for C++'s "argument-dependent lookup". The issues here are somewhat subtle and would take a lot of space to explain. But the end result is that we can remove a massive amount of confusion by getting rid of ADL.
- Error messages are much better, because the insides of templates never leak to users of the template.
- Typechecking is simplified, because we only have to typecheck each template once, at the time of definition, as opposed to repeatedly typechecking it from scratch every time it's instantiated. This, in theory, allows compilation to be faster.
This is unequivocally a good thing - I think maybe my disconnect here in how excited I am compared to others is that I'm comparing it to the experience of debugging lisp macros and everybody else is comparing it to the bottomless pit of despair that is C++ template errors ;)
Yes, to me, it's largely about better errors and such. If th generated code is wrong, it won't compile, so it's not _that_ level of bad. But this can't happen in Rust: http://tgceec.tumblr.com/
There's also the danger of something compiling where it shouldn't.
Part of being a Blub programmer is that you don't even think about the issues. In regards to the weird features brought up, the underlying issues behind these features have been in the C++ consciousness for some time. Below are some talks and resources covering at least some of these issues.
Sean Parent - Inheritance is the Base Class of Evil - https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&c...
Herb Sutter - You don't know const and mutable - http://herbsutter.com/2013/01/01/video-you-dont-know-const-a...
Andrei Alexandrescu - Systematic error handling in C++ - https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012...
Herb Sutter - Writing Good C++ by Default - https://www.youtube.com/watch?v=hEx5DNLWGgA
Andrew Sutton - Generic Programming with Concepts Lite - https://www.youtube.com/watch?v=qwXq5MqY2ZA
One of the things that helps with avoiding "Blubness" in C++ is the significant interest in languages such as Haskel (which is not considered a Blub language by anyone except Agda programmers) and in applying the techniques and insights where possible to C++ whether through writing new libraries (see for example Fit by Paul Fultz II -https://github.com/pfultz2/Fit) or through new language features (see this post by David Sankel - http://davidsankel.com/uncategorized/c-language-support-for-...)
Finally, is also interesting that Paul Graham's blub paradox is being brought up in regards to Rust, C++, and D. The Paul Graham article is in large part talking about the power of meta-programming. In this regard, D and C++ are significantly more powerful in that regard. Features like higher kinded types (template templates), variadics, and non-type template parameters help in this matter. When you can write a function that can generically work with a tuple with any number and type of parameters, you can do some pretty neat stuff. For some examples take a look at Boost.Hana by Louis Dionne (http://boostorg.github.io/hana/). In this regards, Rust is actually the Blub compared to D and C++.