This is going to look like I'm shitting on static dispatch again, which I don't enjoy, because many people are excited about it and have put in substantial work towards it.
Given what we know now, I'd like us to reflect back on static dispatch. It seems like the SD decision has more downstream consequences and is more disruptive then we expected. There has been a ton of discussion about SD related things, which implies it's not easy to get the details right. I'm also concerned that as we make ever more changes to create a nicely balanced language with SD it will be harder to decide to go back, in case we think the final transformation is not better then the old Roc. A looming 0.1 release and the general desire to be respectful and appreciative of others work also decrease the likelihood of reverting.
So given this additional info, now seems like good time to make sure we still want to do this!
We had a simple well balanced language before SD and it looks like we're taking a substantial risk now.
To remove some doubt on this communication through text, I'm not angry and I don't feel strong emotions about the static dispatch situation. I'm just rationally trying to help us make the best language.
I'm curious to get anyone's thoughts on this!
I think this is very risky. I've been pretty vocal about that - and trying to move us into a different direction. But I think that I understand what we could gain with SD. But I think it would be an interesting exercise to have @Richard Feldman and others list out the pros/cons for SD with their current understanding.
Here's my lists:
Pros:
Cons:
I think it is very important to disambiguate the kinds of discussion. While static dispatch has promoted a lot of discussion and design churn, almost all of it is related to syntax. This says very little about the merit or lack there of for static dispatch. A very direct example is the partial application proposal. That proposal only exists because the syntax suggests that maybe it should exist. Same for many other proposal that came following parens and commas (which was added for static dispatch).
I feel like I see very little deep debate around fundamental designs. Most debates are around what syntax to pick and the possibilities opened by the syntax.
These can be seen as disruptive downstream consequences, but I see them much more as minor syntax debates and new ideas sparked by the changes in syntax.
As for pros and cons of SD...
Pros:
Cons:
+1 to the forcing of typing as laid out in #ideas > Warning for unannotated exposed symbols
Yeah, I think we'll come to wanting mandatory (even if provided automatically by LSP) annotation of all function signatures even if the compiler doesn't need it
It's more than just forcing typing. It is forcing type aliases that are equivalent to interfaces. Like I want to see Hasher a rather than N different functions that relate to hashing.
Yeah, or annotations will be HIDEOUS
Yeah, I don't think I would want the autogenerated annotation on an SD function.
Whether that's in the source text of the program, or in LSP Hover
Yeah....lsp hover may be hard
LSPs can do a lot. Generate a rough one right away, and then offer a code action to refactor a implements clause into a named interface type
Could even find types in the project that meet the interface and allow you to sub the implements with that concrete type
But man, we at that point might want to spool up the Roc Editor again :-)
Anthony Bullard said:
Could even find types in the project that meet the interface and allow you to sub the implements with that concrete type
Yeah, this is fundamentally what I want most. Or, not only for concrete types, but also for interfaces (which are just static dispatch type aliases)
I think even in the short term, just requiring type signatures will make people see how ugly the inferred type is and strive for better
But giving them tools to make it easier would be great, of course
I know it's not quite the original topic, but quick note: it's been one of the longest-standing design goals in Roc to explicitly not require type signatures, to the point where a number of language design ideas have been ruled out just because they would require type signatures.
I always want to keep an open mind, of course, but ever requiring type signatures even in the short term is something I actively want to avoid. :big_smile:
I think if we want to make it easier to annotate top-level things, inline type hints in editors would be a great way to do it
both so you can just see what the type is even if it's not annotated, but also to create an incentive to make it look nicer so you're not seeing a weird inferred type that doesn't know what aliases to use
I think the lack of deep debate here is because Roc's type system with product types, sum types, and typeclasses via abilities or methods are enough to do everything we'd want a PL to do. We just want to make that more convenient now, which is why there's so much syntax discussion
that said, I do like the idea of requiring annotations in order to be accepted in the package index
Yeah, annotations are for people unfamiliar with your code
if you don't want to annotate your bash script equivalent, that's reasonable and makes sense, but we want a high quality ecosystem, and that seems like one of several reasonable quality control checks (alongside "it compiles" and "it was formatted with roc format")
Yep, we shouldn't require it on bash script equivalents, this is mainly for libraries
anyway, here's my list:
Pros:
Json.utf8.transform(CamelCase) over Json.utf8_with({ transform: CamelCase })).get_0() for tuple field access)UserId obviously gets its own UserId.roc so it can get static dispatch, whereas today deciding whether a small type like that gets its own module is a source of unimportant debateDict.empty() compared to today's Dict.empty {})Num.plus can keep Num.add's current Num-focused type instead of having to become something like Num.add : a, a -> a where a implements Add)4.(hours) and 4.(hours).(ago!) are very nice imo, and one of the things people love about Ruby syntax (except in this case with full type-checking instead of monkeypatching)Cons:
UserId in the same module as User and have them both support ==; unavoidable downside that comes with the upside of more obvious module organization)I'm actually not worried about overuse of nominal types, and I agree with Brendan that if they do end up being used more than I think is reasonable, I think the negative consequences would be pretty mild - mostly around code being a bit unnecessarily verbose.
I'd be more concerned about people making architectural mistakes that are harder to fix than realizing "oh hey this could just be a structural type and then my code would be more concise," especially considering programmers usually gravitate towards more concise options by default anyway :big_smile:
structural types do allow for certain patterns of data structure sharing, but I never saw much use of that in Elm, haven't seen much use of it in Roc, and don't really think it's a big deal if a feature that's almost completely unused today becomes even less used
as noted above in the Pros, I agree with Brendan's point that structural ad-hoc polymorphism seems like it has higher potential, especially because it means ecosystems can coordinate either with or without explicit dependencies, whereas with Abilities, explicit dependencies are the only option
The example of Arg := [Unix (List U8), Windows (List U16)] with a .from_raw_arg() method shows the power of methods to avoid needing ecosystem coordination
In a young ecosystem like Roc has, we can't depend on there being a solid foundation for people to rely on for things like HTTP, datetime, UUIDs, etc
So that makes code more modular in an awesome way
Richard Feldman said:
I think if we want to make it easier to annotate top-level things, inline type hints in editors would be a great way to do it
I see you bring this up a lot. But maybe this is Architect / Staff engineer brain - but I read most code in GH / Pull requests. I don’t get that benefit there. And that hurts a lot, and a big reason I hate Java
+3 right there
Was about to write the same thing: if you need an editor to engage with Roc, we're now Kotlin
It’s that way with a lot of languages
Yep
Way GH hasn’t made a VSCode-like interface with LSP interactivity (but read only) as the default for viewing code I’ll never understand
Because that would cost money, right?
And I know, VSCode eww, but people can’t find a way to put Neovim in the browser
Sure, but they make workspaces available for free
At least make it the default for PRs
Maybe some form of required module qualification for "main" expressions in top-level functions and values would help with this readability problem?
I’d pay for that
Sam Mohr said:
Maybe some form of required module qualification for "main" expressions in top-level functions and values would help with this readability problem?
Could you expand on this?
I think that Roc with methods is so simple, the only problem I have with it is readability without module qualification.
Anthony Bullard said:
Richard Feldman said:
I think if we want to make it easier to annotate top-level things, inline type hints in editors would be a great way to do it
I see you bring this up a lot. But maybe this is Architect / Staff engineer brain - but I read most code in GH / Pull requests. I don’t get that benefit there. And that hurts a lot, and a big reason I hate Java
I think there's a big gap between languages with inheritance and those without though
like when I see a method-style call chain in Rust, it takes me a little bit longer to figure out which maps are for collections versus Options/Results compared to module-qualified function calls which just give me the answer right away
I think ad-hoc polymorphism is largely the same issue
well but in that case, we're in the same boat today
e.g. if I call |> Bool.isEq or |> Inspect.toStr, that tells me me anything about the types involved
True, but abilities are so complex to use, I generally don’t (outside of builtins)
so that's not a static dispatch thing, it's an ad-hoc polymorphism thing
Richard Feldman said:
so that's not a static dispatch thing, it's an ad-hoc polymorphism thing
True
I don't think that will change much other than operator overloading
e.g. the realworld code base only used operator overloading compared to today
and in that case the units made the types clear, e.g. in Clock.now!() + 4.(hours) I'm not wondering what types are involved :big_smile:
actually one of the biggest surprises in that code base was how even without inlay hints, I still knew what the types were almost always
one of the things it did make me wonder is whether we should consider renaming map in some cases, because that's the biggest offender right now in terms of ambiguity
like if we have .try(...) as opposed to .and_then(...) I take one look at that and I'm like "oh hey, that's Result.try!"
whereas and_then could be anything
similarly, if I see .map(...) I don't know if it's a collection or a Result or what
of course, that is the accepted name for that operation
We do map and map_err, but map_ok and map_err would make more sense
wow, I love that idea!!!
that would actually make a big difference right away
Name things based on the types!
and it makes it more obvious what the function is doing, wowwww
We didn't used to need this because everything was module qualified, so the Result.map is actually the full name. Now that the full name is just map, we need a better name
yeah, except that .map_ok() is somehow actually more concise and more descriptive than Result.map
they both tell you it's a Result (nothing else uses "ok") but with Result.map you have to know it's operating on Ok
It may make sense to do this for other types... List.map_items? Dict.map_entries?
yeah, so it would be rad if we could find more wins like that
maybe!
or like List.map_elems or something
Those are less obvious than map_ok
yeah
could be worth experimenting with
but yeah, if we could get method-style names that are more self-descriptive in a way that means you can instantly know the types of things involved, while still getting all the other benefits of static dispatch, that would be awesome
For Anthony:
I just want to know what the arg types are on top-level functions when reading someone else's code. One way we can do that without requiring type annotations is for method chains to have the first function call required to be a module-qualified function call instead of a method call. This is tricky because functions can have definitions and control flow, not sure what to do there. If we don't name methods to imply what they're acting on (as suggested just now), then this would be more readable to me:
get_third_valid_item = |items|
List.map(items, |item| foo(item))
.keep_oks(|item| ...)
.get(2)
As opposed to what would now be allowed:
get_third_valid_item =
.map(|item| foo(item))
.keep_oks(|item| ...)
.get(2)
Anyway
for the above naming discussion, this was something I needed to figure out when I wrote Weaver. The name always included the module, so it wasn't SubCmd.required_subcommand, it was more obviously SubCmd.required.
I'd say the top 5 things I'm most excited about with static dispatch are:
4.(hours) (helps balance out some of the longstanding fondness I have for whitespace calling)Any function that will probably be module-qualified should consider the module to be part of the name
So Cli.weave should not be called weave_cli since Roc makes it much easier to do import Cli over import Cli exposing [weave_cli]
In short, I look forward to naming conventions aligning based on functions being primarily used as methods vs. as normal functions
It'd be nice to include this kind of thing in the tutorial
yeah I think a light touch might go a long way here
honestly the biggest situation I've noticed that gives me pause has been specifically not knowing whether .map referred to a collection or to a Result, and map_ok instantly solves that one in a super nice way
and we don't have Option or Maybe, so that's not a problem either
I think it'll be interesting to keep an eye out for what specific scenarios come up where the types feel uncertain, and whether naming tweaks could help
because there is a learning cost to giving everything totally unique names, so ideally we could reach for it only in the specific situations where it's solving a problem
(and obviously in the case of wanting to do ad-hoc polymorphism the names will naturally be the same, but as discussed earlier, that comes with the territory with ad-hoc polymorphism!)
A lot of times, variable names can tell you the type of a thing. emails_per_employee feels like a Dict _ Str/Email, I don't want to have to write dict_* if I can just name the args
yeah, I often use by when it's a dictionary, e.g. users_by_email
sightly off-topic, but when I originally decided to intentionally omit a Maybe or Option type from the stdlib, I really underestimated the positive impact it would have to use Result everywhere
like it's been way more than a nice little simplification
The downside has been worries around discarding the info in the error a la ??, but that's way better than just discarding info about the error case at the type level with Option
To me, map is a more fundamental operation that is free from the container
So knowing the container type isn't really a gain
In fact, it makes it impossible to be generic over the container type
So I prefer everything as simply map
Result is special probably, but a kv list and a dict are the same thing from the perspective of mapping.
Or a list and a linked list
Without HKT, we can't make a map method generic anyway
I think just Result.map_ok may be all we need here, it's a light touch but I suspect will cover the 80%
Sam Mohr said:
Without HKT, we can't make a
mapmethod generic anyway
Not exactly true. The types will be dumb, but it will work.
map_over : (a, (?) -> ?) -> b
What are the two question marks here?
I don't particularly feel qualified to have an opinion, and I'm always in favour of trying things out. That said for me the main cons are that static dispatch brings with it:
foo.dobar(blah).doobaz(blahblah) looks as if dobar and dobaz are in someway features of foo. But they are not, and actually they (or, anyway, any call other than the first) may be operating on things that have a completely different type from foo. Pipelines seem a better metaphor to me (and even they can be over-used). map is not a thing a list can do it is a thing you can do to a list, and it's first argument is no more semantically significant than its second.. (not a very conspicuous little fellow) ends up massively overloaded: sometimes it means decimal point, sometimes it means record field access, sometimes it means call a function.So personally those are downsides which for me outweigh the upsides. But I say that as a total amateur _and_ someone who has spent much more time with functional languages, especially ML-lie ones, so _for me_ the existing patterns are more familiar.
By the way, I am satisfied with the collective reflecting that was done :)
To see a demonstration of these pros/cons, what's the most complete/thorough/realistic example of an SD-ful Roc app?
@JanCVanB see
Cons:
- Removes a significant part of the unique and joyful part of Roc's syntax that made it different from other languages (space based calling)
This, 100%.
I have been hesitant to express too much in terms of negative feelings about the SD changes, as I hugely admire all the thought and work that has gone into the planning (and implementation work thus far), and I believe in the principal of "Disagree and Commit". I also can appreciate many of the benefits, such as doing away with abilities and module imports.
With that said, I also 100% agree on the joyful part of Roc's syntax. There are a few things that drew me to Roc, and many of those are unrelated to syntax, but I will say that Roc has had my favorite syntax of any language I have written prior. That is coming from someone who almost exclusively wrote PNC style languages, except for a little Haskell, which was my first and only exposure to ML style languages. While I found Haskell intriguing, I didn't fall in love with it.
Roc, meanwhile, took many of the things I liked from Haskell and turned them into something I absolutely love. I love the expressiveness of Roc, the freedom from parenthesis hell, and the clear logic flow expressed by the pizza pipe operator. I have found Roc syntax to be some of the most enjoyable I have ever written, and it has really given me an appreciation for ML syntax.
While I am open to trying out SD, and as I said before I do appreciate some of the benefits and even acknowledge that SD may be worth the loss, I have to say that I am definitely among those mourning the change of syntax. I will miss the light use of parens, the expressiveness of qualifiers, and the flow of the pizza operator quite a lot.
What is the principal of "Disagree and Commit"?
https://en.m.wikipedia.org/wiki/Disagree_and_commit
Disagree and commit is a management principle that individuals are allowed to disagree while a decision is being made, but that once a decision has been made, everybody must commit to implementing the decision. Disagree and commit is a method of avoiding the consensus trap, in which the lack of consensus leads to inaction.
Yep, exactly. I mention it because I have been feeling a bit like SD is a done deal, and it’s time to commit, and this has been part of the reason I haven’t expressed much. But since this thread is still kicking, and since SD is not yet here, I thought I’d voice a few last thoughts on the changes before it really is too late to say anything.
I haven't said anything on all the static dispatch changes for similar reasons to Ian, I just want to link to a thread I made a while ago on Roc's syntax :sweat_smile:
Similar story here -- as a pretty casual community member I feel disappointed about the changes in syntax, but understand that it's related to a big ol semantic change that has already been talked to death.
What initially sold me on Roc was the prospect of it being a friendlier OCaml, or a more generalized Elm. I realize it can still be that with a different syntax, but the vibe is different and I'm having a harder time than I really should coming to terms with that.
there are lots of us
Long time lurker here, but wasn't there a thread/conversation about possibly revisiting syntax with spaces once SD is in place and in use? Combining static dispatch with the pizza slice / pipe operator?
Is it this one:
Ah yes, that is the conversation I remember reading. Although I couldn't gather by the end of the conversation if there were concrete plans to revisit static dispatch using spaces and |>. There were some mentions of it, but nothing explicit.
There are no concrete plans to revisit static dispatch using spaces and |>but things may change if we end up not liking static dispatch with parens and commas
I see there's a lot of negativity about the syntax, so I'll be the opposite voice. I suspect that previous Roc syntax naturally attracted people that tend to like whitespace and dislike parentheses which is partly why last messages express negative sentiment (it's big 'vibe' change and because Roc started a certain way I think there's some audience capture at play here).
I came to Roc mainly because I'm somewhat dissatisfied with TS (I've written Golang, some Rust but at work I'm NodeJS dev). I like the subset of TS very much, my opinion is contrary to the mainstream here but it's very flexible language. I don't care that much about the syntax but even in that department TS is imo very good language.
What drew my attention to roc:
For me it being whitespace based language decreased readability and I prefer how realword.roc looks with pnc (talking about richards repo) over how it would look with whitespace syntax. I can get used to any syntax, but even when I do there will still be some cognitive load when jumping between few languages in one monorepo and having them use similar syntax might help in that regard.
Just wanted to leave a comment that not everyone is dissatisfied with syntax changes and there are people that prefer it visually :P To me new syntax is still lovely, just in different way :-)
Thanks for sharing @Dawid Danieluk!
Well, coming from C# and its extension methods, this new syntax feels right at home. I also was drawn to Roc due to F# like (or Elm like) pipe operator, but mostly because I like having functions just transform data from A to B and I want it to be easy to chain call the happy path and make the errors kinda handle themselves.
C# is pretty good at this, all it's missing is build in Result and ? operator (like in Rust).
After watching Casey Muratori "Clean code, horrbile performance" I though of looking for a C# replacement - something still productive, a bit lower level, where I can do everything. There is nothing outthere to do that.
Rust is just too... Rusty to for example replace our 1.6mln lines of C#. Zig is way too low level. Swift is nice, but too closed off and compiler sucks (and doesn't run on Windows too well).
Go? I just don't like it, and I haven't found a good way to use it to build native GUIs.
I have really high hopes for Roc to go straigh into empty bucket - productive, low level language for everything. I don't really care for syntax that much, I just want it to be "nice", with good LSP (C# with Rider is still the best coding experience on the market, I will die on that hill) and good debugger (Rust, I am looking at you).
I like the concept of platforms (as long as they are not blocking, meaning I want to add interproc communication between my GUI instances, but green pipes are not on platform and that's it), I like the functional nature with escape hatches with for loops.
I like the low level. I like the familiarity coming from C# - with static dispatch there is way higher chance that if I show Roc to coworkers, they will like it.
From my side - do whatever you need to do with syntax, just finish the project :)
BTW, C# has expression trees that allow for compile time parsing of lambdas body and for example transform them into SQL and SO MUCH MORE (like autogenerating GraphQL querries) - the ripple effect of this feature is enourmus.
I would LOVE to see something like that in Roc
I feel like for me (someone who comes from the land of parens and commas), roc was initially weird for using space calling convention, but after getting used to it, it was a more whimsical language because of it.
So I think it is losing some vibes and whimsey, but don't think that is really what roc should be optimized for. So I think PNC makes total sense.
I feel like this will mostly end up being collective reminiscing more so than it will be dislike of the new syntax once we all get used to it.
With the caveat of DSLs. I think those generally work better with space calling convention
I'm not worried much about syntax, but as this thread shows (given the proportion of discussion towards it) it does matter a lot, and in terms of attracting people to a language (and as per other examples where reason initially did a good job of attracting people to Ocaml - before politics got in the way).
Great pros and cons summary, Richard thanks for sharing that. Quick thoughts on those:
The cons you mentioned in my view seem fairly minor, but Paul Stanley's first point touched on what I feel is a more important con - possibly less explicit language. But that's probably a flip side of more streamlined ad-hoc polymorphism.
Which is probably a good trade....
I want to revive/start a discussion on the state of WSA. @Sam Mohr does this unresolved topic look better to resolve or resurrect?
Yeah, this is probably a good place to have the discussion
I don't think invoking Godly power is conducive to good discussion, but it seems in all the discussion that we've been having, our BDFN is not planning on WSA being in the language unless there's really strong opposition to PNC.
We have been politely keeping WSA around for the folks that prefer Roc with WSA because it wasn't really getting in the way of all the rewriting work we were doing
For anyone unfamiliar with what "whitespace application" (WSA) means, it's this: five = add 2 3
Thanks for the clarification!
instead of this: five = add(2, 3)
But now, Roc is planning on a giant overhaul that will rewrite not just 90% of the compiler, but 100%
So any features that "weren't in the way" like WSA and abilities were okay to _delay the removal of_, but to add them in the Zig-based Roc compiler would mean we'd now be implementing features that we don't seem to want in the 0.1.0 compiler
Which is "wasted" work, where wasted means it doesn't work towards the current vision of Roc
However, implementing WSA would work to the end of allowing folks that think we could have some future with WSA in Roc long-term to prove their case by showing its benefit over PNC (parens and commas based function calls)
So now, it seems we should collectively decide if we want to implement WSA in the new compiler to fulfill that promise, and I think a lot of the WSA advocates agreed to start with PNC in the first place because of said promise
I think it would be nice to have a single canonical explanation for why WSA is being removed with some answers to common questions such as:
I think if I came to check on roc and discovered it's syntax totally changed I would want a sense that it was well considered if I was to maintain trust in the idea that roc is likely to succeed.
Maybe a "Why does roc looks so different?" with a little summary of some of the recent changes would be good. The recent hacker News conversation about roc was very syntax focused. Like it or not, it's what people notice.
I feel like it would have been great if the top reply to those negative comments could have been a link to a well considered explanation of the reasons behind the changes.
a lot of the WSA advocates agreed ... because of said promise
Yes, before I get into any logical thoughts on PNC, I want to voice this primary emotion without accusing anyone of bad intentions - the deprecation of WSA has felt (and now feels extra) sneaky and dismissive because of how it's seemed that its advocates always get redirected in discussions.
It seems like something that would be required for WSA to happen would be a syntax proposal for using static dispatch with WSA and no PNC
I feel like many people have been quieted in their pushback against PNC because they were told that WSA wasn't going anywhere. Now that it is, it feels appropriate to reach out to everyone who was told that WSA wasn't going anywhere and gauge their discontent if it were to actually disappear tomorrow. I see almost no path for WSA support if it isn't addressed before the rewrite.
I'm not sure who would be in charge of that, but it would move the discussion away from "WSA can't do static dispatch, so it's out of the question"
As for my logical thoughts on the merits of PNC, I think it feels alright and could be the right choice for Roc. However, "not like this" - I just want the community to have a chance to voice their opinions on what's actually happening and have our trustworthy BDFN either approve the democratic consensus or take a firm stance on overriding it.
CC @Richard Feldman
I think this is the wrong thread, can someone with inter-channel perms (@Luke Boswell @Brendan Hansknecht ?) move this discussion block to #ideas > reflecting on static dispatch
I gotchu
Everything in here today?
yep
And then we can ping the WSA advocates in that centralized discussion to see if anyone could take lead on organizing a case for WSA working with static dispatch
24 messages were moved here from #contributing > 🚨 Whitespace application and whitespace - breaking change! 🚨 by JanCVanB.
@Sam Mohr Do you want me to resolve that other thread, then? Or do you want it for implementation chat?
If you're talking about #contributing > 🚨 Whitespace application and whitespace - breaking change! 🚨 , I don't think it matters
Thank you for pushing back here @JanCVanB , I've definitely been more focused on "How can I help implement the Roc I want ASAP?" over "How can I help make Roc a great language that we all like?". It's important to have self-advocates to remind me what's really important.
I never wanted Roc to have two function application syntaxes forever, but it was a great way for us to see how PNC feels without making a big breaking change. If the rewrite is prompting this month to be the syntax choosing month, then we can finally do thorough side-by-sides in that context of finality.
So, in the meantime, I'll ping everyone I see in this thread that seems to have been in favor of keeping WSA (whitespace application) over PNC (parens and commas):
Please read the above discussion to get some context about how we are probably moving up the WSA removal date in light of the Zig rewrite. As such, it falls to someone on the WSA side, ideally one of you, to help us figure out a plan that the team would potentially agree on for a candidate matching the currently planned PNC + static dispatch.
To many in this thread, I expect "moving up the WSA removal date" to read as "creating a WSA removal date"
Now, having done that, a very important disclaimer: please help us work together to have a polite, cooperative discussion that lines up our options side-by-side without this becoming a fight of volume of people or volume of yelling
I feel like the big issue with my own (and others) feelings about WSA is that it's pretty much "I just like it more". That's not really a compelling argument, but it does matter.
Every time I'm writing code in JS and I have to dick around adding and removing brackets to add a new function call... It just sucks. It's not fun and I think "I wish i was writing Ocaml".
It would be a shame to think that while writing roc.
I've not weighed into the WSA PNC debate because u didn't feel like I had much to add, but I feel like I should at least lend my support.
@Sam Mohr Do you see complete feature/support parity between PNC & WSA except for a consensus syntax plan for how to call functions via static dispatch?
Yeah, from an impl side, I don't think there's a reason why one wouldn't work in-place of the other
It just needs us to ensure there's a logical and readable syntax for everything in both WSA and PNC
I make this ping because Roc has found great success in many people with different perspectives coming together to build what they think is the right language. Trying to arrive at a democratically-agreed solution is always preferred because we want everyone to be happy
In terms of feeling, it feels attracting new people from javascript world seems to be the main driver, retaining people from elm world is irrelevant.
Again, it is the full right of the language leadership to choose that direction. I am not a contributor, my opinion is hardly relevant. But it is disappointing from my perspective.
That said, it's not a perfect democracy, because we have a BDFN. I am obviously not Richard, so it's not my place to make a decision, but I am re-opening this real can of worms because it seems that we can't make everyone happy, and no one will be satisfied unless we put fairly considered options on the table and then our BDFN helps us in making a decision
Sam Mohr said:
It just needs us to ensure there's a logical and readable syntax for everything in both WSA and PNC
Since static dispatch isn't yet implemented and the compiler rewrite seems to essentially freeze new feature development in Rust, does that mean that
It might be worth making a thread specifically to list the syntax proposals, with discussion in other threads. I'm not very aware of what has and hasn't already been proposed, and the proposals often just get lost in discussion.
Until something like that happens, it seems like we're cooking up a good deal of unhappiness here
Thank you kindly for helping me reopen this can of worms Sam :smile: :heart_hands:
I am not in favor of keeping WSA. We’ve discussed a number of reasons why we chose PNC to enable static dispatch and why WSA just doesn’t work in a way people like with that feature.
And I do not want two different application syntaxes.
But again I’m all in on PNC because we evaluated it as the best choice for SD and (less important) onboard more mainstream users. That call was made not by me, but by the BDFN. I just implemented the PNC syntax.
I personally appreciate WSA in the abstract and would be totally happy using Roc with it. The semantics of the language are what are most important to me. But I also really enjoy the consistency of PNC and never running into a precedence issue with application.
Zig and Rust are both two pretty terrible languages aesthetically, but are both powerful and fun to program in in their own ways. If Zig had WSA it might be 30% more aesthetically pleasing , but if it hurts its expressive power in some way by 1% I would be totally against it
I don't have any compelling argument for WSA aside from DSLs. Well I'll miss it, I'm sure I'll get over it shortly. I thought it was pretty clear it was getting removed, but I guess it wasn't clear to everyone. I really saw this thread more as a way to feel a little sad about its removal than a discussion about keeping it around.
At this point, I think WSA is to die and that is fine. It will have a soft place in my heart, but I don't think it is worth trying to keep around in roc.
CC @Sky Rose @Jonathan
(from the related #ideas > static dispatch - spaces vs parens )
My unsorted opinions:
5) is my hope for us to push on, it seems to be the final piece needed for decision making
I just got off a plane, and it looks like I missed a bunch of discussion! :sweat_smile:
I know I rarely do the explicit "this is the way forward" thing, but it seems like this is a case where we need a really clear decision, so:
let's plan for Roc 0.1.0 to support parens-and-commas calling, and not whitespace calling.
we've discussed this a bunch in the past, and although I and others have a lot of personal affection for whitespace calling, we're doing a rewrite and it just doesn't make sense to implement both from scratch.
of the two styles, it also doesn't make sense to me to choose whitespace calling as the one for 0.1.0
remember, 0.1.0 is not 1.0.0. I'm not saying we won't all look around after 0.1.0 and say "yeah this was a mistake." That can happen! We've had cases of trying out syntax in the past and then deciding not to stick with it after all.
I don't think that's going to happen with PNC, but I've made plenty of predictions that turned out to be wrong.
what I do know is that we have a very big, very exciting project that's just gotten underway, and I think it would be a mistake to redirect our energy into revisiting this design question that we've already spent a huge amount of time on.
I think what we should do is to commit to PNC for 0.1.0 and focus on lending an amazing compiler that people can try out!
there will always be time to revisit syntax options after we've already gotten a feel for how static dispatch and the other changes feel in the new compiler. :big_smile:
I'm sad for a variety of reasons, but I respect your clarity and decisions. I'm willing to redirect my energy into helping us phase out these components smoothly!
thank you Jan, I know this is really important to you, and I really really appreciate it! :hearts:
I have some ideas for next steps, but I'll give this thread time to breathe, if others want to weigh in.
Eelco Hoekema said:
In terms of feeling, it feels attracting new people from javascript world seems to be the main driver
as an aside, I've seen this a few times, and I want to note that this is not the main driver to me.
I didn't write that whole realworld code base thinking "I wonder how this would feel to a JavaScript programmer?" - I wrote it to see how I would personally feel using it, and I came away from that experiment feeling happy with how the syntax felt to use.
Is reclaiming strangeness budget one of the items on the list of benefits? Of course! Would I call it the "main driver" of the change? No.
As with so many other design questions, beginner-friendliness is one consideration among many.
Richard Feldman said:
let's plan for Roc 0.1.0 to support parens-and-commas calling, and not whitespace calling.
As I mentioned here: https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/reflecting.20on.20static.20dispatch/near/498415802
I think this would have been alleviated if, when the decision was made. There was more clarity as to why, and what alternatives had been considered and why they were rejected.
Yes, ofcourse folks can find that out by trawling through a few thousand messages spread across a number of zulip threads. But given this is a change a lot of people clearly feel pretty attached to, I think more clarity would be good.
Again, as I said in the last comment. It would also be a good thing from an externally facing perspective as a quick response when people don't understand why the change is happening.
totally fair! Just to clarify, this was the moment where I made the decision:
Richard Feldman said:
let's plan for Roc 0.1.0 to support parens-and-commas calling, and not whitespace calling.
it wasn't like I had a concrete plan and didn't say anything about it :big_smile:
I can put something together that explains the full motivation, but it might take me a bit. I need to be careful not to post something quick and unpolished, because the last time I did that it ended up on the front page of Hacker News and lobste.rs, and I'm still working through the backlog of responses to that. :sweat_smile:
hahaha, very true.
I guess mostly I just wanted to bring it up so it's in mind in future.
Personally I think it would be nice if meaningful changes to the language had a bit of a "final summary" drawn up before implantation. I think it would really help people who are only checking in occasionally to track how roc is evolving and also to record why things were decided for us to reflect on.
If module params and abilities get removed that would be a great case.
The lambda syntax change is another good example. I wasn't tracking that and was somewhat surprised by it.
I'm not suggesting a full on RFC or anything
More just:
This is why it felt needed:
These were the for and against/ alternatives.
This is why we decided on the outcome.
As a person who’s been following Roc from the sidelines for a while, this seems like a good place to give my take. I feel similarly about this as I felt about the removal of backpassing. I liked backpassing and was a little sad to see it go. I liked whitespace application and am a little sad to see it go. But I also think this community (and Richard in particular) is good at making these kinds of decisions, and I trust you all to make a better decision than I would.
When it comes to syntax in particular, I’ve realized that although I have a lot of enthusastic opinions and preferences, at the end of the day, I like trying new languages. It’s unlikely that the syntax of a language would be what stops me from trying it. “Mainstream users” usually seem to have different preferences from me, and crucially, those preferences are more likely to affect whether they try the language. My understanding is that mainstream adoption is a goal for Roc.
I agree with @Eli Dowling that when it comes to these sorts of changes, having an explanation of why they were made really increases my trust. The explanation of why the compiler is being rewritten is actually a good example of that. Even though it’s “quick and unpolished,” it shows me that the decision was made thoughtfully. Seeing and hearing those kinds of explanations is what gives me the confidence that the decisions you all come to are probably the right ones for Roc.
Yeah, I think one thing we have avoided is RFCs and the like. I think for many accepted ideas, they are small enough for this not to be important. For larger ideas, it is probably worth putting up an RFC or some other doc to explain the decision. Just something quick and as a reference
JanCVanB said:
I have some ideas for next steps, but I'll give this thread time to breathe, if others want to weigh in.
Here are some ideas for next steps:
|> operator.For purely engineering reasons, we need to keep around some vestiges of WSA in the parser in order to properly parse WSA types, e.g. Result Str MyErrTy. A subset of those types also need to be represented as expressions as they're initially parsed, e.g. Foo a b in Foo a b : List (Result a b), since before we see the :, that could well be the start of an expression.
And at that point, we might as well keep around the ability to parse and format that generally.
FWIW, I'm in favor of keeping both WSA and |> around for a while, including implementing them in the new compiler. I think the community is split enough that it'll be beneficial to have both available for a while to play around with.
Wsa gets immediately resolved in the parser. When does |> get resolved?
|> is desugared in canonicalization
(I updated this topic's name with addendum on WSA removal.)
WSA is staying in type annotations
At least from what Richard said, that is the go forward plan
Type language is WSA, Value language is PNC
And I personally don't favor implementing WSA generally since the type language is much simpler to deal with than the full expression grammar
And that is complexity we don't need to carry for little to no reason
As this is supposed to be the v0.1.0 Compiler
What I'm saying is we _have_ to carry over at least a bit of WSA-based expression handling in order to implement the syntax for type aliases.
We can of course choose to throw that away immediately
I think we are agreeing - but I think we only need to retain it in the type annotation grammar part of the parser
I've completed the action items above. Any further discussion/actions here, or shall we resolve this topic?
JanCVanB said:
- I'd like to start a topic for WSA deprecation planning.
See #contributing > deprecating WSA (whitespace application for function calls)
JanCVanB said:
- I'd like to start a topic for what to do about the
|>operator.
See #ideas > Do we still need `|>`?
Let's resolve!
Relevant: we revived #ideas > Using parens for types
JanCVanB has marked this topic as resolved.
Last updated: Jun 16 2026 at 16:19 UTC