Working with arrays, collection and maps

Mapping arrays, collections and maps is either easy as mapping ordinal properties. Elements of the collections will be converted according to the type of the target collection. Collections should be the same arity.

  a.children = b.details.kids      // List<Child> <-> Set<Kid>
  a.options = b.details.properties // Map<String, Object> <-> Map<Integer, Object>

We can access elements of a array/collection/map defining an index/key in square braces. When a Collection/Set is accessed by index the required element is retrieve using collection's iterator.

  a.children[0] = b.details.favoriteKid
  a.educationName = b.details.educations[0].name
  a.educationDescription = b.details.educations[0].description

  // the same approach is applicable to Maps
  a.options["birthdate"] = b.details.birth
  a.options["name"] = b.name
  a.options["lastName"] = b.lastName

A negative integer (I prefer -1) can be specified as an index of an array or collection. In this case Nomin adds an element to the tail of an array/collection. The next snippet shows a possible usage.

  a.options[-1] = { if (condition1) new Option1(...) }
  a.options[-1] = { if (condition2) new Option2(...) }

If condition1 is false and condition2 is true we get the result as an array/collection with the only Option2 instance. This feature can be applied for writing values because there is no meaning to read elements with a negative index, so an exception will be thrown at runtime.

You can use hints or dynamic hints to specify needed types.

  a.children = b.details.kids // List<Child> <-> Set<Kid>
  hint a: List[ExtendedChildren], b: Set[ExtendedKid]

  a.options = b.details.properties // Map<Object, Object> <-> Map<Object, Object>
  hint a: Map[String, Person], b: Map[Integer, Employee] // use hint to specify types
  // or
  hint a: Map[String, {
    it instanceof LinearManager ? DetailedPerson : Person // Person is returned if it is an Employee
  }]

Here is the special case when a custom conversion is used with Map properties. A closure gets a Map.Entry value as the only parameter and should result exactly with a tuple [key, value]. The next sample shows the idea.

  a.options = b.properties // options is Map<String, String> <-> Map<Integer, Object>
  // just convert keys and values to strings or integers
  convert to_a: { e -> [ String.valueOf(e.key), String.valueOf(e.value) ] },
          to_b: { e -> [ Integer.valueOf(e.key), Integer.valueOf(e.value) ] }

Absolutely identical the above you can define conversions between a Map and a Collection/array property.

  a.options = b.props // Map <=> List<String>. Strings in the list are formatted as 'propertyName=propertyValue'
  convert to_a: { String s -> [ s.split("=")[0], s.split("=")[1] ] },
          to_b: { e -> e.key + "=" + e.value }