As a big fan of restrictions, I can’t help but think about the possible loose ends of piping syntax.
Having methods on types allows us to introduce the following rule: the first argument should be either self type or the return type should contain self type and no self type in the arguments.
Foo.method : Foo, Bar -> Baz # instance
Foo.method : Bar -> Foo # static
But not
Foo.method : Bar, Foo -> Baz
Foo.method : Bar, Foo -> Foo
This way all methods with leading self type are instance methods, which is preferable, and others are static methods.
Yes, it's very premature and I didn't think about this long enough. But it seems sane at least on the warning level.
I'm not sure if this restriction is needed. The rule for static dispatch is "If a function is inferred or annotated to take the module's custom type as the first arg, you can call it like a method"
Otherwise, you can't
Also, I don't believe the current syntax plan for methods is Foo.method : ... or Foo.method = |...|, just method : ... or method = |...|
Generally, you call static methods on the class that the static method is defined in, and you can do that today by calling ModuleName.static_method
I probably overcomplicate the idea. Simply said, I would expect self type to be always as the first argument if it's present in args. It's probably a preference, but this kind of rule automatically makes piping preferable which is why not given the presence of piping.
In oop (forgive me), static/instance methods are explicitly expressed via self/this. With static dispatch there’s no actual difference between them, it becomes a matter of style, which is great. But there is a chance to encourage the use of pipe as it’s generally more convenient.
I agree with you that if the syntax for defining methods is Foo.method = ..., then this restriction is good!
But I don't think it is
Let's say it isn't
Then what if the type takes two Foo's
Or what if the second arg to the function is a custom type and the first isn't because it's like create_logger_with_config
Of type create_logger_with_config : (Str => {}), LogConfig => (Logger, ExtraInfo)
Where LogConfig is a custom type
I think I didn't understand your proposal properly to start
But re-reading, I think the "method syntax only works if Self is the first arg" is a very strong motivator
I’m talking only about Foo.method : Foo ...
Foo, Foo -> Any is pipeable as a method
Any, Foo -> Any is not
The logger example is a static method. You have no logger in args, so no problems with it
Sorry, when you say piping, do you mean .method or |> method?
Because the latter won't exist in our current plan of Roc
I already live in the future, Sam :grinning:
.method
My proposal is “if a method of a type contains the type in the args, it must be the first arg, otherwise it hinders ergonomics of piping via Type.method”
I don't understand the proposal, sorry :sweat_smile:
can you rephrase without using the word "method" since that's not a first-class concept in the language and I'm not sure what it means in this context?
Ok, is signature Wall.paint : Color, Wall -> Wall allowed according to the static dispatch proposal?
well yeah, you can still write functions of any type you like :big_smile:
Feels like this is predicated on that Wall.paint syntax that we don't plan on supporting
That's what I’d like to avoid, because this signature leads fo this:
wall
.(|x| Wall.paint(White, x))
.addWindow()
With the restriction “if self type is present in args - it should be the first one”, it will always be
wall
.paint(White)
.addWindow()
The problem is, when you design your set of functions, you might think only about this kind of call Wall.paint(...) forgetting about the chaining option. Yes, the whole problem sounds ridiculous. But it might be a nice touch on the warning level. Like, “you may have a convenient chaining on the call site and you evade it? Are you sane sure?”
in general I don't think we should warn for "you wrote a function that had a particular type" :big_smile:
there might be a valid reason for it (e.g. in a DSL), and since warnings fail CI, we're basically saying "never do this even though it might be the best choice sometimes"
When this kind of signature is exported from a third party module, you have to obey. Or create an issue/pr and wait. Or fork and maintain. In any case, call site ergonomics depends on the declaration.
But I agree, it's not a good idea to decide for a developer what is a good signature and what is not.
Most of the developers are likely sane and the situation is hardly possible
It brings me to the inevitability of a roc linter. I remember you mentioned somewhere that you’d like to avoid configurable linters (I might be wrong). But some things such as this may lead to community-driven solutions, which is not bad, but also not as good as a native toolchain.
I like project-specific linting, like "we have decided to stop using this style and want to deprecate it in our code base"
but I think one-size-fits-all "you should not do this" things should either be warnings at the language level, because they really are a mistake on every project (e.g. warnings for unused arguments whose names don't start with _), or else they shouldn't actually be failing peoples' builds
like when people start working around linting rules, that's a really bad sign
Yes, we are on the same page here. My question is - would roc provide a configurable linter or should it be implemented in the userland?
Last updated: Jun 16 2026 at 16:19 UTC