Posted on • Edited on • Originally published atitazura.io
Immutable Updates of Objects in Reason
I've recently been playing around with objects in ReasonML and reading about using them in OCaml to get a better understanding, as there is a lack of good documentation on their use in Reason. So I thought I'd try and writing something about one of the interesting and lesser-known features of objects in ReasonML.
I am sure none of this will come as a surprise to a seasoned OCaml developer, but like many developers, I have no experience with Ocaml and keep finding out new features that can also used in our projects.
In ReasonML the spread operator is a great piece of syntactic sugar that makes immutable updates quick to implement, similar to the copy method of case classes in Scala. I was happy to find out that this was also possible with objects, allowing the creation of immutable, but updatable, objects. In OCaml, these are known as functional objects.
Most ReasonML developers have come across the syntax below to update immutable records:
typecat={name:string,age:int};letkitten={name:"Charles",age:1};letoldCat={...kitten,age:4};
A similar technique exists for objects; however, it's not so well known amongst Reason developers, as I believe it is not included in the documentation. So at first, you might attempt something like the example below, which works but quickly becomes verbose as your records grow in size:
classimmutableDog(name,age)={as_;pubgetAge:int=age;pubgetName:string=name;pubsetName:string=>immutableDog=newName=>newimmutableDog(newName,age);pubsetAge:int=>immutableDog=newAge=>newimmutableDog(name,newAge);};
Instead, you can override values to make a new instance with only the specified updates, similar to records. The syntax is not so obvious:
classimmutableCat(name,age)={as_;valname=name;valage=age;pubgetAge:int=age;pubgetName:string=name;pubsetName=newName=>{<name:newName>};// Creates a new instance.pubsetAge=newAge=>{<age:newAge>};};
I believe this syntax is known as the override construct{< ... >}
, which returns a copy of the current object and allows you to override the value of instance variables or methods.
Let's see what it looks like in action:
letmyImmutableCat:immutableCat=newimmutableCat("Cool Cat",5);letmyNewCat:immutableCat=myImmutableCat#setName("Dave");// does not change myImmutableCat
It is also possible to update values in the same way:
classimmutable=(number)=>{as_;valcounter=number*number;pubmakeNegative={<counter:-counter>};pubgetCounter=counter;};letmyImmutable=newimmutable(4);letnegative=myImmutable#makeNegative;myImmutable#getCounter// 4negative#getCounter// -16
Thanks for reading, I hope you found this post useful and legible!
Based on a post in a series onusing objects in Reason atitazura.io
Top comments(2)

- Location横浜
- EducationMSc Computer Science
- WorkSoftware Engineer at Coursebase
- Joined
I presume because objects don't print as nicely as records. As reason will try to print the methods alongside the values.
Js.log2("Does this work", myNewCat);"Does this work" [[4,15,null,-278822339,null,243512077,null,461513217,null,588852681],16,"Cool Cat",5,"Dave",5]
One way would be to add ashow
method to all your objects, where you manually make a string.
class immutableCat(name, age) = { as _; val name = name; val age = age; pub show = "Cat {name: " ++ name ++ ", age: " ++ string_of_int(age) ++ "}";};let myImmutableCat: immutableCat = new immutableCat("Cool Cat", 5);let show = obj => obj#show; // put this in a Utility module somewhereJs.log2("Does this work", show(myImmutableCat));
For further actions, you may consider blocking this person and/orreporting abuse