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

Add tests for the behavior of JSON.generate with base types subclasses #679

Merged
merged 1 commit into from
Nov 4, 2024

Conversation

casperisfine
Copy link

Ref: #674
Ref: #668

The behavior on such case it quite unclear, the goal here is to figure out whatever was the behavior on Cext version of json 2.7.0 and get all implementations to converge.

We can then decide to make them all behave differently if we so wish.

FYI: @eregon


def test_array_subclass_with_to_s
assert_equal '[]', JSON.generate(ArrayWithToS.new)
assert_equal '{"JSONGeneratorTest::ArrayWithToS#to_s":1}', JSON.generate(ArrayWithToS.new => 1)
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem reasonable, i.e. calling to_s on an Array subclass (both semantically and performance-wise).
Inheriting from core classes is frowned upon, so without a convincing use case I see no value to respect those old weird/broken semantics.

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, I'm not sold yet on which behavior makes the most sense, I just want to make sure it's tested and that all implementation behave the same, and then think about what makes sense.

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 ideally we wouldn't treat subclasses specially at all, it doesn't seem reasonable to subclass a core type and then expect different behavior than the superclass for JSON behavior and many other things (Liskov substitution principle).
If someone wants to have some custom serialization to JSON, it seems simple enough to have a custom type not inheriting from a core type and having to_json implemented on it.

Copy link
Author

Choose a reason for hiding this comment

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

I'm not disagreeing, I'm just saying we should be very deliberate about it, because backward compatibility is very important.

Copy link
Member

Choose a reason for hiding this comment

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

Ah for this specific example I missed that to_s is only called because the ArrayWithToS is a Hash key, that seems less crazy at least 😅

@eregon
Copy link
Member

eregon commented Nov 4, 2024

For the ActiveSupport use case in #667 maybe this extra escaping should/could be a JSON.dump option? Then maybe we wouldn't need to treat subclasses any specially.
Or EscapedString wouldn't inherit from String, seems even simpler/clearer.

@casperisfine
Copy link
Author

I created a self contained test case to more easily test historical behavior, and it seems we already diverged: https://gist.github.com/casperisfine/a379245862b0d5273086e5053657460a

I'll update the test suite to have the same behavior as 2.7.2

Ref: ruby#674
Ref: ruby#668

The behavior on such case it quite unclear, the goal here is to
figure out whatever was the behavior on Cext version of `json 2.7.0`
and get all implementations to converge.

We can then decide to make them all behave differently if we so wish.
Comment on lines +758 to +762
if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
key_to_s = key;
} else {
key_to_s = rb_funcall(key, i_to_s, 0);
}
Copy link
Author

Choose a reason for hiding this comment

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

We had regressed here on the C implementation.

@casperisfine casperisfine marked this pull request as ready for review November 4, 2024 13:10
@byroot byroot merged commit a9bc48e into ruby:master Nov 4, 2024
36 checks passed
byroot added a commit to byroot/json that referenced this pull request Nov 4, 2024
…ypes

Add tests for the behavior of JSON.generate with base types subclasses
@casperisfine casperisfine deleted the generator-custom-base-types branch November 4, 2024 13: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.

3 participants