Live data from Hacker News

Defining interfaces in C++ with ‘concepts’ (C++20)

lemire.me

21–30 of 77 posts

Re: Defining interfaces in C++ with ‘concepts’ (C++20)

#21
Really good video by Conor Hoekstra on the differences between C++ Concepts vs. Haskell Typeclasses vs. Rust Traits vs. Swift Protocols.

https://youtu.be/E-2y1qHQvTg

It is a good intro overview to the subject. Unfortunately the video has far too much filler, so you need to skip a bit e.g. start at 22:30 when the video gets into examples.

Re: Defining interfaces in C++ with ‘concepts’ (C++20)

#22
post #7

> In Go, I found that using an interface was not free: it can make the code slower. In C++, if you implement the following type and call count on it, you find that optimizing compilers are able to just figure out that they need to return the size of the inner vector. I'm surprised at this, do Go interfaces really introduce much overhead? Of course this depends on the level of performance you care about but surely, be…

Interface methods in Go are like virtual methods in C++. In principle C++ compilers when statically compiling everything can often remove virtual method indirection for some objects, but I think in general this optimization is still uncommon and difficult to coax out a compiler. Go definitely does not do this, even though in principle it should be easier. Basically, "interfaces" in Go and C++ actually refer to quite…

This is common when doing LTO, without it there is no guarantee that there isn't some dynamically loaded code that would be broken, this is one area where JIT focused languages have an advantage.

Re: Defining interfaces in C++ with ‘concepts’ (C++20)

#25
> So what are concept good for? I think it is mostly about documenting your code.

Emphasis mine. While it is somewhat good as documentation, sometimes static_assert with a custom diagnostic message is sometimes better for this purpose.

The hidden power of concepts/constraints is the way it shapes overload sets. You can have something like:

  template 
  void foo(R&& r) {
    /* some generic algorithm */
  }

  template 
  void foo(R&& r) {
    /* optimized for random access */
  }
and it will work if you pass a random access range, as the compiler can deduce that it's more specific than a forward range to resolve the ambiguity. Prior to concepts writing code that did this was way more cumbersome.

Re: Defining interfaces in C++ with ‘concepts’ (C++20)

#26
post #25

> So what are concept good for? I think it is mostly about documenting your code. Emphasis mine. While it is somewhat good as documentation, sometimes static_assert with a custom diagnostic message is sometimes better for this purpose. The hidden power of concepts/constraints is the way it shapes overload sets. You can have something like: template void foo(R&& r) { /* some generic algorithm */ } template void foo(R&…

Indeed. I haven't found concepts to be very good at generating error messages. But they are great for documentation and to get rid of SFINAE hacks for overloading.

The shorter template syntax is a bonus.

edit: concepts should also allow for better IDE tooling, for example proper completion inside template functions; although it is supposed to work, I didn't notice it firing yet in clangd.

Re: Defining interfaces in C++ with ‘concepts’ (C++20)

#27
post #14

I would argue Java interfaces are very different from Go interfaces and C++ concepts, because the former is nominally typed and the latter are structural.

That's something I have been pondering for some time. I believe it's a false dichotomy. My thought is still that structural supersedes nominal . A nominal interface is just another constraint added to the list of constraints of an underlying structural interface?

In practice C++ Concepts don't do what you're suggesting.

The C++ 20 Standard Library provides numerous concepts which have a very different semantic requirement than the syntax they're checking. If you violate the syntactic requirement of course that'll earn you a compiler error, but if you violate the semantic requirements that's silently an ill-formed C++ program, it has no meaning whatsoever and might do absolutely anything if run.

If these were nominal, we could say, well, nobody should have deliberately implemented this inappropriate Concept, similar to an unsafe Rust trait, the act of implementation is a promise to others. But C++ Concepts aren't nominal and so there was no opportunity to do that and so in practice such deviations are likely very common despite the potentially drastic consequences.

Re: Defining interfaces in C++ with ‘concepts’ (C++20)

#28
> In Go, I found that using an interface was not free: it can make the code slower.

The Go version that was presented isn't equivalent though. In Go you are accepting an interface directly which will hide the value under some fat pointer for dynamic dispatch, in c++ you are using generics to monomorphise the function to specific types. If you want to compare the implementations fairly you should've used Go generics:

  func Count[T IntIterable](i T) (count int) {

Re: Defining interfaces in C++ with ‘concepts’ (C++20)

#30

> In Go, I found that using an interface was not free: it can make the code slower. The Go version that was presented isn't equivalent though. In Go you are accepting an interface directly which will hide the value under some fat pointer for dynamic dispatch, in c++ you are using generics to monomorphise the function to specific types. If you want to compare the implementations fairly you should've used Go generics:…

Fair criticism, though I do wonder if it'd really make that much of a difference. Go doesn't really monomorphize generics either, and would end up with an equally if not more expensive lookup for the correct generic function at runtime.

Some reading: https://github.com/golang/proposal/blob/master/design/generi... https://planetscale.com/blog/generics-can-make-your-go-code-...

Post reply on HN