Immutable Data, Mutable State

Published April 03, 2020

This post focuses on improving the state implementation from my previous blog post. At the end of the post the Tweet class is mutable. The click listeners update the interaction count values as well as the like and retweet state. While this does work, I prefer to keep my classes immutable. This forces me to be explicit when the state changes, thus reducing side effects from other areas in the code.

The first goal is to make the Tweet class immutable.

Now that the Tweet cannot be updated by the listeners, another mechanism is needed to serve this purpose. This is where MutableState comes in to play. The javadocs of the file state

* The [MutableState] class can be used several different ways. For example, the most basic way is to store the returned state
* value into a local immutable variable, and then set the [MutableState.value] property on it.

This object is used to store an immutable variable. In this case, the Tweet object is wrapped by this MutableState. To do this, first the TweetView parameter needs to be changed to the MutableState type.

Next, the onCreate() and preview functions need to wrap the Tweet object in a MutableState. There is a mutableStateOf() function that can accomplish this.

This function accepts the state value as the first parameter. The second is a function that determines if two states are equal. The default value of this is ReferentiallyEqual which just determines if the two value objects have the same reference. This works for an immutable value object but if the value object can change, there is also a StructurallyEqual option that checks if the properties of the two value objects are equal.

In this case, the ReferentiallyEqual will be used since I will create a new Tweet class any time the data needs to change. I can update the onCreate() function to implement the state.

The same is needed in the preview function.

With that in place, the TweetView function can now use the state to setup the data and listeners. First, the Tweet is pulled out of the MutableState using the value property.

Accessing the value property in TweetView subscribes it to any changes to the MutableState. When the Tweet object changes the new data will be sent to TweetView, which will display it.

Each of the three listeners: commentClick, retweetToggle, and likeToggle need updates in order to work with the new immutable Tweet object. The copy() function is used heavily to modify only the necessary data. The commentClick function is a good place to start since the logic is straightforward.

The new count value is calculated from the current Tweet value. This new count is fed to the copy() function to create a new Tweet object for the updated state. Setting the new state is as simple as setting the value on the MutableState object.

Similar logic is applied to the retweetToggle and likeToggle listeners. These are slightly more complex because they decide how to modify the count based on the current toggle state.

With this in place the app should build and run successfully. It should also function the same as before. Clicking on the comment action increments the comment count, while clicking on retweet or like toggles the count up and down.

Now the Tweet class is immutable but the state can still be changed thanks to MutableState. This class will be a big help in projects because having immutable data classes for the state value requires more explicit changes for the state.

My next post will focus on showing a profile image for the user, which will wrap up the basic Tweet view. Further posts will show how to display a list of Tweets as well as how to show a floating action button over the list.

Thanks for reading and stay tuned for more!

Photo by Michal Czyz on Unsplash.