smol projects

a troublesome way to return "different types" in nim

16.11.2023 2 min read

Recently, I came across a kata. It went something like this:

Given a string, return the first character that is repeated. If there are no repeating characters, return -1.

So, a few issues here. Nim doesn’t allow union return types - it seems like return types have to be known at compile time So, what can we do instead? How close can we get?

Here are the results of my research:

type IntOrStr = enum
    Int, String
type Result = ref object
        case kind: IntOrStr
        of Int: intVal: int
        of String: strVal: string

proc findSomething(s: seq[string], t: string): Result =
    let idx = s.find(t)
    if idx == -1: 
        return Result(kind: Int, intVal: idx)
        return Result(kind: String, strVal: s[idx])

let res = findSomething(@["a", "b", "z"], "z")
case res.kind:
    of Int: echo res.intVal
    of String: echo res.strVal

First, we define an enum. The enum will contain the possible types that our custom variant type can hold.

Next, we define an variant object type. All objects will have a kind, the kind being any one of our enum values. Depending on what we pass to the object constructor, different object fields will be initialized - intVal if the kind is Int, and strVal if the kind is String.

So, it’s like… fancy objects.

Is it nice that you’re able to do this? I suppose.

Am I happy that I learnt how to use this? Yes.

Do I think it is appropriate for a function to return an index or an element? Not really. If a function returns -1 where an element was not found, it should probably also return an index when an element was found. Alternatively, we can return nil or element. To me, a function that does something like this has overlapping concerns.

Is this worth doing for a kata? …hard no.

Built with Astro and Tailwind 🚀