<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 🔻 🇵🇸</title>
    <description>The latest articles on DEV Community by 🔻 🇵🇸 (@orphanpid).</description>
    <link>https://dev.to/orphanpid</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4028101%2F1e9564f6-144f-4c70-b068-14549c8458b3.jpg</url>
      <title>DEV Community: 🔻 🇵🇸</title>
      <link>https://dev.to/orphanpid</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/orphanpid"/>
    <language>en</language>
    <item>
      <title>Beans: a compiled language for backend services, with no null, no exceptions, and no GC pauses</title>
      <dc:creator>🔻 🇵🇸</dc:creator>
      <pubDate>Fri, 09 Oct 2026 15:23:21 +0000</pubDate>
      <link>https://dev.to/orphanpid/beans-a-compiled-language-for-backend-services-with-no-null-no-exceptions-and-no-gc-pauses-3nkf</link>
      <guid>https://dev.to/orphanpid/beans-a-compiled-language-for-backend-services-with-no-null-no-exceptions-and-no-gc-pauses-3nkf</guid>
      <description>&lt;p&gt;Beans is a compiled language for backend services and business systems. I have been building it for a while. This post covers the two things I care about most: how it stays safe, and how it stays fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety: failure is part of the type
&lt;/h2&gt;

&lt;p&gt;Beans has no null and no exceptions.&lt;/p&gt;

&lt;p&gt;If a value can be missing, its type is &lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt;. If a function can fail, it returns &lt;code&gt;Result&amp;lt;T&amp;gt;&lt;/code&gt;. You handle it with &lt;code&gt;match&lt;/code&gt;, or pass it up with &lt;code&gt;?&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import std.io

fn parse_qty(text: string) -&amp;gt; Result&amp;lt;int&amp;gt; {
    let qty: int = text.to_int()?
    if qty &amp;lt;= 0 {
        return err("quantity must be positive, got {qty}")
    }
    return ok(qty)
}

fn main() {
    match parse_qty("abc") {
        ok(qty) =&amp;gt; { io.println("qty {qty}") }
        err(e) =&amp;gt; { io.println("rejected: {e}") }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prints &lt;code&gt;rejected: can't read 'abc' as int&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The part I like most is what happens when you forget. If you try to use the result as a plain number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let qty: int = parse_qty("5")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the compiler stops you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No crash at 3 AM. The mistake shows up at build time.&lt;/p&gt;

&lt;p&gt;Raw pointers and raw memory exist, because Beans is also for systems work. But they only work inside &lt;code&gt;unsafe&lt;/code&gt; blocks, so you can find every risky line with one search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance: native code, predictable memory
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native binaries through LLVM.&lt;/strong&gt; &lt;code&gt;beansc build app.b -o app&lt;/code&gt; gives you one executable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference counting, not a tracing GC.&lt;/strong&gt; Memory is freed when the last reference goes away. A cycle collector cleans up loops. There are no stop-the-world pauses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ownership control when you need it.&lt;/strong&gt; &lt;code&gt;move&lt;/code&gt; hands a value over without a copy. &lt;code&gt;Shared&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Weak&amp;lt;T&amp;gt;&lt;/code&gt; make sharing explicit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fibers and threads.&lt;/strong&gt; Fibers for cheap concurrency, plus threads, channels, mutexes, and typed atomics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I do not publish speed numbers yet. The benchmark suite runs each workload against tuned C++ references, with fixed checksums and a 3% variance limit. A result only counts if it passes on both Linux x86-64 and macOS ARM64. When it does, I will post the numbers, good or bad.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two engines, one answer
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;beansc run&lt;/code&gt; runs code in an interpreter, so iteration is fast. &lt;code&gt;beansc build&lt;/code&gt; makes the native binary. The test suite runs programs both ways and checks they give the same output. It also checks that the compiler, which is written in Beans, rebuilds itself byte for byte.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can build today
&lt;/h2&gt;

&lt;p&gt;A web API with Espresso: controllers, constructor injection, middleware, OpenAPI, on a non-blocking HTTP/1.1 event loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import github.com/beans-lang/espresso

@espresso.controller(route: "/hello")
pub class HelloController extends espresso.Controller {
    pub fn init() {}

    @espresso.get(route: r"/{name}")
    pub fn hello(@espresso.route name: string) -&amp;gt;
        Result&amp;lt;espresso.ActionResult&amp;gt; {
        return self.ok_text("Hello, {name}!")
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even here, the action returns a &lt;code&gt;Result&lt;/code&gt;. Errors stay values all the way up.&lt;/p&gt;

&lt;p&gt;Also in the ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latte: server-rendered UI components that can also run in the browser as WebAssembly.&lt;/li&gt;
&lt;li&gt;Cortado: native desktop apps.&lt;/li&gt;
&lt;li&gt;Drivers for PostgreSQL, MySQL, SQLite, and Redis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where it stands
&lt;/h2&gt;

&lt;p&gt;Beans is pre-1.0 (v0.1.52). Things can still change. I am looking for people to build a small real tool with it and tell me what breaks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/beans-lang/beans" rel="noopener noreferrer"&gt;https://github.com/beans-lang/beans&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://beans-lang.github.io/docs/" rel="noopener noreferrer"&gt;https://beans-lang.github.io/docs/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it, I would like to hear what felt wrong.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>compilers</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
