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

DM-9932: Make afw classes RFC-209 compliant #312

Merged
merged 12 commits into from Feb 1, 2018
Merged

Conversation

kfindeisen
Copy link
Member

This PR changes all classes to have explicitly declared compiler-generated members, as adopted in RFC-209. I tried to make changes according to the following principles:

  • Do not change current behavior, even if the old behavior is arguably wrong. For example, a class with neither copy nor move constructors defined had both explicitly defaulted, while a class with a copy constructor but no move constructor got a move constructor that delegates to the copy constructor.
  • Follow the Rule of Three. In particular, I added explicit (defaulted) destructors wherever I added a copy or move constructor, and I added explicit members to classes where RFC-209 does not require them if they already had explicit destructors.
  • Keep definitions locations consistent. Members were explicitly defaulted in the header file if most constructors were inline, and in the source file if most constructors were defined there.
  • Use C++11 idioms. Where compiler-generated members had manually implemented defaults, I replaced them with the default keyword.

Copy link
Member

@TallJimbo TallJimbo 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!

I've made a number of small suggestions, mostly on ways in which you could go a bit further to clean things up a bit more. Feel free to ignore anything you think is out of scope, especially the areas where I'm advocating something that's not as precisely backwards-compatible as everything else you've done.

AffineTransform(AffineTransform const &) = default;
AffineTransform(AffineTransform &&) = default;
~AffineTransform() = default;

Copy link
Member

Choose a reason for hiding this comment

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

I think assignment can be defaulted for this class, too; the implementation later in the class declaration should be equivalent to that.

@@ -101,6 +101,9 @@ class Box2I {

/// Standard copy constructor.
Box2I(Box2I const& other) : _minimum(other._minimum), _dimensions(other._dimensions) {}
// Delegate to copy-constructor for backwards-compatibility
Box2I(Box2I&& other) : Box2I(other) {}
Copy link
Member

Choose a reason for hiding this comment

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

I'm quite confident that defaults are fine for all compiler-generated member functions in this class.

I also understand if you'd prefer to just adhere strictly to your current guidelines, but I'll keep noting the ones I'm certain about as I go.

// Delegate to copy-constructor for backwards compatibility.
Box2D(Box2D&& other) : Box2D(other) {}

~Box2D() = default;
Copy link
Member

@TallJimbo TallJimbo Jan 27, 2018

Choose a reason for hiding this comment

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

Defaults for all compiler-generated functions would be fine for Box2D.

CoordinateBase(CoordinateBase&&) = default;
CoordinateBase& operator=(CoordinateBase const&) = default;
CoordinateBase& operator=(CoordinateBase&&) = default;
virtual ~CoordinateBase() = default;
Copy link
Member

Choose a reason for hiding this comment

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

CoordinateBase's destructor should not be virtual; it's a CRTP base class, and we never hold its subclasses by a base class reference or pointer.

Note that virtual needs to be removed from the other specializations in this file as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

That seems like a strange thing to guarantee. Why bother using inheritance, then? Keeping it virtual seems safer.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I misspoke; we never delete its subclasses via a base class reference or pointer, which is much easier to guarantee. In this case, we also very rarely use the classes via a base class reference or pointer, but that's not an essential part of the pattern. For example, Eigen uses CRTP extensively, and the templated base classes are very much a part of the interface. It also doesn't define its destructors as virtual, because the base classes are by definition only used in contexts in which you can safely static_cast them a more derived class that can be inferred from their template arguments.

It's probably best to just say that because CRTP is essentially compile-time polymorphism, many of the usual rules of C++ inheritance that are derived from runtime polymorphism don't apply. I think a good case could be made that the implementations of Point and Extent don't actually benefit from these base classes much (they add a lot of boilerplate in exchange for reducing a bit of other code duplication), and I'd probably be supportive of a ticket to remove them, but we should absolutely not add a vtable to any of them.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have no idea what you mean by "rules of C++ inheritance"; the principles of inheritance are language-independent. But it is true that none of the classes in question contain other virtual methods, so they can't really be used as interfaces anyway. I'll change the declarations.

ExtentBase(ExtentBase &&) = default;
ExtentBase &operator=(ExtentBase const &) = default;
ExtentBase &operator=(ExtentBase &&) = default;
virtual ~ExtentBase() = default;
Copy link
Member

Choose a reason for hiding this comment

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

Should not be virtual (same reasons as CoordinateBase). Also other specializations in this file.

@@ -84,7 +84,7 @@ MaskFormatter<MaskPixelT>::MaskFormatter(std::shared_ptr<lsst::pex::policy::Poli
: lsst::daf::persistence::Formatter(typeid(this)) {}

template <typename MaskPixelT>
MaskFormatter<MaskPixelT>::~MaskFormatter(void) {}
MaskFormatter<MaskPixelT>::~MaskFormatter(void) = default;
Copy link
Member

Choose a reason for hiding this comment

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

Archaic void.

@@ -110,7 +110,7 @@ MaskedImageFormatter<ImagePixelT, MaskPixelT, VariancePixelT>::MaskedImageFormat
: lsst::daf::persistence::Formatter(typeid(this)) {}

template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
MaskedImageFormatter<ImagePixelT, MaskPixelT, VariancePixelT>::~MaskedImageFormatter(void) {}
MaskedImageFormatter<ImagePixelT, MaskPixelT, VariancePixelT>::~MaskedImageFormatter(void) = default;
Copy link
Member

Choose a reason for hiding this comment

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

Archaic void.

TanWcsFormatter& TanWcsFormatter::operator=(TanWcsFormatter const&) = default;
TanWcsFormatter& TanWcsFormatter::operator=(TanWcsFormatter&&) = default;

TanWcsFormatter::~TanWcsFormatter(void) = default;
Copy link
Member

Choose a reason for hiding this comment

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

Archaic void.

WcsFormatter& WcsFormatter::operator=(WcsFormatter const&) = default;
WcsFormatter& WcsFormatter::operator=(WcsFormatter&&) = default;

WcsFormatter::~WcsFormatter(void) = default;
Copy link
Member

Choose a reason for hiding this comment

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

Archaic void.

for (int n = 0; n < N; ++n) {
this->_vector[n] = other[n];
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Should be able to default this instead (same later in this file); I can confirm that that would be equivalent for this class.

@kfindeisen kfindeisen force-pushed the tickets/DM-9932 branch 3 times, most recently from a71567b to 83cc12c Compare January 31, 2018 22:13
@kfindeisen kfindeisen merged commit 24a8078 into master Feb 1, 2018
@kfindeisen kfindeisen deleted the tickets/DM-9932 branch August 22, 2018 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants