← Back to context

Comment by aw1621107

4 hours 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.

Rust 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.

  • > 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

> Rust is quite capable of expression templates, as its iterator adapters prove.

AFAIU iterator adapters are not quite what expression templates are because they rely on the compiler optimizations rather than the built-in feature of the language, which enable you to do this without relying on the compiler pipeline.

  • I had always thought expression templates at the very least needed the optimizer to inline/flatten the tree of function calls that are built up. For instance, for something like x + y * z I'd expect an expression template type like sum<vector, product<vector, vector>> where sum would effectively have:

        vector l;
        product& r;
        auto operator[](size_t i) {
            return l[i] + r[i];
        }
    

    And then product<vector, vector> would effectively have:

        vector l;
        vector r;
        auto operator[](size_t i) {
            return l[i] * r[i];
        }
    

    That would require the optimizer to inline the latter into the former to end up with a single expression, though. Is there a different way to express this that doesn't rely on the optimizer for inlining?

    • Expression templates do not rely on optimizer since you're not dealing with the computations directly but rather expressions (nodes) through which you are deferring the computation part until the very last moment (when you have a fully built an expression of expressions, basically almost an AST). This guarantees that you get zero cost when you really need it. What you're describing is something keen of copy elision and function folding though inlining which is pretty much basics in any c++ compiler and happens automatically without special care.

      1 reply →