Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use macros to instantiate most SField instances: #3658

Closed
wants to merge 1 commit into from

Conversation

scottschurr
Copy link
Collaborator

Overview

There have been cases in the past where SFields have been defined in such a way that they did not follow our conventions. In particular, the string representation of an SField should align with the declared name of the global static const SField.

This commit leverages the preprocessor to encourage SFields to follow this naming convention. This should help reduce the likelihood of similar bugs in the future.

Details

This branch uses the token pasting capabilities of the preprocessor to assure that for any given SField the in-code name and the JSON text name match.

I also took the opportunity to use token pasting so the type of a TypedField always agrees with its SField::fieldType. In order to get the second change to work, I renamed the various TypedFields so their suffixes match the suffixes of the SerializedTypeID enum members.

While preparing for this change I noticed that the JSON text of the sfPayChannel SField was simply "Channel". That's the kind of mismatch this pull request intends to prevent. The JSON text is part of the API, so it cannot be changed. So this branch changes the name of the SField from sfPayChannel to sfChannel.

Type of Change

  • Refactor (non-breaking change that only restructures code)

This change is internal only. There should be no need for a test plan, documentation changes, or release notes associated with this change.

@cjcobb23
Copy link
Contributor

I like this change, for consistency reasons. My only issue is now that you can't find the definition of the various SField constants in the codebase. For example, there is no longer a definition for sfLedgerSequence that you can find via grep or something similar. It's not very difficult though to deduce that the constant is an SField and is probably defined in SField.cpp. Not sure how I feel about this. Otherwise, looks great.

@scottschurr
Copy link
Collaborator Author

Yeah, I agree with that drawback, @cjcobb23. Unfortunately I think the drawback is inevitable using the macro approach, since we want the macro to use name pasting to generate the name of the variable. That inevitably means the variable name in the declaration will be buried inside the macro magic and not grepable. I don't see any approach to the problem that can avoid this drawback. In the future metaprograming may be able to produce a text name given a declaration, but that's C++26 at the earliest.

If macros supported text extraction, then we could make this work. But that's not the universe we live in.

You can think about it and decide how the advantages and disadvantages balance out for you.

Copy link
Contributor

@pwang200 pwang200 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! 👍

@pwang200
Copy link
Contributor

@cjcobb23 Clion helped me. For this PR, it helped me comparing the preprocessor results with the previous code quickly.

FWIW, my flow has not changed much, i.e. one click to find the declaration and another to find the definition and the IDE helped to show the preprocessor result automatically.

@cjcobb23
Copy link
Contributor

@pwang200 It's good to know that CLion was able to know what was happening. I'm fine with this as is. I think not being able to grep is a minor drawback, and the consistency gains are worth that drawback.

@scottschurr
Copy link
Collaborator Author

@cjcobb23 and @pwang200, it occurred to me that I can restructure the macros so the exact name of the SField is still findable by grepping. The revised macro relies of error checking, rather than correctness by construction, but it accomplishes the same end. The revised macro would result in declarations that look like this:

CONSTRUCT_TYPED_SFIELD(sfCloseResolution, "CloseResolution",       UINT8,      1);

The macro itself would leverage static_assert to validate that the declaration and the text name match.

#define CONSTRUCT_TYPED_SFIELD(sfName, txtName, stiSuffix, fieldValue, ...) \
SF_ ## stiSuffix const sfName ( \
access, STI_ ## stiSuffix, fieldValue, txtName, ##__VA_ARGS__); \
static_assert(std::string_view( #sfName) == "sf" txtName , \
    "Declaration of SField does not match its text name")

Do you think this might be be a preferable approach? If so, I'd be happy to code up the change as a [FOLD] for review.

@cjcobb23
Copy link
Contributor

@cjcobb23 and @pwang200, it occurred to me that I can restructure the macros so the exact name of the SField is still findable by grepping. The revised macro relies of error checking, rather than correctness by construction, but it accomplishes the same end. The revised macro would result in declarations that look like this:

CONSTRUCT_TYPED_SFIELD(sfCloseResolution, "CloseResolution",       UINT8,      1);

The macro itself would leverage static_assert to validate that the declaration and the text name match.

#define CONSTRUCT_TYPED_SFIELD(sfName, txtName, stiSuffix, fieldValue, ...) \
SF_ ## stiSuffix const sfName ( \
access, STI_ ## stiSuffix, fieldValue, txtName, ##__VA_ARGS__); \
static_assert(std::string_view( #sfName) == "sf" txtName , \
    "Declaration of SField does not match its text name")

Do you think this might be be a preferable approach? If so, I'd be happy to code up the change as a [FOLD] for review.

@scottschurr I do prefer this. It accomplishes the same end, but now the exact name is findable by grep.

@scottschurr
Copy link
Collaborator Author

Hi folks, I changed up the macros and updated the construction parameters in the most recent [FOLD] commit. Let me know if you like this approach better. Thanks.

ps I'm sure it will eventually become blasé, but right now it is a rush to do string compares at compile time...

Copy link
Contributor

@pwang200 pwang200 left a comment

Choose a reason for hiding this comment

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

Look great! Thanks for the change.

Copy link
Contributor

@cjcobb23 cjcobb23 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

There have been cases in the past where SFields have been defined
in such a way that they did not follow our conventions.  In
particular, the string representation of an SField should match
the in-code name of the SField.

This change leverages the preprocessor to encourage SFields to
be properly constructed.

The suffixes of SField types are changed to be the same as
the suffixes of corresponding SerializedTypeIDs.  This allows
The preprocessor to match types using simple name pasting.

Since the string representation of the SField is part of our
stable API, the name of sfPayChannel was changed to sfChannel.
This change allows sfChannel to follow our conventions while
making no changes to our external API.
@scottschurr
Copy link
Collaborator Author

Thanks gents. I rebased and squashed. I'll mark the pull request as passed once I've seen it pass continuous integration.

@scottschurr
Copy link
Collaborator Author

Travis is passing all of the builds except for the macOS ones. There's a CI fix for macOS in a different pull request, so I'm inclined to say this pull request has done well enough on CI. I'm marking the pull request as passed.

@scottschurr scottschurr added the Passed Passed code review & PR owner thinks it's ready to merge. Perf sign-off may still be required. label Nov 25, 2020
@nbougalis nbougalis mentioned this pull request Dec 4, 2020
@scottschurr scottschurr deleted the sfield-name branch December 7, 2020 23:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Passed Passed code review & PR owner thinks it's ready to merge. Perf sign-off may still be required.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants