Stream: ideas

Topic: parenthesis and naming


view this post on Zulip Brendan Hansknecht (Mar 21 2022 at 17:54):

So arguably, this is just me not knowing how to write good roc/pipeline enough, but one thing I find annoying in Roc is when I have to add an extra function and it requires a set of parenthesis.

A common example is when with integer size mismatches. Here is an over extreme example of what I mean:

out = Num.shiftRightBy x y

Oh wait, x is a U64, not a Nat:

out =Num.shiftRightBy (Num.toNat x) y

Oh wait, I actually want to shift y like an I64, not a U64:

out = Num.toU64 (Num.shiftRightBy (Num.toNat x) (Num.toI64 y))

Hmm... That line looks gross, let's split it up:

x = Num.toNat x
y = Num.toI64 y
out = Num.toU64 (Num.shiftRightBy x y)

Oh wait, I can't shadow x and y in roc:

x1 = Num.toNat x
y1 = Num.toI64 y
out = Num.toU64 (Num.shiftRightBy x1 y1)

This of course gets worse as lines get longer and the parenthesis start to really add up.

Also, it is kinda annoying to need to go x1 x2 x3 if I have to modify a value multiple times. I think it makes some code much harder to read. Maybe that is some form of mutation bias. This pushes me to want more on the same line, but that leads back to the tons of parenthesis problem

I think always using the same name is also really useful to ensure that you will always enable the roc compiler to optimize to not have copies. If I only ever have access to the newest version of a variable, I can't accidentally reference an old versions.

Anyway, I don't really have a direct solution or idea, I have seen differing solutions like $ in haskell or just shadowing in general like you would see in rust.

Overall wondering what peoples thoughts are/how this could be better. Might just need to change how I write code.

view this post on Zulip Zeljko Nesic (Mar 21 2022 at 18:13):

My hunch is that editor will solve your problems :)

view this post on Zulip Richard Feldman (Mar 21 2022 at 18:32):

Brendan Hansknecht said:

out = Num.toU64 (Num.shiftRightBy (Num.toNat x) (Num.toI64 y))

thoughts on this?

out =
    Num.toNat x
        |> Num.shiftRightBy (Num.toI64 y)
        |> Num.toU64

view this post on Zulip Richard Feldman (Mar 21 2022 at 18:33):

(personally that's how I'd write it!)

view this post on Zulip Richard Feldman (Mar 21 2022 at 18:34):

if x had a longer name, I'd probably go one step further:

out =
    x
        |> Num.toNat
        |> Num.shiftRightBy (Num.toI64 y)
        |> Num.toU64

but I generally think it looks kinda weird when a super short variable name is alone at the beginning of a pipe :big_smile:

view this post on Zulip Richard Feldman (Mar 21 2022 at 18:34):

out =
    something
        |> Num.toNat
        |> Num.shiftRightBy (Num.toI64 somethingElse)
        |> Num.toU64

view this post on Zulip Brendan Hansknecht (Mar 21 2022 at 18:56):

Ok. So a lot of pipelining. That will definitely take my brain to some getting used to. Definitely more readable.

Out of curiosity, what would you do with something like this?

t0 =  someCalculation
t1 =
    if t0 >= range then
        t0 - range
    else
        t0
t2 =
    if t1 >= range then
       modWithNonzero t1 range
    else
        t1
# use t2

Can the repeated version naming be made better?

view this post on Zulip Kevin Gillette (Mar 21 2022 at 18:56):

At least in other languages, I tend to just give sub-expressions their own names on separate lines

view this post on Zulip Kevin Gillette (Mar 21 2022 at 18:58):

I feel pipelines are better suited to single-value transformations (rather than binary operations, which feel unbalanced to me when using pipelines)

view this post on Zulip Brendan Hansknecht (Mar 21 2022 at 19:00):

I agree, but then you have to name the sub-expressions which is part of the problem I have.

view this post on Zulip Brendan Hansknecht (Mar 21 2022 at 19:01):

In some functions there will be a lot of these.

view this post on Zulip Kevin Gillette (Mar 21 2022 at 19:24):

sometimes it works out to decompose those into smaller functions, but not always

view this post on Zulip Brian Carroll (Mar 21 2022 at 19:32):

I go out of my way to give subexpressions names that are "whatever I would put in a comment", or some reason why I'm doing the operation. Sometimes that ends up being really low-level like limited or rounded or something but reasons why are better names. I think it's valuable for debuggability / readability.

view this post on Zulip Brian Carroll (Mar 21 2022 at 19:39):

I mean, obviously that's how to name things! The point is I still like to do that even for small things like this because it helps me think through it and understand my own code.

view this post on Zulip Richard Feldman (Mar 21 2022 at 20:45):

Brendan Hansknecht said:

Out of curiosity, what would you do with something like this?

t0 =  someCalculation
t1 =
    if t0 >= range then
        t0 - range
    else
        t0
t2 =
    if t1 >= range then
       modWithNonzero t1 range
    else
        t1
# use t2

for this one I might extract a helper function:

ensureBelow = \num, minimum, transform ->
    if num >= minimum then
        transform num minimum
    else
        num

someCalculation
    |> ensureBelow range Num.sub
    |> ensureBelow range modWithNonzero

view this post on Zulip Richard Feldman (Mar 21 2022 at 20:47):

I'd assume this would end up inlining to the original

view this post on Zulip Brendan Hansknecht (Mar 21 2022 at 21:01):

Yeah, my brain definitely does not think this way. Very interesting. Thanks!

view this post on Zulip Richard Feldman (Mar 21 2022 at 21:05):

happy to help! It took me a lot of Elm usage to learn about patterns like these :big_smile:


Last updated: Jun 16 2026 at 16:19 UTC