Stream: ideas

Topic: Tags and dot syntax


view this post on Zulip Alex Nuttall (Dec 10 2024 at 20:16):

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.

view this post on Zulip Richard Feldman (Dec 10 2024 at 20:39):

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

view this post on Zulip Alex Nuttall (Dec 10 2024 at 20:50):

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)

view this post on Zulip Richard Feldman (Dec 10 2024 at 20:54):

I could see arguments either way on that

view this post on Zulip Alex Nuttall (Dec 10 2024 at 20:56):

It's not a new issue really, "first" |> Wrapper "second" is already possible, and not really a problem I guess

view this post on Zulip Brendan Hansknecht (Dec 10 2024 at 21:18):

I believe with the current proposal, wrapping multiple values would be this:
"one".pass_to(Wrapper, "two") to get Wrapper "one" "two"

view this post on Zulip Eli Dowling (Dec 11 2024 at 01:53):

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:

view this post on Zulip Brendan Hansknecht (Dec 11 2024 at 02:32):

To be fair, I don't think I have ever pipe to a tag that took more than one arg

view this post on Zulip Brendan Hansknecht (Dec 11 2024 at 02:32):

So yeah, I would probably add an intermediate variable

view this post on Zulip Sam Mohr (Dec 11 2024 at 02:32):

I do because it's convenient, and then get unhappy when I see the code again

view this post on Zulip Brendan Hansknecht (Dec 11 2024 at 02:32):

I just see no reason to deny that if it works with local functions

view this post on Zulip Sam Mohr (Dec 11 2024 at 02:33):

So it's probably better to incentivize tags in the front

view this post on Zulip Brendan Hansknecht (Dec 11 2024 at 02:36):

hmm....

view this post on Zulip Brendan Hansknecht (Dec 11 2024 at 02:36):

fair enough

view this post on Zulip Alex Nuttall (Dec 11 2024 at 11:05):

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