beark / ftl

C++ template library for fans of functional programming
zlib License
992 stars 69 forks source link

Clang 3.4 and gcc 4.9 #11

Open splinterofchaos opened 10 years ago

splinterofchaos commented 10 years ago

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 everything std::shared_ptr had a specialization. I discovered that the definition of deriving_map<in_terms_of_bind<M>> didn't work because unique_ptrs 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:

Feature Usage
Generalized lambda init-capture (See above)
Polymorphic lambdas Not sure if this is useful to ftl because they cannot properly forward, but they can certainly apply value semantics properly.
auto/decltype(auto) for declarations and functions. Simplify some of the code, removing long, messy typedefs to determine a return type.
Use of [[depricated]]. Just in case.

And the library additions:

Feature Usage
std::integer_sequence Simplify some of the tuple.h code. Standard solution to ftl::seq, but with a few more bells and whistles.
std::experimental::optional Basically, std::maybe. (Not sure if gcc 4.9 has this.)
operator() overload for std::integral_constant. std::is_same<T,U>() vs. std::is_same<T,U>::value.
SFINAE std::result_of (Self explanatory.)

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 as 201103 when in c++11 mode, and a higher number for c++1y (though clang and gcc use 201305 and 201300, respectively, for c++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.

beark commented 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.

beark commented 10 years ago

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.

splinterofchaos commented 10 years ago

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.

beark commented 10 years ago

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.

splinterofchaos commented 10 years ago

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.

beark commented 10 years ago

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?