In current roc, it's common to have a pipeline where the final stage is applying a tag. For example:
pipe =
thing
|> doSomething
|> Wrapper
In the dot-syntax world, this could be replicated with pass_to, maintaining the nice unidirectionality.
pass_to_style =
thing
.do_something()
.pass_to(Wrapper)
But would it make sense to allow tag application to look like a method call?:
method_style =
thing
.do_something()
.Wrapper()
So, a thread to discuss trade-offs, practicality, and offer opinions.
my immediate reaction is that it looks strange to me, but I could also find myself getting used to it and liking it because it makes a common case more concise without making it less clear
One thing that occurred to me is that it might be strange to pass extra payloads that way. Presumably "one".Wrapper("two") would be the same as Wrapper "one" "two".
Maybe method style tag application should be restricted to .Wrapper()?
pass_to could still handle multiple payloads via a lambda: something.pass_to(\x -> Wrapper "first" x)
I could see arguments either way on that
It's not a new issue really, "first" |> Wrapper "second" is already possible, and not really a problem I guess
I believe with the current proposal, wrapping multiple values would be this:
"one".pass_to(Wrapper, "two") to get Wrapper "one" "two"
I'd personally be pretty against that code. Just assigning an intermediate variable is much clearer.
I think piping works normally because you are "acting upon" the piped value.
In this case it just looks weird to have two args.
It's the kind of thing I would do at the time thinking I'm being clever, and then also call out in other people's PRs :sweat_smile:
To be fair, I don't think I have ever pipe to a tag that took more than one arg
So yeah, I would probably add an intermediate variable
I do because it's convenient, and then get unhappy when I see the code again
I just see no reason to deny that if it works with local functions
So it's probably better to incentivize tags in the front
hmm....
fair enough
Putting a tag (especially Ok) at the start of an expression often feels like introducing noise to me. I find it's nice to put the Ok off to the right so the content is emphasised, rather than the wrapper.
I wrote this for an advent of code solution, and chose to pipe to Ok, even though the expression to the left reads RTL.
when char is
'[' -> Open Square |> Ok
']' -> Close Square |> Ok
'<' -> Open Angle |> Ok
'>' -> Close Angle |> Ok
'(' -> Open Round |> Ok
')' -> Close Round |> Ok
'{' -> Open Curly |> Ok
'}' -> Close Curly |> Ok
other -> Err (InvalidChar other)
Potential other ways to write this with dot/brackets syntax:
prefix only:
Ok(Open(Square))
mixed direction with method style:
Open(Square).Ok()
Open(Square).pass_to(Ok)
method only:
Square().Open().Ok()
keep the pipe:
Open(Square) |> Ok
Out of those, I prefer the 'keep the pipe' option. I don't think it looks good in multi-line dot chains though.
Last updated: Jun 16 2026 at 16:19 UTC