
Why I want Concepts, sooner rather than later - vmorgulis
https://isocpp.org/files/papers/p0225r0.html
======
CJefferson
I was involved in putting concepts into the g++ standard library, for the
aborted C++0x concept design.

My feeling is this is a classic example of an area where the perfect is the
enemy of the good.

At one extreme we have C++'s current design -- try substituting the types into
the template and see what explodes. At the other extreme (which is what C++0x
templates did) is that if a template passes 'concept check', we know,
100%(ish), that the resulting code is going to compile.

The problem is, that this means when you write the concepts for a function,
you have to have concepts for every corner of the C++ language you could make
use of. This means for many functions the concept list ended up being longer
than the function! Further, it is easy to miss optimisations (such as rvalue
references), because you didn't 'concept' for them.

The latest aim is (to me) a good middle-ground. It checks (for example) that
something is "numberish", or "iteratorish". You can easily create freakish
types which will pass concept check, and then not compile, leading to the kind
of error messages users currently get. But the common cases, of people passing
sensible, but wrong, things into methods, will get much nicer errors.

~~~
jstimpfle
If I get the idea, concepts are similar to Haskell's decade-old type classes,
as an alternative to OOP classes and inheritance, which by now almost
everybody has agreed are largely a bad idea from an architectural perspective.
Did anyone see Edward Kmett's talk "Type classes vs the world" and wants to
lose a few words on how they compare?

Regarding the problem you mentioned, I've often tried to break my problem
domain in "abstract concepts" using templates, static assertions, code
generation etc. I don't think I have a real word success story. Abstraction
doesn't work out of course for business logic because generalizing over the
mess which our world is is just incredibly hard, but also not for algorithms,
because quite frankly, efficient implementation is the result from learning a
thousand neat little tricks and applying them in the right situations.
Abstraction remove these opportunities.

For example, recently I've seen a Java application with a parameterized
container class. The parameters were abstract and thus the container had to
use tons of nested Hashmaps to get from A to B. Had it admitted that the only
sensible parameter was "int", everything could have been implemented using a
few super-fast arrays.

Another problem is that abstraction actually grows cancerours dependencies
across the code base. If we instead design clean data interfaces reusing basic
data types and add a few lines of comments / constraints / consistency checks,
this dependency hell just freezes down and we notice that abstraction wasn't
the actual problem to begin with.

For the basic quick and dirty app, or script, of course it's extremely
important to have generic STL containers and a std:: algorithm, or python
dicts / set / iterators, and be done with it. Also in rare cases, abstractions
like Monoid, Functor, Applicative, Traversable, Monad can come in handy when
you can reuse a few lines of code from a generic library.

But to come back to your point, I think that's all largely explored territory
and the point of diminishing returns has long been surpassed.

Thoughts? Counterexamples?

~~~
EGreg
My first thought is, why exactly do you think everyone concluded that OOP
classes and inheritance is bad architecture?

~~~
jstimpfle
It's my impression -- I've heard it from so many programmers that I respect.

The impression may be biased by my own frustrations dealing with bad
abstractions (like: 90% of the classes I've seen out there are semantically
broken, a.k.a not state machines).

