Description
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 assave()
,fetch()
, and evenput(Sting, Object)
. - Unwanted object dirtying and failing to receive updates. Default types for server-side dictionaries and arrays are
Map
andList
and we auto-convert them toJSONObject
andJSONArray
when callinggetJSONObject(String)
andgetJSONArray(String)
. Since we need to keep track of mutable container changes, we have to internally callput(String, Object)
with the newJSONObject
orJSONArray
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 updateestimatedData
instead of usingput(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!