Side Effects


Dart, like many other languages, uses pass-by-reference for complex objects, and pass-by-value for simple objects. This can occasionally be confusing or surprising to someone new to the language. It may not always be clear when your function will have side effects or not. So I decided to create a simple project which helps highlight when you can expect your function to have side effects.

This post uses terminology which is totally wrong. See my follow up post Side Effects may include… Being Wrong! The table here is still good, but has been slightly modified to accurately reflect the terminology and what is going on under-the-hood. Apart from that I’m leaving the remainder of the post as is, however please, please please read the follow up post.

The code can be downloaded directly from my side_effects Github Repository. For the impatient of you, a table summarizing the results can be found below:

Type Immutable Mutable
bool Yes No
num Yes No
int Yes No
double Yes No
String Yes No
List No Yes
final List No Yes
Map No Yes
final Map No Yes
Class No Yes
List Value
(Eg: list[0])
Dependant on
value’s type
Dependant on
value’s type
Map Value
(Eg: map[‘one’])
Dependant on
value’s type
Dependant on
value’s type
Class Value
(Eg: myClass.prop)
Dependant on
value’s type
Dependant on
value’s type

Of note in particular is the final version of List and Map. Both will allow new elements to be added, and existing elements to be modified

In my example, I wanted to test both adding a value, as well as modifying a value. For the basic types, there really isn’t a distinction worth noting. However for more complex types like List and Map one can either change the value, or add a value to the collection so I wanted to demonstrate both, though both behave similarly. In order to accommodate multiple functions which can could be used for the tests, without being too repetitive, I used a typedef for a modify function, and in my testing function, accepted a modify function as an argument.

library side_effects;

typedef void modify(var arg);

// ...
void testFunction(var arg, modify mod) {
  if(arg is num) print('Testing Num:'); // Num captures int, double and num types
  if(arg is bool) print('Testing bool:');
  if(arg is String) print('Testing String');
  if(arg is List) print('Testing List:');
  if(arg is Map) print('Testing Map:');
  if(arg is SideEffect) print('Testing class SideEffect');
  if(arg is PartialEffect) print('Testing class PartialEffect');
  print('Before call: $arg');
  print('After call: $arg\n');

I then used two separate functions for testing the add or modify scenarios. I’ll just include a couple of lines from each as they are slightly verbose

void addOne(var arg) {
  if(arg is num) arg += 1; // Num captures int, double and num types
  // ...

void modifyOne(var arg) {
  if(arg is String) arg = "Completely Different";
  // ...

I also wanted to test classes in two different ways, I wanted to test modifying the class properties directly, as well as passing the class properties to the various modify functions themselves. To account for that, I created two identical classes with slightly different names which addOne and modifyOne could test for directly. Thus I created the classes SideEffect and PartialEffect. Each of these also overrides the toString method to provide better output than simply ‘Instance Of...‘.

Clone and run the application from the Github repository, look at the source in bin/side_effects.dart and let me know any thoughts you may have. For me, coming from other similar languages, the behaviour of String was a surprise to me. But for those unfamiliar with the language, I think side-effects of a function should be clearly understood early on, as they can cause some frustrating bugs to pop-up if you don’t consider them.

This entry was posted in Dart and tagged , , . Bookmark the permalink.

Have Something To Add?

Loading Facebook Comments ...
Loading Disqus Comments ...