Re: [eigen] Taking advantage of C++11 features in Eigen

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


Hi,

I'm not a C++11 expert but let chime in.

I agree with Nicola that the case of the Tensor module and adding C++11 support are very different.

In the former case, we have en entire module that makes use of C++11 features without any fallback to C++03. From the user point of view, the use of C++11 is completely transparent, so it is important make it clear it requires C++11. Here we are talking about adding more compatibility/support for key C++11 features. I think such additions can be silently enabled if the following criteria are met:
- it does not introduce a new feature, it must strictly be about C++11 compatibility.
- it does not change the performance of Eigen itself.
- it has a favorable code maintenance cost versus user benefits ratio.

This is clearly the case of move semantics (as long as Eigen does not make use of it itself), static assertions, support for C++11 functors, or support for C++11 allocator.

The support for simple initializer lists (i.e., with scalar values only) is certainly fine too. For more sophisticated initializer lists, then we cannot know the code overhead without trying it.

Regarding alignment, I'm afraid the C++11 alignas does not bring any improvement since, AFAIK the practical difficulties are the same as with the respective compiler extensions (http://eigen.tuxfamily.org/dox/group__DenseMatrixManipulation__Alignement.html)

cheers,
gael



On Thu, Feb 13, 2014 at 4:58 AM, Nicola Gigante <nicola.gigante@xxxxxxxxx> wrote:

Il giorno 13/feb/2014, alle ore 02:05, Christoph Hertzberg <chtz@xxxxxxxxxxxxxxxxxxxxxxxx> ha scritto:

>
> Yes, this is only in the devel-branch and it lacks doxygen documentation. Unfortunately, especially for internal things of Eigen you need to study the source code (this has been pending for a while http://eigen.tuxfamily.org/bz/show_bug.cgi?id=138 …)

I definitely wanted to study the source code anyway, so it’s not a problem :)

> Okay, maybe my concern is a bit far-fetched. Consider this scenario:
> A user has a compiler which enables C++11 (or his build system accidentally does). He writes a library which depends on Eigen and claims to be C++03 compatible, since Eigen is and he did not knowingly use C++11 features himself. He then releases his library and gets complaints from users without or with insufficient C++11 support.
>
> Even when only using the code by oneself, I myself had my experiences with compiling on different machines having different compiler versions (actually, my problems were more on different versions of an OS-provided library, but I think this somewhat similar).
>
> Generally, this is not an argument against introducing C++11 features in Eigen, but to properly protecting against "accidentally" using them. I.e., if a user makes a well-thought decision to switch to C++11 he shall be able to do so (and profit from it), but not complain if he later needs to port his code to a system with inferior compiler support.

I personally think that anybody who will want to claim its work to be C++03 compatible (or $anystandard-compatible, by the way)
would at least need to know what this standard supports and what not. Since you support Eigen on a wide variety of compilers, you know
better than me that such a claim would anyway require intensive test effort, taking into account compilers quirks and differences that
in an ideal world should not exist. For such a scenario, accidentally using a feature from another version of the standard is a very
unlikely event, and would imply the existence of some serious problems in the engineering process of said project as a whole…
Note that this is different from having to take into account differences in how compilers implement the _same_ standard, where as said,
compatibility problems can be dealt only with extensive testing...

By the way, brace-init syntax is the only “user visible” change, i.e. the only that would cause some user code to compile
in one standard and not in the other. But compilation failures are not the worst kind of regressions. The worst are performance
regressions. As I said in the previous mail, deciding to use C++11, especially in new projects, means making entirely different design
decision, especially in generic APIs.

Consider for example move semantics. It seems like a mere performance improvement for existing code, like in this example:

std::vector<std::string> v = /*fill somehow..*/;
std::sort(v.begin(), v.end());

As everybody knows, for a big vector and big strings, useless copies in C++03 make this code very very inefficient.
You can easily see 10x speed improvement by just adding -std=c++11 on the command line (supposing the library has support too,
of course).
But is it really only a performance improvement, even if so huge? It’s not. It’s also a _usability_ improvement, because now users can
_really_ write code like that to sort a vector of strings, not only in a benchmark, while before you probably didn’t want to have a vector of
strings in the first place… As in this example, move semantics and other C++11 features really change recommended coding styles and
design patterns (think about the “never say new/delete” rule, for example), it’s not just a matter of more convenient syntax.

To make it “short", my point is that you already have such game-changer features silently enabled in Eigen, since you have move semantics,
because your users can start writing code that return huge matrices by value from functions and never care about performance bottlenecks,
while such code would explode at runtime if compiled in C++03 mode, while still compiling well. If you’re worried about regressions for
someone back-porting code to C++03, this kind of regressions are far worse than compilation errors, especially if an entire code-base
is using an API that need to be redesigned (again, someone facing those troubles “accidentally” should not have been starting
his project in the first place and Eigen support for this or that feature is certainly not who is to blame).

Then, for coherence to your concern, you should thus avoid all C++11 features all-together, not only “user-visible” changes like initializer
lists, and simply forbid users from taking advantage of them, which is clearly not what you want…

To return to brace-init syntax, you already have it “for free” for some fixed sized vectors, since Matrix has a couple of constructors
that take two/three/four scalars. So you can already do something like:

Vector3f v = {1,2,3};

Some user is going to write code like this and wonder why it can’t work for VectorXf as well...

>
>> You can make the choice even more explicit if you want, by testing a EIGEN_USE_CPP11 symbol or something like that.
>
> We decided against further user provided preprocessor symbols (we had some troubles with EIGEN_DEFAULT_TO_ROW_MAJOR in the past http://eigen.tuxfamily.org/bz/show_bug.cgi?id=422 -- again, maybe I'm over-concerned here ...)
>
>> What other libraries are doing is to conditionally support such features if explicitly enabled and supported by the compiler,
>> and silently drop them if missing. From the users point of view is clean, painless, and enables them to choose how to write their code.
>
> Basically, that is the plan for Eigen as well (as far as I interpreted our previous discussions about it). Only we decided to enable features by including files from <Eigen/CXX11/...> instead of using preprocessor defines. If you have good arguments for the latter approach, it would not be too late yet to change that decision (so far we mostly have one unsupported module depending on C++11).
>

My (not so radical as it seems) proposal is to use neither separate headers nor preprocessors defines. What I’d suggest is to simply support
selected features if enabled, and silently drop them if not, as you’re already doing for move semantics and static_assert.
This is what other (also huge) libraries are doing (see boost and Qt for example) and IMHO is the best way to go, from both
the user and code maintenance points of view.

A different thing are modules that _depend_ on C++11, like the one you mentioned. Those can indeed be put in a distinct subdirectory,
or just ifdef everything away if needed features are not available, becoming a big static_assert saying to the user what’s going on.

>> If yours is not a firm stop sign, I would like to start working on some ideas and, as time goes, we can see if they're worth or not.
>
> I definitely don't want to stop you entirely from providing C++11 features to Eigen (nor would I consider to have anything near the right to solitarily keep you from doing it).
> I guess I mostly was a bit worried by your first mail that your plans would endanger C++03 compatibility/maintainability ...
>
> Sorry for skipping most of your mail. Generally, I agree that C++11 adds a lot of very useful extensions, which we eventually shall use in Eigen. For details, maybe C++11 experts want to join the discussion …
>

Of course C++03 compatibility must remain an axiom, and maybe initially I’ve badly explained myself too. If we agree on the basic points,
I think I’ll soon start separate threads to let you know where my experiments are going.

>
> Christoph
>

Greetings,
Nicola




Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/