Live data from Hacker News

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

lemire.me

31–40 of 77 posts

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

#31
post #19
post #14

Earlier quoted context omitted.

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?

Nominal interfaces can still be useful though, as they convey a stronger sense of intent than structural. For example, java.io.Serializable is a completely empty interface that classes “implement” to signal that they are safe to serialize. As a structural interface, it’d be useless.

structurally you can do something similar by adding some tag (in the form of a constant or nested type) to your class. For example:

  template concept serializable = requires { typename T::is_serializable_tag; };

  void serialize(serializable auto x) {...};

  struct NotSerializableClass { ... };
  struct SerializableClass { using is_serializable_tag = void; ... };

  serialize(NotSerializableClass{}); // error
  serialize(SerializableClass{}); // all good
In C++, specializing a trait is also an option. So, while nominal and structural interfaces are not the same, sometimes the lines are blurred.

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

#32
post #14

Earlier quoted context omitted.

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 absolute…

I have been programming in C++ for almost 20 years [1] and I don't remember ever being bitten by accidental concept conformance. So I object to the "likely very common" description. Implicit conformance was very much an explicit design goal.

[1] yes, concepts as an explicit language feature are new, but C++ has had de-facto concepts since Stepanov work on the original STL in the 90s.

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

#33

[flagged]

Yeah, I agree, let's just rewrite all our system software in Javascript. Much better. (Well, except for your Javascript interpreter, that will still be written in C++, obviously.)

Tsk, JS is already the old thing. All the cool kids are on Typescript now.

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

#34
post #14

Earlier quoted context omitted.

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?

Well it depends on a runtime/compile-time distinction. A nominal type is a structural type with a compile-time constraint. If you have compile-time only constants you can model nominals with structural, type Square static const IsSquare = true var length = 10 You can kinda hack-in subtyping, type Shape static const Shape = true type Square import static from Shape static const IsSquare = true var length = 10

This is routinely done in c++ with tags (for example iterator_tag). Tags inheritance is also a thing.

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

#36
post #22
post #7

Earlier quoted context omitted.

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.

Indeed you need LTO for generalized devirtualization, but guarded devirtualization, static classes and final can still help even without LTO.

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

#37
post #23

Earlier quoted context omitted.

Rust is a serious contender is this space, and closing the gap quickly.

Including introducing new features on 6 weeks basics, just wait until Rust also gets 40 years of history.

You know this is a red herring. Frequency of the release cycle is orthogonal to the amount of changes or even how long the changes are in development.

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

#38
post #37
post #23

Earlier quoted context omitted.

Including introducing new features on 6 weeks basics, just wait until Rust also gets 40 years of history.

You know this is a red herring. Frequency of the release cycle is orthogonal to the amount of changes or even how long the changes are in development.

Just wait until Rust gets 40 years old.

Pity I won't be no longer around to check on it, given average human life expectancy.

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

#40
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&…

Rust requires trait bounds (its equivalent of concepts) to type-check the template code at definition site, when it's written, not at the instantiation site where it's used. This results in much better error messages. The downside is that trait bounds for numeric code are awfully verbose, and you can't sneak in a printf without declaring it as a requirement.
Post reply on HN