Skip to content

Proposal: Remove ParseObject Mutable Container Tracking #58

Closed
@grantland

Description

@grantland

Currently ParseObject tracks changes to mutable containers such as List, Map, JSONArray, and JSONObject passed in through put(String, Object) and returned from get(String), so modifications to these containers will flag the owner ParseObject as dirty and these modifications persisted to Parse or LDS.

This is feature is bad for a number of reasons:

  • Bad programming practice. Passing around mutable objects should be limited to prevent getting into an illegal state due to an outside entity modifying the internal state of an object. Convention states that any mutable object passed as a parameter should be copied as an immutable object so that neither the caller or the callee could modify the each other's instance.
  • Efficiency. Right now the SDK has to track mutable container changes by computing the current hash of the container, comparing it to the cached hash of the container to see if it's been mutated, and storing the new hash. This needs to be done on almost all ParseObject entry points which slows down execution time for simple things such as save(), fetch(), and even put(Sting, Object).
  • Unwanted object dirtying and failing to receive updates. Default types for server-side dictionaries and arrays are Map and List and we auto-convert them to JSONObject and JSONArray when calling getJSONObject(String) and getJSONArray(String). Since we need to keep track of mutable container changes, we have to internally call put(String, Object) with the new JSONObject or JSONArray value so we can keep track of any changes to that object, however this comes with a side affect of making the object dirty and inability to receive updates to those values when using those methods. Removing this feature will allow us to update estimatedData instead of using put(String, Object) internally, which will fix this problem.

Removing mutable containers would involve removing code related to tracking mutable containers as well as modifying put(String, Object) and get(String) to make a immutable copy of any container object passed in as the value or returned.

The reason for the proposal is that removing mutable containers would be a breaking change, but the assumption is that no one is relying on it on purpose. If a developer was relying on this "feature", only a small change would be required to re-enable the old behavior.

Current Behavior:

List<String> names = new ArrayList<>();

ParseObject object = new ParseObject("TestObject");
object.put("names", names);
object.save(); // Results in a creation of { "names": [] }

names.add("nikita");
object.save(); // Results in a update of { "names": ["nikita"] }

Proposed Behavior:

List<String> names = new ArrayList<>();

ParseObject object = new ParseObject("TestObject");
object.put("names", names);
object.save(); // Results in a creation of { "names": [] }

names.add("nikita");
object.save(); // Results in a no-op since the object isn't dirty

// To keep old functionality, call `put` after mutating the container to update
object.put("names", names);
object.save(); // Results in a update of { "names": ["nikita"] }

Feedback on this breaking change would be greatly appreciated!

/cc @nlutsenko @wangmengyan95 @hallucinogen

Metadata

Metadata

Assignees

Labels

type:featureNew feature or improvement of existing feature

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions