Open splinterofchaos opened 10 years ago
Indeed, these are things I've spent a lot of time thinking about myself. I've not really been able to come to a conclusion about what's best, and therefore left things at status quo (as in, strictly C++11). A short summary of my thoughts on the subject:
As FTL hasn't yet technically seen a release, I don't feel we're necessarily obliged to keep backward compatibility. To my knowledge, there's also no "serious" code relying on FTL (there certainly shouldn't be, not yet). So there's pretty much no one to upset.
However, as you correctly point out, access to gcc-4.9 and clang-3.4 isn't exactly widespread yet. In particular, as far as I know, there is no major distribution shipping with either. Completely breaking compatibility with essentially everyone who doesn't compile their own compiler seems a bit hasty. On the other hand, by the time the library is ready for proper use, this may well have changed.
As for keeping backwards compatibility using #defines
and such, I don't much like the idea of having to maintain several subtly differing duplicates of features. Perhaps doing so is the pragmatic approach, though. I'm certain it's possible to write a Travis script that downloads and compiles gcc-4.9 and clang-3.4 and tests all four versions, which would make maintenance a lot easier for this case. Of course, it still doesn't change the fact that there will be more code duplication and complexity, for perhaps very little gain.
Then again, generalised lambda captures, return type deduction for all functions, the new library additions...
In short, I'm quite undecided. In both this and a number of other cases where I've postponed a decision far too long.
I would love to hear the input of more people, if there are any around with an opinion, otherwise--since I'm undecided myself--I'm leaning towards including C++14/1y features as @splinterofchaos seems to favour it and is so far the one (besides myself) with most time and interest vested in the library.
In case we do go for some of the features, I'm thinking it should be the strict subset that both gcc-4.9 and clang-3.4 support, using fallback implementations as required by older versions. Experimental and TS type features should probably be avoided.
As no further input has been received, I will close this issue and (soon) start work on getting Travis to build with gcc-4.9 and clang-3.4 in addition to the existing compilers. I will also be setting up some kind of compile-time configuration or feature detection mechanism so that work can begin on using C++14 features when available, and fallbacks when not.
I apologize. Shortly after you responded, I lost my internet connection, until now.
An update on availability: The latest Ubuntu has clang 3.4 in its repositories with no need for a PPA. I'm unsure about other distros, however.
No problem, not that much has happened since.
There is an issue with Ubuntu's clang 3.4 though. Actually, probably not with clang itself, but with the libc++ version they ship--which seems to be a fair bit older than 3.4. I saw a number of errors and even a crash when last I tried it.
Of course, it's still entirely possible to use c++1y/14 features, particularly if you get a later libc++ version. In fact, FTL is now more or less set up so that we could start using them. I mean, there are currently no macros or anything, but we do have a FTL_CPP14
define that is only set by cmake when compiling with gcc 3.9 and clang 3.4, including -std=c++1y
switches. Library users could simply toggle this define themselves in their build system.
As for how to continue from here; I was thinking about using e.g. macros like
#ifdef FTL_CPP14
#define MOVE_CAPTURE(x) x = std::move(x)
#else
#define MOVE_CAPTURE(x) x
#endif
which would allow lambda captures to use move if possible and otherwise fall back to capture by copy. Similar macros would be easy to make for forwarded captures and so on.
Hmm, without more fine grained feature checks, I think generalised lambda captures is more or less the only new feature that's actually useful at this time. Possibly polymorphic lambdas and auto
/decltype(auto)
for regular functions, but the former seems very situational and the latter does not make much sense if we want to keep backwards compatibility (because we'll have to do the typedefs etc anyway).
I'm still hesitant to make things too complicated, but it's certainly possible to give greater feature control through defines than just the catch-all FTL_CPP14
. I.e. there could be FTL_VARIABLE_TEMPLATES
, FTL_GENERALISED_LAMBDA_CAPTURES
, and so on. It would be easy to change the current cmake script to set the appropriate ones for each compiler.
Ah, re-opening as it seems we may have some discussions after all.
There is an issue with Ubuntu's clang 3.4 though. Actually, probably not with clang itself, but with the libc++ version they ship--which seems to be a fair bit older than 3.4. I saw a number of errors and even a crash when last I tried it.
Yes, to use the 3.4 features requires a 3.4 library. I think I even had to comment out a line (using ::gets
or something) to get it to work, but that might've been before I upgraded libc++.
I do have plans for variable templates. (Monoid::id, MonoidA::fail, etc.) One of the recent proposals suggested that variable templates end in _v
do there is no collision with currently-used identifiers. But last I checked, clang still had a bug or two to fix when using var templates in a template environment.
If we're going to optionally include variable templates, we might as well set up the configuration system to allow different subsets of C++14 in a more generalised manner. Much as I don't like it, I suppose it's almost inevitable, if not for 14, then for 17.
I guess the common solution would be a configuration.h
or whatever that checks for feature defines, including one that turns them all on. I.e.:
#ifdef FTL_CPP14
#define FTL_GENERALISED_LAMBDA_CAPTURE
#define FTL_VARIABLE_TEMPLATES
...
#endif
#ifdef FTL_GENERALISED_LAMBDA_CAPTURE
....
#else
...
Sounds reasonable?
I do not know of what compatibility goals this library has except that travis ci is set up for clang 3.3 and gcc 4.8. I also do not know that this is the most opportune time to upgrade, but I thought I'd make this "issue" to discuss some of the pros, cons, and steps to adopting the C++1y features in these two releases.
One example of a c++1y feature I required: I went through ftl/include/memory.h and added a specialization for
std::unique_ptr
for everythingstd::shared_ptr
had a specialization. I discovered that the definition ofderiving_map<in_terms_of_bind<M>>
didn't work becauseunique_ptr
s are move-only. gcc 4.8 can do this, but it requires 3.4 of clang.See: splinterofchaos/ftl@5934a448fbaf7bf938e9ecd51ac87b1a66588dc1
To summarize the language features allowed by both gcc 4.9 and clang 3.4 that I think might benefit ftl:
And the library additions:
std::integer_sequence
ftl::seq
, but with a few more bells and whistles.std::experimental::optional
std::maybe
. (Not sure if gcc 4.9 has this.)operator()
overload forstd::integral_constant
.std::is_same<T,U>()
vs.std::is_same<T,U>::value
.std::result_of
gcc has yet to implement variable templates, relaxed constexprs, or TypeTraitsRedux, to name a few.
Only upgrading to clang 3.4 would enable auto for function return types, which gcc 4.8 implements, although gcc 4.8 may not work for every situation clang does because it's based on an out-of-date proposal.
clang 3.4 would allow experiments with variable templates, but break gcc compatibility.
I did have to modify some of the code that I submitted in order to get clang 3.4 to compile my master: splinterofchaos/ftl@749805adaa8ced3df4b3bce4d781c4149bf63500
Since the new releases of clang and gcc might not be readily available to everyone, it might be best to maintain backwards compatibility. In that case, both compilers define the macro
__cplusplus
as201103
when inc++11
mode, and a higher number forc++1y
(though clang and gcc use201305
and201300
, respectively, forc++1y
mode). Furthermore, since clang uses a slightly higher number, and has slightly more features, this macro can be used to distinguish between what gcc and clang can handle.