(To back that up, there is a python script of mine which I think is rather
clean. It has basically a single class in it, which was needed because the API
of cmd.Cmd relies on inheritance. I had to spend quite some time to circumvent
that insane amount of brokenness. I've put in a few cynic comments out of
frustration. If you're interested:
[https://github.com/jstimpfle/gitadmin/blob/08a2c0b7dd1a8950e...](https://github.com/jstimpfle/gitadmin/blob/08a2c0b7dd1a8950e3e9084a964ae3a248b29b39/gitadmin#L1303)
Good times.)

Name the use cases where you think inheritance is a good fit.

~~~
millstone
Inheritance got a bad rap in part because object oriented analysis was done as
an exercise in taxonomy (Employee is a Person is a Mammal is an Organism...),
instead of identifying useful abstractions. A second problem is using
inheritance when composition is obviously better. java.util.Stack is a lovely
example of both sins in action.

Where inheritance shines is in enabling _close coupling across module
boundaries_. An example is event routing: how do you enable customization of
how events flow through your app? UIKit handles this through inheritance. The
base method gives you the default behavior, which you can override to
customize. You can stop propagation by just not calling super, or redirect the
event by calling the method somewhere else, etc. It's flexible.

JavaScript handles this clumsily, by trying to anticipate all the
customizations you might want to do and providing APIs for each of them
(event.preventDefault, event.stopPropagation...) Despite all that, frameworks
like React have to reimplement event dispatch, because the default behavior is
too inflexible.

Here inheritance is the glue that enabled close coupling between UIKit's
default event dispatch algorithm and outside modifications to it.

~~~
jstimpfle
Yeah widget toolkits (if not done across maintenance boundaries) are really
the one situation which is always described as a good fit for inheritance.
However I don't think I like the idea of "close coupling across module
boundaries". Sounds like an antithesis to sustainable architecture to me.
Anyway I don't do UI...

------
lambda
Meanwhile, you can use Rust now where traits (which fill a very similar niche
to concepts) have been available for a long time, and are widely used in the
standard library.

Of course, once you do, you find that some of the traits you would like to be
able to use aren't expressible without "higher kinded types"
([https://github.com/rust-lang/rfcs/issues/324](https://github.com/rust-
lang/rfcs/issues/324)), so there are still some big features that everyone
kind of hopes will happen soon but there's no current plan for. But the
existing trait system gets you pretty far for a lot of what you want to do.

~~~
zenbsd
Traits are not like Concepts. Concepts are for template meta-programming.
You're thinking of the "Contracts" proposal which would be like concepts but
for normal types, so like traits.

Also, can we have a C++ article where the comment section doesn't turn into a
Rust ad?

~~~
0xCMP
We could if C++ wasn't so complicated, overwhelming, and prone to writing bad
code that everyone feels compelled to replace it and going as far as starting
a project like Rust to solve the issues Python or Go do for C++ with the same
level of zero-cost abstractions.

Devil's Advocate: C++ may be complicated, but try comparing hello worlds in
each language. Maybe Rust still isn't the holy grail either.

~~~
lambda
Rust:

    
    
      fn main() {
          println!("Hello, world!");
      }
    

C++:

    
    
      #include <iostream>
      
      int main() {
        std::cout << "Hello, world!";
      }

~~~
masklinn
The Rust version adds a newline (hence print _ln_ ) while the C++ version
doesn't. Either the Rust version should use `print!`, or the C++ version needs
an `<< std::endl`

~~~
claudius
Adding '\n' to the string is perfectly fine, no std::endl needed (\n
translates to the system-specific newline and the stream is flushed on
destruction anyways).

------
tux3
And this was published in response: "Why I want Concepts, but why they should
come later rather than sooner" [0]

[0] [http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2016/p024...](http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2016/p0240r0.html)

~~~
lanevorockz
It's all about timing, with C++11/C++14 having changed the language
substatially it would be nice to fix some of the issues that templates have
caused over the years. Due to new behaviours on the language existing
templates might stop working.

Honestly almost any template by itself it's brittle and can fail to execute as
predicted depending on the type received. This causes major issues and has to
be solved sooner rather than later.

Also important to note that Concepts went through a lot of work and it evolved
from concepts to the current concepts lite that was proposed for C++17.

I would like that the committee was a bit more open when mature proposals
backed by senior members fail to pass. It could help other people understand
the issue and maybe work towards solving it.

------
0xCMP
Can someone explain what C++ Concepts are and what they're used for? I see
they'd simplify the code greatly but when I went to read this article I
expected him to talk about maybe an approach to programming that focuses on
the concepts first or something and was completely surprised that this is a
programming feature.

~~~
svalorzen
In essence, they are used to allow template writers to easily put constraints
on the type parameters that their templates require, and provide better
diagnostics to users of template classes when they try to instantiate a
template with the wrong parameters.

Normally when you wrongly instantiate a template you get a block of text which
describes exactly what went wrong. In terms of the language as it is now, the
whole block is necessary, but the ability to mentally parse it is a skill that
requires time and is otherwise relatively useless. In addition, for library
users, errors could happen way inside the internals of the library, and the
users would have little to no information as on how to parse such errors.

To try to mitigate this, type traits were introduced. These are used by
template writers, and their task is to check that template parameters satisfy
certain given requirements or else a certain overload is discarded (using
SFINAE for example). In this way, errors would be caught before trying to
actually instantiate a template, and users would not be exposed to errors
within the internals, but just at a boundary when a template was being
instantiated. But still this approach has limitations, and the errors are
still not quite pretty.

Concepts tries to fix all this with an approach that resembles java's
"implements". It provides a way to easily specify and check at compile time
the interface required by template parameters, so that it can be checked
before instantiating the template and give better errors in terms of the
concept rather than type traits features.

------
slavik81
Quite frankly, I still don't get it. Concepts are a big, complex feature and
the main thing you get out of them is that it makes it easier to write error-
checking for template parameters. I don't think I've ever actually been bitten
by that problem in the first place.

I was champing at the bit to get C++11 features like auto, move, lambdas,
unique_ptr, bind and random. I could see exactly where I'd use them to make my
code simpler.

The C++17 proposals mostly are uninspiring in comparison. Some seem minimally
useful while others seem very complicated. I worry that we might end up
standardizing a bunch of useless or poorly considered features.

~~~
srean
>I don't think I've ever actually been bitten by that problem in the first
place.

That I think qualifies you to be a few of a kind if not one of a kind. If you
use a lot of templates and manage to avoid the problem of 'late errors' with a
reasonable effort I would love to know more about your programming style

~~~
slavik81
I suppose I probably have been bitten by this sort of thing when using
iostreams and Google Mock.

------
static_noise
Summary: The article is talking about including Concepts in the upcoming
___C++17_ __standard - but only in the language specification, not the
standard library because it 's not fully ready. It argues that the language
part is ready, though.

