Skip to content
This repository has been archived by the owner on Mar 26, 2020. It is now read-only.

Generating constexpr for constants when possible #282

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

itsff
Copy link

@itsff itsff commented Oct 5, 2016

I've noticed that the constants in generated C++ code are always initialized in the cpp file, even for basic types like bool and numerics.

In this patch I've modified the C++ code generator to determine if a value can be initialized in the header and, if so, place it there as a constexpr. This only happens for bools, numerics, enums and optionals thereof. If any other kind of constant is present, its value will get set in the implementation file as before.

Please refer to the "generated-src" from the test suite which is part of this commit.

@smarx
Copy link

smarx commented Oct 5, 2016

Automated message from Dropbox CLA bot

@itsff, thanks for the pull request! It looks like you haven't yet signed the Dropbox CLA. Please sign it here.

@itsff
Copy link
Author

itsff commented Oct 5, 2016

Signed.

@smarx
Copy link

smarx commented Oct 5, 2016

Automated message from Dropbox CLA bot

@itsff, thanks for signing the CLA!

@mknejp
Copy link
Contributor

mknejp commented Oct 10, 2016

Nice idea, however the tests are only half-way there. To make sure everything links properly the header-only constants need to be ODR-used in at least two translation units. Furthermore I wouldn't count on optional<> being a literal in all implementations considering Djinni is C++11 only and users have to supply their own optional type.

@guycnicholas
Copy link

There was talk back in March in the djinni Slack channel about moving the requirement to C++14. Should this again be considered now?

@mknejp
Copy link
Contributor

mknejp commented Oct 10, 2016

optional is C++17, which technically isn't out yet.

Copy link
Contributor

@artwyman artwyman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great in concept. I've made a few suggestions inline regarding style and clarity.

I'm torn on the question of requiring optional to support constexpr. Both std::experimental::optional (the pre-C++17 version) and std::optional (in C++17) were specified to have constexpr constructors, and I'd be keen to benefit from that in our own code. However boost::optional doesn't, and I'm pretty sure there are users out there making use of that. This might be something which requires a new command-line flag so that users can specify whether their optional implementation supports constexpr, along with specifying its class name and header file.

Adding a test in the test-suite to ensure that ODR isn't violated is a good suggestion too.

case _ => {
needsCppGen = true;
isConstExpr = false;
";"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest making constValue empty here, and applying the semi-colon in the final statement below. The semicolon isn't really part of the const value.

w.w(s"${marshal.fieldType(c.ty)} const $selfName::${idCpp.const(c.ident)} = ")
writeCppConst(w, c.ty, c.value)
w.wl(";")
val isConstExpr = c.value match {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to unify the cases for this match with the ones above in the header file. One option would be to make a helper function which returns the constValue used in the header file, then have isConstExpr here simply test whether that value is non-empty.

for (c <- consts) {
var isConstExpr = true
val constValue = c.value match {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be clearer to match on c.ty instead. I'm not set on that, since this does make the code simpler, but it took me a while to figure out that this distinction is the reason that optionals are being treated as constexpr-eligible. It's not an explicit case statement anywhere, but simply implicit in the fact that the constant value for an optional is of type T.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants