Search code examples
scalarecursioninsertmutationujson

Understanding this Mutable Recursive Function using the uJson library


I am trying to implement an insert function using the ujson library:

Here is my attempt:

import ujson.{Obj, Value}
import upickle.default._

object Example extends App {
  def r = transform(
    List(Map(
      "a" -> Map("b" -> Obj("c" -> List(1,2,3), "d" -> List(2,4,6))), 
      "e" -> Map("f" -> Obj("g" -> List(1,2,3)))))
  ).to(Value)

  def insert(j: ujson.Value, k: String, v: ujson.Value): Unit = j match {
    case a: ujson.Arr => a.arr.foreach(e => insert(e, k, v))
    case o: ujson.Obj =>
    if (o.obj.keySet contains k)  o.obj(k) = v
    else o.obj.values.foreach(e => insert(e, k, v))
    case _ => Nil
  }

  println(r)
  insert(r, "b", transform(None).to(Value))
  println(r)
}

However, this gives me output that is unchanged:

[{"a":{"b":{"c":[1,2,3],"d":[2,4,6]}},"e":{"f":{"g":[1,2,3]}}}]
[{"a":{"b":{"c":[1,2,3],"d":[2,4,6]}},"e":{"f":{"g":[1,2,3]}}}]

Given that the Value type is mutable, why does this not mutate and update the key, k, with value v for json value object r?


Solution

  • You are creating Value anew every time you call r so, every changes you would make to it, are dismissed.

    You create one copy when you call println(r).

    Then you create a separate copy with insert(r, "b", transform(None).to(Value)), mutate it and dismiss.

    Then you are creating third copy with another println(r).

    If you want to refer to the same object use val instead of def.