Stream: beginners

Topic: How to define a static method


view this post on Zulip gavr (Apr 04 2026 at 12:35):

I thought that it works kinda like UFCS(from Nim or D)

Person : {name: Str, age: I64}

have_birthday : Person -> Person
have_birthday = |person| {
  { ..person, age: person.age + 1}
}
...

  person: Person
  person = {name: "String", age: 24}
  p2 = person.have_birthday()

But with this code Im getting

This have_birthday method is being called on a value whose type doesn't have that method:
   ┌─ main.roc:35:15
   │
35 │   p2 = person.have_birthday()
   │               ^^^^^^^^^^^^^

The value's type, which does not have a method named have_birthday, is:

    { age: I64, name: Str }

This tutorial only mentions method calling, but not method definition.
https://github.com/roc-lang/roc/blob/main/docs/mini-tutorial-new-compiler.md#method-calling

And here https://github.com/lukewilliamboswell/roc-platform-template-zig/blob/main/examples/all_roc_syntax.roc I see

# Define a nominal type with a custom is_eq method
Animal := [Dog(Str), Cat(Str)].{
    is_eq = |a, b| match (a, b) {
        (Dog(name1), Dog(name2)) => name1 == name2
        (Cat(name1), Cat(name2)) => name1 == name2
        _ => Bool.False
    }
}

Is that possible to define a method for a structural type like my Person?
Or for a third party type defined in other package that I can't change (from this example it seams that its that u should define methods inside type itself like in java, and I dont believe its impossible to define them outside)

view this post on Zulip Anton (Apr 04 2026 at 14:05):

You can define a method like this:

main! = |_args| {
    person: Person
    person = {name: "String", age: 24}
    p2 = person.have_birthday()

    echo!(Str.inspect(p2))
    Ok({})
}

Person := {name: Str, age: I64}.{
    have_birthday : Person -> Person
    have_birthday = |person| {
        { ..person, age: person.age + 1}
    }
}

But I'm pretty sure you cannot add your own method to Person outside the module where it is defined.
You can:

view this post on Zulip Stuart Hungerford (Apr 08 2026 at 05:35):

Does that affect static dispatch for types I don't "own", e.g. adding a new arithmetic static dispatch method to numeric types in the library?

view this post on Zulip Jonathan (Apr 08 2026 at 06:26):

You can't define methods for types that you don't own, i.e. in a module other than where the type was defined (at least that was my last understanding). The "dot" syntax searches the module of the type of the first arg for the function, and so won't find your function.

view this post on Zulip Jonathan (Apr 08 2026 at 06:28):

You can use "->" to dispatch using the first arg for functions in general, like a pipe operator (1->myAdd(2)). Or you can always wrap the type.

view this post on Zulip Stuart Hungerford (Apr 08 2026 at 08:43):

So if I wanted to model say additive semigroups where types could meet that expectation by having a semi_add(a, b) function I could still create my own semi_add() for say integers of some kind. But how would I create a function that expects parameters that comply with additive semigroups?

I realize this is a pretty esoteric example and may be outside Roc's planned scope. Either way it still looks like a really fun and friendly language.

view this post on Zulip Jonathan (Apr 08 2026 at 09:49):

Afaik you can accept "all things that implement semi_add" but semi_add would have to be implemented by the type owner. Outside of just passing in the required semi_add function as an argument to whatever needs it, you can always do this at the value level ("All you need is data and functions", "Scrap your type classes") and create records of functions {value: a, semi_add: a, a -> a} but I think it'll be circuitous and probably (can't speak for the Roc devs) not idiomatic.

Edit: Just saw your comment in another thread referencing the above article :smile:

view this post on Zulip Stuart Hungerford (Apr 08 2026 at 22:39):

Thanks for the clarification. Really looking forward to creating something in Roc.


Last updated: Apr 10 2026 at 12:38 UTC