Feldman is such a charming guy! I highly recommend checking out his podcast Software Unscripted and watching his many talks on YouTube.
The recent SU episode with Brian Carroll talking about WASM in Roc was a great listen.
Roc also has an active community on zulip, so consider stopping by :)
[1] https://twitter.com/sw_unscripted
[2] https://www.youtube.com/results?search_query=richard+feldman
[1] https://taylor.town/elm-2023
Evan also announced some stuff about Elm and Postgres at Strange Loop earlier this year, so I expect another wave of movement soon
1. The typesystem will be sound, ML-like, and so simple that any code that doesn't interact with external data will not need _any_ type annotations.
2. An aim to make it the fastest managed compiled lang around (faster than golang).
3. Functional.
4. A focus on fast compile times from the beginning (like golang).
5. Serde from rust is essentially a language builtin.
6. Zero side effects, only managed effects (which I think will do wonders for testability and mocking in a compiled language).
What I'm unclear about is:
1. Whether they'll support macros,
2. Whether their decision to build a whole new IDE will take away from the work that will go into an LSP (it will take a lot to pry away neovim from my hands).
It'd be dope if anyone more familiar can comment on the above!
Also, as feedback to Richard Feldman, your podcast is (imo) great marketing for your lang! It's what's made me excited about your PL.
EDIT: Forgot another feature I'm allured by: ability to run programs with type errors (as best as one can).
> 1. Whether they'll support macros,
The plan is not to support macros. A major reason is that macros tend to conflict with editor tooling, and I definitely have big plans for Roc's editor tooling!
> 2. Whether their decision to build a whole new IDE will take away from the work that will go into an LSP (it will take a lot to pry away neovim from my hands).
The IDE project has been deprioritized a lot (e.g. I don't expect any work to be done on it in 2024) because we realized there's a way to build the editor plugin ecosystem we want to build in a way that works across multiple editors.
There already is a preliminary language server, and there are instructions in the VS Code extension for how to get it set up [0]. I assume something similar should work for neovim!
EDIT: I just noticed that while I was typing this, the author of the Roc language server responded too...hi, Ayaz! Thanks for all your excellent contributions to Roc!
https://github.com/ivan-demchenko/roc-vscode-unofficial#conf...
I disagree! I've been working on a macro-heavy Rust project with both proc and declarative macros and the tooling makes them better. I'll add that there is immense value in turning repetitive code into "spreadsheet" style tables of data as well as being able to combine const expressions to get user controllable compile-time errors.
Gotcha. In every lang I've used a lot, I've found meta-programming (compile-time or dynamic) to be valuable (and often indespensible). I can imagine that a lang like Elm that is domain-specific can do fine without the expressive power of macros, but I struggle to imagine that for a general-purpose lang like Roc.
I'm sure you've ruminated on this, so I'm excited to see how it all pans out.
Maybe a Software Unscripted episode with someone who's written a lot of macros is in order? :) David Tolnay (serde maintainer) would be great!
How do you plan on supporting meta-programming, then? Code-generation as a first class citizen a la .NET?
I've tried using languages with this promise, such as Haskell, and also spent a lot of time with TypeScript, which makes a different set of tradeoffs, and I feel like I've spent enough time on both to know this is the wrong tradeoff to make. It sounds flashy to be able to say that no type annotations are necessary, but in practice what it ends up meaning is that you end up tracking down errors in the wrong parts of your code because the compiler can't figure out how to reconcile problems.
e.g., you have function A incorrectly call function B. How does the compiler know if A has the wrong arguments, or B has the wrong signature? It can't! I know that's a toy example, but it really does lead to a lot of real-world frustration. Sometimes the type errors are very far away from where the actual issues are, and it can lead to a lot of frustration and wasted time.
The TS approach of "please at least annotate all your function signatures" isn't nearly as flashy, but it strikes a much better utilitarian balance.
One of the practical benefits of having full inference is that these signatures can be inferred and then correctly generated by an editor. Like I can write the implementation of my function, and then tell my editor to generate a type annotation, and it can always generate a correct annotation.
That saves me time whenever I'm writing the implementation first (I often write the annotation first, but not always), even if I end up wanting to massage the generated annotation stylistically. And unlike having Copilot generate an annotation, the type inference system knows the actual correct type and doesn't hallucinate.
To me, the main benefits of type inference at the top level are that they offer beginners a more gradual introduction to the type system, and that they offer experts a way to save time through tooling.
I usually think of writing explicit type annotations as 'pinning' the type in situations where things are inferred/generic by default.
The whole signature or just the parameters? I thought typescript is pretty chill about inferring the return type on its own.
I find this an interesting perspective: That Golang is a compiled managed language. This is certainly correct. I don't see this being expressed to often, however.
There doesn't seem to be any particularly compelling reason to use it, and note that, unless they can use libraries from an existing language, there needs to be a really MAJOR reason to use a new language to compensate the lack of libraries.
I like Roc's approach of detecting errors statically but still trying to let you run the code. If a snippet is work in progress and has an unused variable, Go or Zig will refuse to compile it. Yes, an unused variable indicates a problem, which is why it's not going to pass any sensible CI setup and make its way into production, but that doesn't mean I should be disallowed from checking whether what I've got so far works. Roc allows¹ running a program with type errors as long as you don't execute a code path affected by them, which I imagine is very useful for refactoring.
The platform approach is also interesting, but I don't know how it will play into code reuse. I guess the different io/platform interfaces might not be quite as big of a problem in a pure functional language? I'm not experienced enough to tell.
¹: I haven't checked how successful it is, given it's immaturity I expect there to be issues
What I find surprising is how few programmers I talk to are aware of this, let alone use it. I find it a significant productivity boost.
Extrapolating away from debuggers: Everything should be warning, nothing should be an error. Then adopt a policy that you don't check in warnings. I find it utterly insane that 'unused variable' is treated as an _error_ (in the sense that it prevents compilation). It.. just isn't.
I hear _lots_ of noise in the line of 'well but my dev team will just ignore that rule', but that's a "doctor it hurts when I press here" issue. You don't solve that by just being more beliggerent, you fix that by having a chat with the team.
I wonder what 'friendly' means in the context of 'a programming language', but if its: "Assuming you are not a complete idiot", that's a plus, I guess.
>What I find surprising is how few programmers I talk to are aware of this, let alone use it. I find it a significant productivity boost.
Forward to the past, as often is the case.
See:
https://news.ycombinator.com/item?id=37841588
and its parent and child comment.
But, that website has one of the smoothest on boarding experience I've ever seen for a new language. From the inline REPL (with built in tutorial), to the code definition section, its insanely practical. Every new (& old) language should have a website and onboarding experience like this one.
For web UI, I always thought QisKit set the bar pretty high. It's intuitive and informative:
But other than that great to have a quite good idea of the language in just a few seconds.
# Function Definition:
addAndStringify = \num1, num2 ->
Num.toStr (num1 + num2)
# String Interpolation:
"\(greeting) there, \(audience)!"
# desugars to
Str.concat greeting (Str.concat " there, " (Str.concat audience "!"))
https://www.roc-lang.org/tutorialThe unique selling point of Roc is clever optimization to convert purely functional source code to deep-imperative fast machine code, while keeping all the correctness of functional algorithms.
See this video of Richard Feldman for details — «Outperforming Imperative with Pure Functional Languages»: https://www.youtube.com/watch?v=vzfy4EKwG_Y
Among those clever optimizations:
- static reference counting (no GC, like in Rust, but with no borrowing and borrow problems);
- stack allocation of the data with no external links;
- hidden («opportunistic») mutability even in the cases, where Haskell or Lisp will copy the value.
edit:markup
All functional language compilers, interpreters, and/or runtimes ultimately have to do this by definition. The efficiency of transpilation varies widely.
The only «sine qua non» optimization through opportunistic mutablity is AFAIK tail call optimization. But it is probably too well-known to call it «clever optimization» in 2023.
But, for example, applying a function to a list will produce the code allocating new list in, say, OCaml and Haskell, at least by default. And Roc will produce the code for mutating the list in-place _from the source code with the same semantic_ (see example for the Quicksort algorithm in the video above).
Compile-time lifetime analysis (that probably is not needed at all in functional languages with GC) and widely used unboxed values are way not common in functional language implementations. For example, in OCaml those features are still experimental (and probably never will be used by default, as in Roc).
- side effects are strictly relegated to async effects, eg all I/O calls return a future
- declarative static loading as imports
Does this mean that it's somewhat equivalent to Rust with everything behind a `Rc` or `Arc`?
But Roc counts references in _compile_ time. So it's like _usual_ (not wrapped in Rc<>) values in Rust. But in Rust the value is deleted from the heap when the stack frame with the _only_ link to it («the owner») is deleted. And in Roc the value is deleted from the heap, when the _last_ link to it leaves the stack.
So we have the machine code _almost_ as efficient as a Rust-produced machine code, but the source code with a much simpler semantics.
Everything is hidden behind some kind of "let's get started!" wizard. https://dotnet.microsoft.com/en-us/learn/languages/fsharp-he...
https://learn.microsoft.com/dotnet/fsharp/get-started/get-st...
What I like about this page is that it shows a basic project structure.
https://fsharp.org/ is the best place to actually start, although i'm guessing you did and went to the hello world which leads back to ms's nightmares.
https://fsharpforfunandprofit.com/ is the standard recommendation from there but there's finally some good youtube and other content out there.
They have a browser repl as well https://try.fsharp.org/
I'm sorry, but what do you mean by that? Roc is "as" pure as Haskell (or Koka), if that's your point.
Elm really broke my heart, I believed it will go places it never went. Roc honestly, I am OK to play around with it and build whatever makes me happy.
Edit: related to state management, the "platform" concept looks interesting too https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#...
1. https://www.erlang.org/doc/man/gen_server.html 2. https://hexdocs.pm/elixir/1.12/GenServer.html
I know in my linked [0] that Feldman has since apologized, if only because the comment was being linked to so often [1], but again, why not use any other language where the creators are not so hostile, some even going so far as to say that they "wouldn't trust anything that Richard Feldman was involved in. He was instrumental in making the Elm community a hostile and unwelcoming place."?
[0] https://github.com/gdotdesign/elm-github-install/issues/62#i... (check the edit history)
[1] https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...
5 years ago I was upset and posted a comment that was unfairly harsh to another commenter. I apologized at the time, and I meant it. I definitely should not have made the harsh comment that I did. It was wrong. There's no excuse for my having written it.
There are a lot of people working on Roc other than me. I'm not even the top committer anymore. [0] I hope you can find it in your heart to give their work some consideration, if not mine.
As a manager, I empathize with the frustration you were feeling. Steering a team or a community towards a vision is very hard. Just when you think you’re getting somewhere, someone does the exact opposite and mixes people up. It’s easy to lose patience. I’ve made similar mistakes on popular projects and was fortunate enough that no one publicized them. I was allowed to learn from my mistakes without being punished for it.
I don’t have any advice on this. It’ll probably turn out fine.
> EDIT 5 years later: You can see in the edit history of this comment what I originally wrote here; I was upset and said unkind things that I regret, and which nobody deserved to hear. I apologized at the time and I still feel I should apologize again, unequivocally. I was in the wrong here.
Seriously, tho, that's the comment that "made the Elm community a hostile and unwelcoming place" and is still being dredged up after 5 years? That comment can barely even be considered harsh, and is nowhere near hostile.
Is it really worth tearing down someone's life, monitoring the internet for any time their name appears, just so you can spread the continue to spread the hate toward him after so long? This is where you make your stand?
> Threatening a person with exclusion from a community for attempting to patch the source code is quite antithetical to the spirit of Open Source, as far as I can see.
Elm also seemed very promising in the beginning, and honestly I don't even think that comment is so abhorrent on its own. I think Elm died the death of a thousand cuts. If it had only been one errant comment somewhere, it would've been mostly forgotten about by now. Instead, it's Elm that's mostly forgotten about.
So I say best of luck, but also... No thanks for now.
edit: Just so it's completely clear, I am actually implying that "maintainers being dicks" was actually not the problem with Elm. I think people just got especially infuriated by it because they were sick of trying to deal with Elm's breaking changes, of which this represented one. I remember going through and learning Elm and like literally months later everything was completely different and I no longer knew how to make a basic hello world application (around 0.16 or 0.17 maybe? Can't recall. I just remember that effects had changed a fair bit.) I know that to some degree this is the nature of a 0.x product, but at some point it's like "OK... then who is supposed to even use this?" Among other issues of course.
I don't understand why people have to make technical stuff personal.
- simplicity
- strict evaluation model
- devx
- faster runtime
- built in effect system
I love haskell and write it every day, but I have the feeling that the language is probably too complex to really cross over to the mainstream. I remain convinced that the advantages of a pure functional approach are so compelling that we will one day see roc or something like it be the default choice for most programming tasks, and am really excited to see so much progress being made on the language.For example: https://github.com/fsharp/fslang-suggestions/issues/243#issu...
ETA: Also if I'm reading this right Roc appears to natively support some kind of row polymorphism. That's a nice-to-have.
Many other things are features or bugs depending of your preferences. For me, for example, eager evaluation is a big improvement, but YMMV.
Does it have any support for laziness? E.g. could one define the list of all fibonacci numbers similarly to Haskell's
fib = let f a b = a : f b (a+b) in f 0 1If anything, Haskell gets a lot of eyerolls for its slow moving pace and for trying to build a language from mathematical first principles.
It's not perfect (eg.: Monad was not designed to be a special case of Applicative in the beginning, I believe) but it's better at "avoiding baggage" than many other languages I know of.
A video about the design decisions of the (hash) map: https://www.youtube.com/watch?v=Z3UGuaJWbaA
Need less Altman, and more altlang posts.
As a big elm fan who does backend work, I’ve been looking Roc for a while with a lot of excitement.
https://github.com/roc-lang/roc/blob/main/FAQ.md
I don't fully agree with all of the reasoning, but it's a reasonable position to stake.
I do suspect there's a way to solve the issues they raise with currying, but haven't thought about it enough to be sure.
The only other complaint I have that isn't addressed in the FAQ is the choice to use '\' to start a lambda. I've never liked that syntax anytime I've seen it. '->' as a infix operator is sufficient to disambiguate, so given all of the other good ergonomic choices they've made, that just kinda sticks in my craw.
I like the 'be fast' and 'be haskell like' approach.
I see you have an Earthfile in the repo. Let me know if you have any Earthly feedback or if I can help with the build in any way, @rtfeldman.
( We've been working on making Earthly faster for Rust builds by using cache mounts. )
Counting all the java operators and keywords, you get 84. This doesn't include assignment operators like "+=" or "-=" (11 such operators).
ChatGPT tells me that python has 36 keywords and 28 operators (not including the 13 assignment operators). This seems low and may be missing some syntactical sugar operators, but even then 64 is a far lower number than F#'s 150. Much debate could be had about which of these operators are fair to count or not, but it seems preliminarily that the data supports the position that functional programming languages (or at least F#) tend to go heavy on special keywords and operators
I do agree that default convention may rely heavily on a few syntaxes that aren't as common in procedural or OO languages.
So instead of:
["a", "b", "c"] |> List.append "d" |> List.append "e" |> List.append "f"
You could have:
["a", "b", "c"] |> append "d" |> append "e" |> append "f"
Since Roc knows that the type returned from each function is a List.
An important note is that any module could expose an append function that has the same interfaces as `List.append`, so that could easily lead to confusion.
» 1/0
1000000000000000000 : Frac *Thanks for pointing it out!
Just installing and trying to reach a valid hello world going just by the errors and it's actively rude within three error messages.
Also it's missing the final newline
Can you share those error messages? I am sure that is not the intent.
Is it a Haskell/Elm thing I’m unfamiliar with?
Is there an (C) FFI planned?
1. Why another language and not a better runtime for an existing language with an install base that already exists?