Hacker News new | ask | show | jobs
by jcelerier 1789 days ago
> Integer-like things. C++ char is similar to Rust's u8 or i8 but Rust's char and bool are very deliberately not just integers.

sure, but there's an easy mapping from char / bool to integers. C++ supports parametrizing on values of struct type, which is a clear increase in expressive power:

    struct foo {
      int count;
      float init;
    };
    
    template<auto arg> struct bar {
      float x[arg.count];
      
      bar() {
       for(int i = 0; i < arg.count; i++) 
         x[i] = arg.init;
      }
    };
    
    constexpr foo f{ .count = 123, .init = 4.56 };
    bar<f> b;


> You would like to define a type, which is parameterised not by the type of function, but by specific functions? So, for example I can make a foo<sum> and a foo<average> and those are distinct types which presumably internally are using the provided function to behave differently?

yes, it's pretty much the only way in C++ to have zero-cost callbacks / strategy pattern using function pointers since the compiler can directly inline the function pointer everywhere in the type's implementation instead of having to go and read it from some variable at run-time

1 comments

You're correct to observe that more sophisticated value parametrisation might be useful. At least &str (imagine roughly a nicer std::string_view as a built-in type) is on the horizon for Rust.

Because Rust cares a lot about soundness, this gets very tricky for user-defined types. The current idea is that they could be allowed if they derive Eq. What "derive Eq" means in practice is that the compiler is comfortable believing that either you can compare instances of these types to one another with a bit-match or they're composed of types with that property.

You wouldn't be allowed to implement Eq instead for this, because such implementations are safe in Rust, and thus their promises are worthless (Rust has unsafe traits like Allocator, and if you choose to implement those and get it wrong your program has Undefined Behaviour, but by definition that won't happen for a safe trait, even if you deliberately implement it contrary to the specification)

So that rules out floating point numbers because you shouldn't try to compare those to each other with bit matching - NaNs for example.

What does C++ do here? Just YOLO, if you make poor choices the resulting code is nonsense and too bad?

--

We still don't have an example, the constant function pointer thing feels unergonomic to me, I think I'd cook up a Trait representing whatever it is that these functions have in common, and then implement that Trait as necessary to get the same effect by parametrising on the Trait -- but I may very well be missing some affordance your preferred approach has since the equivalent C++ is just to use a Class and finalize the implementations yet you aren't doing that.