Atoms

Sometimes it's useful to represent a concept that doesn't necessarily have any meaningful "data" apart from a name. For example, you may want to represent the states of a simple street-light (i.e. red, yellow, or green).

Claro's atoms provide a clean solution for modelling these states:

Fig 1:


atom Red
atom Yellow
atom Green

Now, you can write code that directly uses these Red, Yellow and Green as values.

Fig 2:


random::forSeed(1)
  |> random::nextNonNegativeBoundedInt(^, 3)
  |> var r = ^;

var lightColor: oneof<Red, Yellow, Green>;
match (r) {
  case 0 -> lightColor = Red;
  case 1 -> lightColor = Yellow;
  case _ -> lightColor = Green;
}
print(lightColor);

Output:

Red

Static Validation

You could try to use strings for this purpose, but then you would need to do runtime string equality checks throughout your codebase to distinguish one state from another as their types would all be the same, `string`, and even worse you open yourself to simple typo bugs.

Using atoms, Claro will catch any accidental typos for you at compile-time:

Fig 3:


random::forSeed(1)
  |> random::nextNonNegativeBoundedInt(^, 3)
  |> var r = ^;

var lightColor: oneof<Red, Yellow, Green>;
match (r) {
  case 0 -> lightColor = Red;
  case 1 -> lightColor = Yelow;  # <-- Claro will catch this misspelling for you.
  case _ -> lightColor = Green;
}
print(lightColor);

Compilation Errors:

atoms_EX3_example.claro:8: No variable <Yelow> within the current scope!
  case 1 -> lightColor = Yelow;  # <-- Claro will catch this misspelling for you.
                         ^^^^^
atoms_EX3_example.claro:8: Invalid type: found <<UNKNOWABLE DUE TO PRIOR TYPE VALIDATION ERROR>>, but expected one of (<Red, Yellow, Green, oneof<Red, Yellow, Green>>).
  case 1 -> lightColor = Yelow;  # <-- Claro will catch this misspelling for you.
                         ^^^^^
2 Errors

Ad-Hoc "Enums"

Unlike many other languages, if you want to define a type that has only a limited set of possible values you don't have to declare an "enum" ahead of time. Instead, Claro encourages modeling this using the builtin oneof<...> type as in the example above. It can be useful to define an alias to represent the "enum" in a concise way if it's widely used:

Fig 4:


alias LightColor : oneof<Red, Yellow, Green>

random::forSeed(1)
  |> random::nextNonNegativeBoundedInt(^, 3)
  |> var r = ^;

var lightColor: LightColor;
match (r) {
  case 0 -> lightColor = Red;
  case 1 -> lightColor = Yellow;
  case _ -> lightColor = Green;
}
print(lightColor);