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-20019: Fix pickling of String Fields #468

Merged
merged 1 commit into from Jun 6, 2019
Merged

Conversation

parejkoj
Copy link
Contributor

@parejkoj parejkoj commented Jun 4, 2019

No description provided.

Copy link
Member

@kfindeisen kfindeisen left a comment

Choose a reason for hiding this comment

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

I have some suggestions for reducing code duplication, but the basic approach looks good.

@@ -75,6 +75,17 @@ class Access final {
/// @internal Access to the private Key constructor.
static Key<Flag> makeKey(int offset, int bit) { return Key<Flag>(offset, bit); }

/// @internal Access to the private Key constructor.
static Key<std::string> makeKeyString(int offset, int size) {
return Key<std::string>(offset, FieldBase<std::string>(size));
Copy link
Member

@kfindeisen kfindeisen Jun 5, 2019

Choose a reason for hiding this comment

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

As I understand it you don't need the explicit construction of FieldBase, and the code is more readable without it (see makeKey<Flag>, above).

Copy link
Member

Choose a reason for hiding this comment

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

I guess you could merge makeKeyString, makeKeyArray, and makeKey<Flag> into a single template, but then you'd need to include explicit arguments in all your calls (e.g., makeKey<std::string>(1, 42) or makeKey<Array<int>>(1, 42)). Not sure that's much of an improvement, especially if you need to hunt down the existing flag calls. 😞

template <typename U>
static Key<Array<U>> makeKeyArray(int offset, int size) {
return Key<Array<U>>(offset, FieldBase<Array<U>>(size));
}
Copy link
Member

Choose a reason for hiding this comment

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

Change the type parameter from U to T. By convention, U is used for templates that need to accept types other than some "primary" type (e.g., converting constructors), and it's a bit confusing when you only have one generic type.

}

template <typename U>
void declareFieldSpecializations(PyField<Array<U>> &cls) {
Copy link
Member

Choose a reason for hiding this comment

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

U -> T

Copy link
Member

Choose a reason for hiding this comment

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

As with the makeKey methods, you could make a template that covers both Array and string, and without the need for an explicit template argument.

template <typename U>
void declareFieldSpecializations(PyField<Array<U>> &cls) {
cls.def(py::pickle(
[](Field<Array<U>> const &self) {
Copy link
Member

Choose a reason for hiding this comment

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

Consider using Class = Field<Array<U>> to reduce code duplication; see the style guide.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think there are few enough uses (3 total) that that definition doesn't help, and it gives another layer of indirection for someone looking at the code to have to follow.

void declareKeySpecializations(PyKey<std::string> &cls) {
declareKeyAccessors(cls);
cls.def_property_readonly("subfields", [](py::object const &) { return py::none(); });
cls.def_property_readonly("subkeys", [](py::object const &) { return py::none(); });
Copy link
Member

Choose a reason for hiding this comment

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

Do you actually need these properties at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I copied them from the PyKey<T> specialization: that was being used string before I added this one, so I would assume I should keep it consistent with the new specialization.

return py::make_tuple(self.getName(), self.getDoc(), self.getUnits());
},
[](py::tuple t) {
if (t.size() != 3) throw std::runtime_error("Invalid number of parameters when unpickling!");
Copy link
Member

Choose a reason for hiding this comment

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

Report the actual size?

schema.addField("string", type="String", doc="A string field", size=42)
schema.addField("variable_string", type="String", doc="A variable-length string field", size=0)
schema.addField("array", type="ArrayF", doc="An array field", size=10)
schema.addField("variable_array", type="ArrayF", doc="A variable-length array field", size=0)
Copy link
Member

Choose a reason for hiding this comment

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

Lots of code duplication; consider factoring the two schema definitions into their own function (makeTestSchema? addCommonTestFields?).

@parejkoj parejkoj merged commit 3287933 into master Jun 6, 2019
@timj timj deleted the tickets/DM-20019 branch February 18, 2021 00:01
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