Got my first unit test with PNC to work - alongside whitespace application. Long way to go, but I'll use this thread to collect feedback and share progress
THese two are passing
#[test]
fn single_line_application_with_parens() {
expr_formats_same(indoc!(
r"
combine(peanut_butter, chocolate)
"
));
}
#[test]
fn multi_line_application_with_parens() {
expr_formats_same(indoc!(
r"
combine(
peanut_butter,
chocolate
)
"
));
}
Any especially tricky cases you'd like to see tested let me know
And yes, I will make the second case allow trailing comma and make sure it formats to that
One really nice feature in some language formatters: if you add the trailing commas, it formats to multiline. If you delete the trailing comma it formats back to single line.
Note: I think they generally will still override and go to multiple if a line gets way too long
I can do that
Brendan Hansknecht said:
Note: I think they generally will still override and go to multiple if a line gets way too long
I like the "trailing comma means I want multiline" idea, but I don't think we should enforce line lengths in any way.
having spent a lot of time with formatters that do and don't enforce line lengths, I still find the line lengths enforcement a significant source of annoyance and not a significant source of helpfulness
Thank you for that Richard! And I agree totally
that said, I do think having a line-length-enforcing formatter would be helpful for docs generation, because then we can tell it exactly how many monospace chars are going to be available on the page, and wrap gracefully based on that (since there's no way to avoid wrapping in that scenario)
and sometimes we want to generate inferred types for docs that weren't annotated, so in those cases we have to add line breaks somewhere anyway
but I think that's a separate use case, and I don't think roc format
should enforce at all :big_smile:
I think for docs you don’t really need tooling
agreed, but I do think it would be helpful (someday) when it comes to wrapping!
another way to think of it: if we don't have our own wrapping logic, the browser is going to decide how to wrap on overflow, and it's not going to look right (compared to if we did it ahead of time)
Yeah you’d want that tool to output differently wrapped output based on screen width
Which would require a derivative of the “A prettier printer” algo
yeah, we could (for example) include different wrapping widths at different breakpoints in the HTML, and then hide all but 1 of them as the screen resizes
so you're only ever seeing one, but they've all been precomputed to look nice at a few different widths
You’d probably want to move our formatter to using a prettier algo, with a default width of Infinity.
that could work! :+1:
I've run into a weird failure with the test_fmt tests: I get that these are not the same, but I've tested in my editor and these are byte for byte equivalent:
combine(
mix(vodka, gin),
FoodItems.Juices({
< color: Colors.orange,
< flavor: Flavors.orange,
> color: Colors.orange,
> flavor: Flavors.orange,
amount: 1 + 2,
}),
)
Has anyone ran into this before, and what things should I be looking for?
Are there escape sequences being hidden?
Sam Mohr said:
Are there escape sequences being hidden?
I can check, but my editor sure didn't catch it. I copied one line, but it in find and it finds both lines
Try manually typing, copy-paste would hide the issue
Screenshot 2024-12-27 at 9.42.04 AM.png
I did that as well
Super weird. Probably not worth the investigation
So I should get rid of the test?
Can you not just update the result?
This isn't a snapshot
This is an indoc test
You can comment it out and I'll try to fix it once this gets to the PR stage
24 messages were moved from this topic to #contributing > 🚨 Whitespace application and whitespace - breaking change! 🚨 by Anthony Bullard.
Another interesting bit.
Currently creating a Type with type parameters has this syntax:
List a : [Cons a (List a), Nil]
But with PNC right now this would look like:
List(a) : [Cons(a, List(a)), Nil]
Is that lhs desired? or would we instead expect
List : a -> [Cons(a, List(a)), Nil]
I honestly don't know which why I'd go with this, but this does give it the feel of List is a type that needs a type arg a
to be supplied for it to be "applied" and made concrete.
Another advantage of the latter is that any form of application in types would be uniform
Well of course I didn't think about the obvious problem - this is not obviously distinguishable from a Function type being defined :-(
So I guess List(a) : [Cons(a, List(a)), Nil]
it is! Unless someone else has a genius idea here
This is the only real example from the static dispatch proposal, and it is using non-PNC syntax for this one and only case, and I don't think that's a good outcome:
Sort a : a
where a.order(elem, elem) -> [LT, EQ, GT]
@Richard Feldman if you could opine here, that would probably help unblock me.
current plan is to leave type syntax completely unchanged relative to today
we can discuss in a thread if we want to make changes, but currently no plans to change anything
So only when using the constructors as values?
I think seeing Cons a (List a)
in a type annotation and Cons(123, Nil)
when used as a value might be....confusing
But maybe not more confusing than Str, Str -> Str
/ |a, b| a
contrast
it's a fair point, but we haven't discussed it before, and I think we should discuss before making any implementation changes :big_smile:
So here is the first Roc program to compile with 100% PNC usage:
app [main!] {
pl: platform "../../basic-cli/platform/main.roc",
}
import pl.Stdout
import pl.Stdin
import pl.Stderr
main! = \_args ->
tick!({})
tick! = \{} ->
try Stdout.write!("Enter a number: ")
when Stdin.line!({}) is
Ok(str) ->
num =
Str.toU8(str)
|> Result.withDefault(255)
|> addOne()
try Stdout.line!("Did you write $(Num.toStr(num)) (Y/n)")
when Stdin.line!({}) is
Ok "n" -> Ok({})
Ok _ -> tick!({})
Err _ -> Err(Done)
Err(EndOfFile) ->
try Stderr.line!("EOF")
Err(Done)
Err(StdinErr(_)) ->
try Stderr.line!("Couldn't read from stdin")
Err(Done)
addOne = \n ->
if n == 255 then
255
else
n + 1
It's very dumb, but it was something that was quick to translate...working on migrating some of my AOC
(NOTE: This is with PI as well)
PR is up: https://github.com/roc-lang/roc/pull/7421
This doesn't look like correct PNC:
num =
Str.toUtf8(str)
|> Result.withDefault 255
|> addOne
Should be:
num =
Str.toUtf8(str)
|> Result.withDefault(255)
|> addOne()
You got me. I’ll fix that
Thanks for pointing that out Brendan, think I caught a formatter error
I just wanted to share this, from someone I know who's planning to try Roc soon and who didn't know PNC was coming:
This is super exciting stuff. My only points of friction are not having a version manager and getting used to the omitted parens
(I told him about our "cli versions itself plans, and asked to clarify if the second thing was referring to whitespace calling)
Yeah having spaces only is a trip for me, as I’m already dyslexic and struggle to read code I’ve been used to for years, but I know this isn’t a roc thing, I’ve seen it in other languages in the functional world
But, I’m excited to play with it
And an optimistic that my brain will adjust
Nice to hear!
(I explained about PNC)
Wait
You have parenthesis now?
I wonder if people with dyslexia and maybe mild forms of ADHD struggle to parse whitespace application as a general rule? Maybe the parens and then commas help guide their eyes from left to right?
Would be interesting if there has been any science done on something like that
(yup!)
:tada:
Hell yeah! I didn’t expect that. I think that was literally my only “I don’t know if I can read/write this” point when looking at the language lol
The parenthesis stuff was my biggest worry
And prob the main thing that kept from digging in sooner
It’s always been on my list, literally an apple notes list I have to play with new tech, roc has been there since [before he'd even met me]
Anthony Bullard said:
I wonder if people with dyslexia and maybe mild forms of ADHD struggle to parse whitespace application as a general rule? Maybe the parens and then commas help guide their eyes from left to right?
yeah it's the first time I've heard of it, but it was really heartwarming to hear! :smiley:
makes me feel better about the loss of aesthetics I like, knowing that for others the benefit is much more than aesthetic
Yes, a lot of things that make a language easier to parse for a computer, makes it easier for (many) humans to parse
Us humans just have a lot more natural variance than computers
also, this is someone who has done Gleam in the past, so it's interesting that whitespace calling was specifically a barrier to trying Roc where functional semantics weren't at all a barrier (this is someone coming from an imperative background)
anyway, thanks to all who made it happen! :smiley:
Last updated: Jul 06 2025 at 12:14 UTC