roc/www/public/index.html
2023-09-18 15:26:10 -05:00

317 lines
20 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The Roc Programming Language</title>
<!-- <meta name="description" content="A language for making delightful software."> -->
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="/homepage.css">
<!-- <link rel="icon" href="/favicon.svg"> -->
</head>
<body>
<h1>The Roc Programming Language</h1>
<p>Roc's goal is to be a fast, friendly, functional language. It's very much a work in progress;
below, you can see the current progress towards this goal. This website is intentionally unstyled
as a way to emphasize the language's current level of incompleteness. The website will become
more polished after the language itself becomes more polished!</p>
<p>Roc compiles to machine code or to <a href="https://webassembly.org">WebAssembly</a>. Eventually
you'll be able to use Roc to build high-quality servers, command-line applications, graphical
native desktop user interfaces, among other classes of applications. Today, only command-line interfaces have
support beyond the
proof-of-concept stage; the other use cases will mature over time.</p>
<p>Like <a href="https://www.lua.org/">Lua</a>, Roc's automatic memory management doesn't require
a virtual machine, and it's possible to call Roc functions directly from any language that can
call <a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a> functions. This makes
Roc additionally useful as a language for implementing plugins, and gives you a way to
incrementally transition a legacy code base from another language to Roc.</p>
<p>So far, the Roc compiler has progressed past the "proof of concept" stage, but there are
currently lots of known bugs and unimplemented features, and the documentation for both the
language and the standard library is incomplete. The overall ecosystem is in its infancy, and
the compiler is neither battle-tested nor fuzz-tested yet, so we don't recommend relying on Roc
for critical projects until its development is further along.</p>
<p>With all that context in mind, if you'd like to try it out or to get involved with contributing,
the <a href="https://github.com/roc-lang/roc">source code repository</a> has
<a href="https://github.com/roc-lang/roc/releases">nightly builds</a> you can download,
and a <a href="https://roc-lang.org/tutorial">tutorial</a>.
</p>
<p>If you'd like to learn more about Roc, you can continue reading here, or check out one of these videos:</p>
<ul>
<li><a href="https://media.handmade-seattle.com/roc-lang">Roc at Handmade Seattle</a> - November 12,
2021 (very low-level explanation of how Roc's compiler makes programs run fast)</li>
<li><a href="https://youtu.be/vzfy4EKwG_Y">Outperforming Imperative with Pure Functional Languages</a> - October 1,
2021 (about Roc's runtime performance and optimizer)</li>
<li><a href="https://youtu.be/6qzWm_eoUXM">A taste of Roc</a> - September 23, 2021 (syntax, application examples)
</li>
<li><a href="https://youtu.be/cpQwtwVKAfU?t=75">Roc at the Philly ETE conference</a> - May 6, 2021 (platforms and
applications)</li>
<li><a href="https://youtu.be/FMyyYdFSOHA">Roc on Zig Showtime</a> - April 24, 2021 (making a platform)</li>
<li><a href="https://youtu.be/ZnYa99QoznE?t=4790">Roc at the Berlin FP Meetup</a> - September 1, 2020 (overall
vision for the language)</li>
</ul>
<h2>A <em>Fast</em> Language</h2>
<h3>Goal</h3>
<p>We want Roc to run faster than any non-systems language (like C, C++, Rust, or Zig)
that sees mainstream use in industry. The goal is that nobody should find themselves
thinking "I should rewrite my Roc program in [some mainstream garbage-collected language]
because that will make it run significantly faster."
</p>
<p>When benchmarking Roc code against similarly-optimized programs written in
<a href="https://go.dev">Go</a>,
<a href="https://www.swift.org/">Swift</a>, <a href="https://www.java.com">Java</a>,
<a href="https://learn.microsoft.com/en-us/dotnet/csharp">C#</a>, or
<a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-262">JavaScript</a>,
we generally aim for Roc to outperform all of those languages. Outperforming systems
languages like Rust, Zig, C, D, and C++ is a non-goal, as is outperforming research languages
that see little or no use in industry. (Realistically, there will always be certain specific
benchmarks where some popular non-systems-level languages outperform Roc, but the goal is to
usually be at the front of that pack.)
</p>
<h4>Current progress</h4>
<p>Progress towards this performance goal is already quite far along.</p>
<p>Roc already uses unboxed data structures and unboxed closures, monomorphizes polymorphic code,
and uses LLVM as a compiler backend. These optimizations, especially unboxed closures and
monomorphization, can be found in several systems-level languages (like C++ and Rust), but not
in any mainstream garbage-collected languages. Roc closures in particular have the distinction
of being as ergonomic as the closures found in garbage-collected languages
(where they are typically boxed), but have the performance of systems language closures
(which are typically unboxed, but have more complicated types).
<p>Because of these optimizations, in many cases Roc code already
compiles to the same machine instructions that the equivalent code written in one of these
systems languages would. Something we do regularly is to compare the LLVM instructions generated
by Roc's compiler and by these systems languages' compilers, to check whether we're generating
equivalent instructions.</p>
<p>That said, there are also cases where Roc has strictly more runtime overhead than languages
like C, C++, Zig, and Rust do. The most costly is automatic memory management, which Roc
implements using automatic reference counting. Static reference count optimizations like
elision and reuse (thanks to Morphic and
<a
href="https://www.microsoft.com/en-us/research/publication/perceus-garbage-free-reference-counting-with-reuse/">Perceus</a>)
improve things, but significant runtime overhead remains.
</p>
<p>Eliminating this overhead altogether would require sacrificing other design goals
(e.g. it would require introducing memory-unsafe operations, or compile-time lifetime errors),
and there isn't much overhead left to remove outside of automatic memory management. For example,
smaller sources of overhead include mandatory array bounds checks, disallowing cyclic references
(which rules out a certain niche of efficient graph data structures), and automatic opportunistic
in-place mutation instead of direct mutation. Even if all of these sources of overhead were
completely eliminated, it seems unlikely that typical Roc programs would see a particularly big
performance boost.</p>
<p>Overall, we expect Roc's performance in the use cases mentioned above (servers, CLIs, GUIs, etc.)
to be about the same as the equivalent C++ code would be, if all that C++ code
(including its dependencies) were written in a restricted subset of C++ which always did array
bounds checks and used shared pointers for all heap allocations.
The Roc code might even run somewhat faster, because its reference counts are non-atomic by default,
and can be statically optimized away in some cases—but then again, Roc also has a bit of overhead
to perform opportunistic in-place mutation instead of direct mutation.</p>
<p>To be clear, we don't expect this because we've benchmarked a bunch of programs written in Roc
and in this restricted C++ subset, and found that the numbers were about the same (although if
you know C++ well enough and want to do such experiments, we'd happy to help and would be
interested to see the results!) but rather because Roc's compiler and
<a href="https://clang.llvm.org/">clang</a> should both be generating essentially the same
LLVM instructions when the C++ is restricted to that subset.
</p>
<p>Of course, <em>unrestricted</em> C++ code can certainly run faster than unrestricted Roc code.
The same is true when comparing other such minimal-overhead systems languages to Roc, including
Rust, Zig, C, and D. The point of the comparison is to give you a general idea of what Roc
compiles to, since it is quite different from the VMs and JITted bytecode interpreters found in
today's most popular garbage-collected languages!</p>
<p>The talk <a href="https://youtu.be/vzfy4EKwG_Y">Outperforming Imperative with Pure Functional Languages</a>
discusses some early results from Roc's optimizations, and
<a href="https://media.handmade-seattle.com/roc-lang">Roc at Handmade Seattle</a> gets into
low-level details of how Roc's compiler generates programs similarly to how clang does.
</p>
<h2>A <em>Friendly</em> Language</h2>
<h3>Goals</h3>
<p>Roc aims to be a user-friendly language with a friendly community of users.</p>
<p>A programming language can be much more than a tool for writing software, it can also be a way
for people to come together through shared experiences, to teach and to learn from one another,
and to make new friends.</p>
<p>No community is perfect, but a community where people show kindness to each another by default
can be a true joy to participate in. That all starts with friendliness, especially towards
beginners, and including towards people who prefer other programming languages.
After all, languages are tools people use to create software, and there's no need for us
to create artificial divisions between ourselves based on the tools we use!</p>
<p>On a technical level, Roc aims to ship a toolset where user-friendliness is a major priority.
This includes everything from helpful error messages (aiming to meet the bar set by
<a href="https://elm-lang.org">Elm</a>) to quality-of-life improvements inspired by dynamic
languages (always being able to run your program even if there are compile errors, automatic
serialization and deserialization using schemas determined by type inference, reliable hot
code loading that's always enabled and requires no configuration to set up, etc.) to accessibility
features in the included editor.
</p>
<p>Roc also aims to ship a single binary that includes not only a compiler, but also a
<a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a>,
package manager, test runner, debugger, static analyzer, code formatter, and a full-featured
editor, all of which are designed to work seamlessly together.
</p>
<h3>Current Progress</h3>
<p>Work has not yet started on the package manager, static analyzer, debugger, or hot code loading
system, and although work has started on the editor, it's not yet far enough along to be usable
for practical purposes. The standard library is perhaps 80 percent complete in terms of
functionality, but a lot of operations do not yet have documentation.</p>
<p>The REPL fully supports entering arbitrary expressions, and will evaluate them and print the
results. It remembers recent expressions entered in the current session (if you press the up arrow),
but it can't yet execute effects. You can try out the REPL in a browser at
<a href="https://roc-lang.org/repl">roc-lang.org/repl</a> - it uses a WebAssembly build of Roc's
compiler, and compiles the code you write to WebAssembly on the fly, which it then executes in
the browser to display the answer.
</p>
<p>The compiler works well enough on a basic level to build things with it, but some error messages
could use significant improvement, and it has a lot of known bugs and missing features. You can
currently use it on macOS (either Intel or Apple Silicon), Linux (only x86-64 machines at the moment),
and Windows (only recently supported; debugging and testing features don't work on it yet, and
there are likely bugs we haven't encountered yet due to lack of battle testing). Support for other
operating systems has not yet been discussed.</p>
<p>The compiler doesn't yet support incremental compilation or hot code loading, and build times vary
based on what machine you're building for.</p>
<p>For example, suppose you run `roc check`, which reports errors it finds (type mismatches, naming
errors, and so on) but doesn't actually build an executable, on a code base that's under a thousand
lines of code. On an M1 MacBook Pro, this typically takes about 10 milliseconds.</p>
<p>In contrast, if you do `roc build` (or `roc run`) on that same machine, it will take closer to 500
milliseconds instead. Almost all that extra time is spent waiting for LLVM to generate (unoptimized)
machine code, and then for the system linker to assemble an executable from it.</p>
<p> Fortunately, we can eliminate almost all of those extra 490 millisconds of build time by using
Roc's (work in progress) development backend instead of LLVM. This compiles directly from Roc's
internal representation to machine code, like most compilers did before LLVM. (LLVM can optimize
code into running very fast, but even when it performs no optimization at all, LLVM itself takes a lot
longer to run than generating unoptimized machine code directly.)</p>
<p>The LLVM backend is currently the most feature-complete, followed closely by the WebAssembly backend
(which the online REPL uses exclusively, instead of LLVM). The x86 and ARM backends still have a
ways to go, but improving them can be done by anyone with the patience to read some documentation;
we have issues split up for them, and are happy to help new contributors get up and running!</p>
<p>Builds on Linux and Windows also use Roc's surgical linker instead of the system linker, which
runs so fast that linking essentially disappears from the performance profile altogether. The
surgical linker currently only works on Linux and Windows, and it currently supports building
executables but not (yet) dynamic libraries, which is relevant if you're using Roc to create
plugins or want to call Roc functions from existing code bases in other languages. Work has started
on macOS surgical linking, but it isn't usable yet. If you're interested in working on that,
please get in touch on <a href="https://roc.zulipchat.com/">Roc Zulip</a>!</p>
<p>The test runner currently has first-class support for running standard non-effectful tests.
It does not yet have first-class support for effectful tests, property-based tests, snapshot tests,
or "simulation tests" (where effects are replaced by hardcoded values during the test - similar to
"mocking" in other languages), although these are all planned for the future.</p>
<p>The code formatter is nearly feature-complete, although occasionally it will report an error -
usually due to a comment being placed somewhere it doesn't yet know how to handle. Unlike most of
the rest of the compiler, the formatter is one place where the number of known bugs is so small
that fuzzing would be very helpful as a way to surface bugs we don't yet know about. (If you're
interested in working on setting up fuzzing for the formatter, please let us know in
the <a href="https://roc.zulipchat.com/#narrow/stream/316715-contributing"><code>#contributing</code> channel</a>
on Zulip! Separately, we're also very interested in fuzzing the compiler, even though we already
have a sizable list of known bugs there.)</p>
<p>On the community side, so far the community is a friendly bunch, and we want to keep it that way
as it grows! We hope to do that by encouraging a culture of kindness and helping one another out,
especially by being welcoming towards beginners.</p>
<p>If you'd like to join in, the best place to do that is in our Zulip chat. Feel free to drop by the
<a href="https://roc.zulipchat.com/#narrow/stream/231634-beginners/topic/introductions"><code>introductions</code>
topic</a>
and introduce yourself!
</p>
<h2>A <em>Functional</em> Language</h2>
<h3>Goals</h3>
<p>Roc aims to be a purely functional programming language. This means all Roc functions are
<a href="https://en.wikipedia.org/wiki/Pure_function">pure functions</a>, and all effects are
<a href="https://medium.com/@kaw2k/managed-effects-and-elm-36b7fcd246a9">managed effects</a>
instead of side effects.
</p>
<p>A major motivating reason for this is to facilitate tooling. For example, in the future the goal
is that Roc's test runner won't bother re-running tests whose outcomes could not possibly have
changed (because they were pure functions whose inputs did not change). Tests that contain only
pure functions can be trivially run in parallel, and they will never <a
href="https://www.smashingmagazine.com/2021/04/flaky-tests-living-nightmare/">flake</a>.
Additionally, having the guarantee that the application contains only pure functions can also make
certain debugging tools more reliable, such as time travel and retroactive tracing.
</p>
<p>Roc also takes a novel approach to managed effects. In most programming languages, the standard
library contains both data structures and I/O primitives (e.g. for using the file system or the
network), and then you might decide to use a <a
href="https://en.wikipedia.org/wiki/Application_framework">framework</a>
on top of that standard library.</p>
<p>In Roc, every application is built on a <em>platform</em>. A platform is like a framework except
that it also provides I/O primitives and behind-the-scenes memory management. (Roc's standard
library only contains data structures.) In practice, this means that using Roc feels similar to
using any other programming language where you've chosen to use a framework, except that the
documentation for your I/O primitives comes from the framework instead of the standard library.</p>
<p>This might sound like a minor distinction, but it turns out there are a lot of surprising benefits
to organizing things this way, which would be impossible to achieve without having platforms as a
first-class language concept. <a href="https://youtu.be/cpQwtwVKAfU">The Edges of Cutting-Edge Languages</a>
goes into more detail about some of these benefits.
</p>
<h3>Current Progress</h3>
<p>Today, platforms as a concept already exist, and there are a few different ones implemented.
You can find them in the <a href="https://github.com/roc-lang/roc/tree/main/examples"><code>examples/</code></a>
directory in the source code repository. The platform for building command-line interfaces is the
most fully featured; the others are mostly in the proof-of-concept stage.
</p>
<p>Roc's built-in tooling is not yet far enough along to take advantage of pure functions. For
example, there is a built-in test runner, but it does not yet run tests in parallel or skip
running tests whose outcomes could not possibly have changed.
</p>
<p>Roc is already a purely functional programming language, though, so all of these benefits
are ready to be unlocked as the tooling implementations progress!
</p>
<h2>The Roc Programming Language Foundation</h2>
<p>We've created a nonprofit to support Roc, you can learn more about it <a
href="https://foundation.roc-lang.org/">here</a>.</p>
<footer>This site is powered by <a href="https://www.netlify.com">Netlify</a>.</footer>
</body>
</html>