14 Feb 2026

feedPlanet Mozilla

Niko Matsakis: Sharing in Dada

OK, let's talk about sharing. This is the first of Dada blog posts where things start to diverge from Rust in a deep way and I think the first where we start to see some real advantages to the Dada way of doing things (and some of the tradeoffs I made to achieve those advantages).

We are shooting for a GC-like experience without GC

Let's start with the goal: earlier, I said that Dada was like "Rust where you never have to type as_ref". But what I really meant is that I want a GC-like experience-without the GC.

We are shooting for a "composable" experience

I also often use the word "composable" to describe the Dada experience I am shooting for. Composable means that you can take different things and put them together to achieve something new.

Obviously Rust has many composable patterns - the Iterator APIs, for example. But what I have found is that Rust code is often very brittle: there are many choices when it comes to how you declare your data structures and the choices you make will inform how those data structures can be consumed.

Running example: Character

Defining the Character type

Let's create a type that we can use as a running example throughout the post: Character. In Rust, we might define a Character like so:

#[derive(Default)]
struct Character {
    name: String,
    class: String,
    hp: u32,
}

Creating and Arc'ing the Character

Now, suppose that, for whatever reason, we are going to build up a character programmatically:

let mut ch = Character::default();
ch.name.push_str("Ferris");
ch.class.push_str("Rustacean");
ch.hp = 44;

So far, so good. Now suppose I want to share that same Character struct so it can be referenced from a lot of places without deep copying. To do that, I am going to put it in an Arc:

let mut ch = Character::default();
ch.name.push_str("Ferris");
// ...
let ch1 = Arc::new(ch);
let ch2 = ch1.clone();

OK, cool! Now I have a Character that is readily sharable. That's great.

Rust is composable here, which is cool, we like that

Side note but this is an example of where Rust is composable: we defined Character once in a fully-owned way and we were able to use it mutably (to build it up imperatively over time) and then able to "freeze" it and get a read-only, shared copy of Character. This gives us the advantages of an imperative programming language (easy data construction and manipulation) and the advantages of a functional language (immutability prevents bugs when things are referenced from many disjoint places). Nice!

Creating and Arc'ing the Character

Now, suppose that I have some other code, written independently, that just needs to store the character's name. That code winds up copying the name into a lot of different places. So, just like we used Arc to let us cheaply reference a single character from multiple places, it uses Arc so it can cheaply reference the character's name from multiple places:

struct CharacterSheetWidget {
    // Use `Arc<String>` and not `String` because
    // we wind up copying this into name different
    // places and we don't want to deep clone
    // the string each time.
    name: Arc<String>,

    // ... assume more fields here ...
}

OK. Now comes the rub. I want to create a character-sheet widget from our shared character:

fn create_character_sheet_widget(ch: Arc<Character>) -> CharacterSheetWidget {
    CharacterSheetWidget {
        // FIXME: Huh, how do I bridge this gap?
        // I guess I have to do this.
        name: Arc::new(ch.name.clone()),

        // ... assume more fields here ...
    }
}

Shoot, that's frustrating! What I would like to do is to write name: ch.name.clone() or something similar (actually I'd probably like to just write ch.name, but anyhow) and get back an Arc<String>. But I can't do that. Instead, I have to deeply clone the string and allocate a new Arc. Of course any subsequent clones will be cheap. But it's not great.

Rust often gives rise to these kind of "impedance mismatches"

I often find patterns like this arise in Rust: there's a bit of an "impedance mismatch" between one piece of code and another. The solution varies, but it's generally something like

The goal with Dada is that we don't have that kind of thing.

Sharing is how Dada copies

So let's walk through how that same Character example would play out in Dada. We'll start by defining the Character class:

class Character(
    name: String,
    klass: String,  # Oh dang, the perils of a class keyword!
    hp: u32,
)

Just as in Rust, we can create the character and then modify it afterwards:

class Character(name: String, klass: String, hp: u32)

let ch: given Character = Character("", "", 22)
      # ----- remember, the "given" permission
      #       means that `ch` is fully owned
ch.name!.push("Tzara")
ch.klass!.push("Dadaist")
   #    - and the `!` signals mutation

The .share operator creates a shared object

Cool. Now, I want to share the character so it can be referenced from many places. In Rust, we created an Arc, but in Dada, sharing is "built-in". We use the .share operator, which will convert the given Character (i.e., fully owned character) into a shared Character:

class Character(name: String, klass: String, hp: u32)

let ch = Character("", "", 22)
ch!.push("Tzara")
ch!.push("Dadaist")

let ch1: shared Character = ch.share
      #  ------                -----
      # The `share` operator consumes `ch`
      # and returns the same object, but now
      # with *shared* permissions.

shared objects can be copied freely

Now that we have a shared character, we can copy it around:

class Character(name: String, klass: String, hp: u32)

# Create a shared character to start
let ch1 = Character("Tzara", "Dadaist", 22).share
    #                                       -----

# Create another shared character
let ch2 = ch1

Sharing propagates from owner to field

When you have a shared object and you access its field, what you get back is a shared (shallow) copy of the field:

class Character(...)

# Create a `shared Character`
let ch: shared Character = Character("Tristan Tzara", "Dadaist", 22).share
      # ------                                                       -----

# Extracting the `name` field gives a `shared String`
let name: shared String = ch1.name
        # ------

Propagation using a Vec

To drill home how cool and convenient this is, imagine that I have a Vec[String] that I share with .share:

let v: shared Vec[String] = ["Hello", "Dada"].share

and then I share it with v.share. What I get back is a shared Vec[String]. And when I access the elements of that, I get back a shared String:

let v = ["Hello", "Dada"].share
let s: shared String = v[0]

This is as if one could take a Arc<Vec<String>> in Rust and get out a Arc<String>.

How sharing is implemented

So how is sharing implemented? The answer lies in a not-entirely-obvious memory layout. To see how it works, let's walk how a Character would be laid out in memory:

# Character type we saw earlier.
class Character(name: String, klass: String, hp: u32)

# String type would be something like this.
class String {
    buffer: Pointer[char]
    initialized: usize
    length: usize
}

Here Pointer is a built-in type that is the basis for Dada's unsafe code system.1

Layout of a given Character in memory

Now imagine we have a Character like this:

let ch = Character("Duchamp", "Dadaist", 22)

The character ch would be laid out in memory something like this (focusing just on the name field):

[Stack frame]              [Heap]         
ch: Character {                           
    _flag: 1                              
    name: String {                        
        _flag: 1         { _ref_count: 1  
        buffer: ──────────►'D'            
        initialized: 7     ...            
        capacity: 8        'p' }          
    }                                     
    klass: ...                            
    hp: 22                                
}                                         

Let's talk this through. First, every object is laid out flat in memory, just like you would see in Rust. So the fields of ch are stored on the stack, and the name field is laid out flat within that.

Each object that owns other objects begins with a hidden field, _flag. This field indicates whether the object is shared or not (in the future we'll add more values to account for other permissions). If the field is 1, the object is not shared. If it is 2, then it is shared.

Heap-allocated objects (i.e., using Pointer[]) begin with a ref-count before the actual data (actually this is at the offset of -4). In this case we have a Pointer[char] so the actual data that follows are just simple characters.

Layout of a shared Character in memory

If I were to instead create a shared character:

let ch1 = Character("Duchamp", "Dadaist", 22).share
          #                                   -----

The memory layout would be the same, but the flag field on the character is now 2:

[Stack frame]              [Heap]         
ch: Character {                           
    _flag: 2 👈 (This is 2 now!)                             
    name: String {                        
        _flag: 1         { _ref_count: 1  
        buffer: ──────────►'D'            
        initialized: 7     ...            
        capacity: 8        'p' }          
    }                                     
    klass: ...                            
    hp: 22                                
}                                         

Copying a shared Character

Now imagine that we created two copies of the same shared character:

let ch1 = Character("Duchamp", "Dadaist", 22).share
let ch2 = ch1

What happens is that we will copy all the fields of _ch1 and then, because _flag is 2, we will increment the ref-counts for the heap-allocated data within:

[Stack frame]              [Heap]            
ch1: Character {                             
    _flag: 2                                 
    name: String {                           
        _flag: 1         { _ref_count: 2     
        buffer: ────────┬─►'D'        👆     
        initialized: 7  │  ...      (This is 
        capacity: 8     │  'p' }     2 now!) 
    }                   │                    
    class: ...          │                    
    hp: 22              │                    
}                       │                    
                        │                    
ch2: Character {        │                    
    _flag: 2            │                    
    name: String {      │                    
        _flag: 1        │                    
        buffer: ────────┘                    
        initialized: 7                       
        capacity: 8                          
    }                                        
    class: ...                               
    hp: 22                                   
}                                            

Copying out the name field

Now imagine we were to copy out the name field, instead of the entire character:

let ch1 = Character("Duchamp", "Dadaist", 22).share
let name = ch1.name

…what happens is that:

  1. traversing ch1, we observe that the _flag field is 2 and therefore ch1 is shared
  2. we copy out the String fields from name. Because the character is shared:
    • we modify the _flag field on the new string to 2
    • we increment the ref-count for any heap values

The result is that you get:

[Stack frame]              [Heap]       
ch1: Character {                        
    _flag: 2                            
    name: String {                      
        _flag: 1         { _ref_count: 2
        buffer: ────────┬─►'D'          
        initialized: 7  │  ...          
        capacity: 8     │  'p' }        
    }                   │               
    class: ...          │               
    hp: 22              │               
}                       │               
                        │               
name: String {          │               
    _flag: 2            │               
    buffer: ────────────┘               
    initialized: 7                      
    capacity: 8                         
}                                       

"Sharing propagation" is one example of permission propagation

This post showed how shared values in Dada work and showed how the shared permission propagates when you access a field. Permissions are how Dada manages object lifetimes. We've seen two so far

In future posts we'll see the ref and mut permissions, which roughly correspond to & and &mut, and talk out how the whole thing fits together.

Dada is more than a pretty face

This is the first post where we started to see a bit more of Dada's character. Reading over the previous few posts, you could be forgiven for thinking Dada was just a cute syntax atop familiar Rust semantics. But as you can see from how shared works, Dada is quite a bit more than that.

I like to think of Dada as "opinionated Rust" in some sense. Unlike Rust, it imposes some standards on how things are done. For example, every object (at least every object with a heap-allocated field) has a _flag field. And every heap allocation has a ref-count.

These conventions come at some modest runtime cost. My rule is that basic operations are allowed to do "shallow" operations, e.g., toggling the _flag or adjusting the ref-counts on every field. But they cannot do "deep" operations that require traversing heap structures.

In exchange for adopting conventions and paying that cost, you get "composability", by which I mean that permissions in Dada (like shared) flow much more naturally, and types that are semantically equivalent (i.e., you can do the same things with them) generally have the same layout in memory.


  1. Remember that I have not implemented all this, I am drawing on my memory and notes from my notebooks. I reserve the right to change any and everything as I go about implementing. ↩︎

14 Feb 2026 11:49am GMT

13 Feb 2026

feedPlanet Mozilla

Thunderbird Blog: Mobile Progress Report: February 2026

The first Mobile Progress Report of 2026 provides a high-level overview to our mobile plans and priorities for the coming year.

Android

Our primary focus this year revolves around a better user experience and includes a major push to improve quality. We want to make the app stable, reduce our bugs, and speed up our development process. To do this, we have to make some big changes and improvements to the app's basic structure and database. We're moving toward modern Android standards, which includes using technologies like Compose and creating a single, consistent design system for our User Interface.

But we don't want a year of just code fixes; we know we need to add features, especially around messaging & notifications. We're making sure we deliver features and improve the user experience along the way. It's a tricky balance between making the app better for users and overhauling the inner workings. We think these changes are worth the investment because they'll lead to a better app, and ultimately, a better app for everyone. So the focus is better quality and simplifying the code to make us quicker.

Thunderbird has a new product - Thunderbird Pro - and as it comes more online, we plan to connect the Android app to it.

Here are our priorities for the year. P1 is the top focus:

P1

P2

P3

iOS

The main thing we're trying to do for iOS this year is successfully launch Version 1 of our app. That sounds simple, but it involves building a lot of complicated, low-level foundational things.

This quarter, we're concentrating on finishing up the IMAP and SMTP pieces, getting our design system established, and building the basic UI so we can start using these pieces. After that, we'll shift to implementing OAuth. This will stop users from having to use confusing processes, like creating an app token, and let them sign in easily through the standard account import process with a simple User Interface.

Once we have IMAP and OAuth ready, we'll have the absolute bare minimum for a mail app, allowing users to send and receive email. But there are other features you'd expect in a mail app, like mailboxes, signatures, rich text viewing, attachment handling, and the compose experience. We've already made great progress on the underlying functionality, and we have a clear vision of what needs to be implemented to make this successful.

Our key priorities for iOS are:

P1

P2

It's exciting to see the momentum that the iOS app is gaining and to get a clearer picture of what we need to do for the Android app to simplify things. We are getting farther on fewer, more targeted goals. I look forward to communicating with you over the next few months and share the progress that we are making.
-

Jon Bott (he/him)

Manager, Mobile Apps

The post Mobile Progress Report: February 2026 appeared first on The Thunderbird Blog.

13 Feb 2026 3:19pm GMT

The Mozilla Blog: Heading to India AI Impact Summit, Mozilla leaders call for investment in open source AI as a path to sovereignty

Large black AI letters over purple cloud graphic on pink background.

Mozilla is headed to New Delhi, India for the India AI Impact Summit 2026 next week with a message: Open Source is the path to both economic and digital sovereignty. Participating in dozens of events across the weeklong global forum, Mozilla leaders will make the case that a different kind of AI future is possible, and that global action is urgently needed to build a global AI ecosystem firmly grounded in the public interest.

"We're at a crossroads for AI, where the world can continue to rent from a few big global corporations, or can take back control," said Mark Surman, president of Mozilla. "To build national resilience and lower costs for their domestic stakeholders, countries should leave India ready to meaningfully invest in open source AI as a transformational solution."

As part of the India AI Impact Summit 2026, Mozilla is curating three official events that showcase its work to help build a more decentralized AI ecosystem. These include panels on the state of competition in AI, how open source AI can operationalize digital sovereignty, and the launch of a new convenings program aimed at Bollywood artists and filmmakers to explore the future of creativity in the age of AI. Mozilla will also host a community party for open source AI developers and founders.

At the Summit, Mozilla will speak to growing concerns about consolidation in the AI landscape, with just a few large global corporations essentially renting access to AI to the rest of the world. As more powerful AI systems are built and controlled behind closed platforms, users are left with little visibility into how these systems work and almost no ability to shape or govern them. This concentration of control means a small number of companies can decide who gets access to advanced AI, on what terms, and at what cost, with far-reaching consequences for innovation, public institutions, and digital sovereignty.

Mozilla believes this growing concentration of AI control threatens innovation, fair competition and public accountability. To counter this, Mozilla is investing in people, products, and organizations working to build a more open and human-centered AI ecosystem. Open source AI is a key part of this effort, providing practical, real-world infrastructure that allows systems to be inspected, improved locally, and governed in the public interest.

In partnership with G5A, Mozilla Foundation will also launch "The Origin of Thought" at the Summit - a new initiative to explore the intersections of culture and AI. The program will convene Bollywood artists, filmmakers, technologists, and cultural practitioners to help shape a nuanced, multi-faceted understanding of AI's impact on our lives - not just as a tool but as a potential cultural force. The first taster session, held at The Oddbird Theatre in New Delhi, will feature filmmakers Nikkhil Advani and Shakun Batra.

"Creativity has always been how people make sense of change, long before policy frameworks or product roadmaps catch up. As AI reshapes how culture is made, shared, and remembered, we need spaces that slow the conversation down enough to ask what we're protecting and why," said Nabiha Syed, executive director of Mozilla Foundation. "The Origin of Thought brings artists, technologists, and decision-makers together to look beyond efficiency and novelty, and toward the human stakes of this moment. This work reflects our belief that imagination is a critical safeguard, not a luxury. When we center creative voices, we make it possible to build technologies that expand opportunity, dignity, and livelihoods."

Through its participation at the India AI Impact Summit 2026, Mozilla will reaffirm its commitment to building an AI future that is open, accountable, and shaped by the societies it is meant to serve, and to ensuring that open source AI remains a central pillar of global AI governance and innovation.

"Technology should adapt to humanity, not the other way around," said Raffi Krikorian, CTO of Mozilla. "Across our entire portfolio, Mozilla is working to decentralize the future of AI - from building new tools for developers to supporting creators to building all levels of the open source AI ecosystem. India, with its incredible community of founders, startups, and developers, knows firsthand that open source AI is where innovation is going next."

The post Heading to India AI Impact Summit, Mozilla leaders call for investment in open source AI as a path to sovereignty appeared first on The Mozilla Blog.

13 Feb 2026 1:00pm GMT

The Rust Programming Language Blog: crates.io: an update to the malicious crate notification policy

The crates.io team will no longer publish a blog post each time a malicious crate is detected or reported. In the vast majority of cases to date, these notifications have involved crates that have no evidence of real world usage, and we feel that publishing these blog posts is generating noise, rather than signal.

We will always publish a RustSec advisory when a crate is removed for containing malware. You can subscribe to the RustSec advisory RSS feed to receive updates.

Crates that contain malware and are seeing real usage or exploitation will still get both a blog post and a RustSec advisory. We may also notify via additional communication channels (such as social media) if we feel it is warranted.

Recent crates

Since we are announcing this policy change now, here is a retrospective summary of the malicious crates removed since our last blog post and today:

In all cases, the crates were deleted, the user accounts that published them were immediately disabled, and reports were made to upstream providers as appropriate.

Thanks

Once again, our thanks go to Matthias, Socket, and the reporter of polymarket-client-sdks for their reports. We also want to thank Dirkjan Ochtman from the secure code working group, Emily Albini from the security response working group, and Walter Pearce from the Rust Foundation for aiding in the response.

13 Feb 2026 12:00am GMT

12 Feb 2026

feedPlanet Mozilla

Hacks.Mozilla.Org: Launching Interop 2026

The Interop Project is a cross-browser initiative to improve web compatibility in areas that offer the most benefit to both users and developers.

The group, including Apple, Google, Igalia, Microsoft, and Mozilla, takes proposals of features that are well defined in a sufficiently stable web standard, and have good test suite coverage. Then, we come up with a subset of those proposals that balances web developer priorities (via surveys and bug reports) with our collective resources.

We focus on features that are well-represented in Web Platform Tests as the pass-rate is how we measure progress, which you can track on the Interop dashboard.

Once we have an agreed set of focus areas, we use those tests to track progress in each browser throughout the year. And after that, we do it all again!

But, before we talk about 2026, let's take a look back at Interop 2025…

Interop 2025

Interop dashboard showing browser scores. At the top are two large circles: ‘Interop’ with a score of 95 in green, and ‘Investigations’ with a score of 36 in orange. Below are four browser scores in green circles: Chrome 99, Edge 98, Firefox 99, and Safari 98, each shown with their respective browser icons.

Firefox started Interop 2025 with a score of 46, so we're really proud to finish the cycle on 99. But the number that really matters is the overall Interop score, which is a combined score for all four browsers - and the higher this number is, the fewer developer hours are lost to frustrating browser differences.

The overall Interop score started at 25, and it's now 95. As a result, huge web platform features became available cross-browser, such as Same-Document View Transitions, CSS Anchor Positioning, the Navigation API, CSS @scope, and the URLPattern API.

That's the headline-grabbing part, but in my experience, it's way more frustrating when a feature is claimed to be supported, but doesn't work as expected. That's why Interop 2025 also focused on improving the reliability of existing features like WebRTC, CSS Flexbox, CSS Grid, Pointer Events, CSS backdrop-filter, and more.

But it's not just about passing tests

With some focus areas, in particular CSS Anchor Positioning and the Navigation API, we noticed that it was possible to achieve a good score on the tests while having inconsistent behavior compared to other browsers.

In some cases this was due to missing tests, but in some cases the tests contradicted the spec. This usually happens when tests are written against a particular implementation, rather than the specified behavior.

I experienced this personally before I joined Mozilla - I tried to use CSS Anchor Positioning back when it was only shipping in Chrome and Safari, and even with simple use-cases, the results were wildly inconsistent.

Although it caused delays in these features landing in Firefox, we spent time highlighting these problems by filing issues against the relevant specs, and ensured they got priority in their working groups. As a result, specs became less ambiguous, tests were improved, and browser behavior became more reliable for developers.

Okay, that's enough looking at the past. Let's move on to…

Interop 2026

Over 150 proposals were submitted for Interop 2026. We looked through developer feedback, on the issues themselves, and developer surveys like The State of HTML and The State of CSS. As an experiment for 2026, we at Mozilla also invited developers to stack-rank the proposals, the results of which we used in combination with the other data to compare developer preferences between individual features - this is something we want to expand on in the future.

After carefully examining all the proposals, the Interop group has agreed on 20 focus areas (formed of 33 proposals) and 4 investigation areas. See the Interop repository for the full list, but here are the highlights:

New features

As with 2025, part of the effort is about bringing new features to all browser engines.

Cross-document View Transitions allow transitions to work across documents, without any JavaScript. The sub-features rel="expect" and blocking="render" are included in this focus area..

Scroll-driven animations allow you to drive animations based on the user's scroll position. This replaces heavy JavaScript solutions that run on the main thread.

WebTransport provides a low-level API over HTTP/3, allowing for multiple unidirectional streams, and optional out-of-order delivery. This is a modern alternative to WebSockets.

CSS container style queries allow you to apply a block of styles depending on the computed values of custom properties on the nearest container. This means, for example, you can have a simple --theme property that impacts a range of other properties.

JavaScript Promise Integration for Wasm allows WebAssembly to asynchronously 'suspend', waiting on the result of an external promise. This simplifies the compilation of languages like C/C++ which expect APIs to run synchronously.

CSS attr() has been supported across browsers for over 15 years, but only for pseudo-element content. For Interop 2026, we're focusing on more recent changes that allow attribute values to be used in most CSS values (with URLs being an exception).

CSS custom highlights let you register a bunch of DOM ranges as a named highlight, which you can style via the ::highlight(name) pseudo-element. The styling is limited, but it means these ranges can span between elements, don't impact layout, and don't disrupt things like text selection.

Scoped Custom Element Registries allow different parts of your DOM tree (such as a shadow root) to use a different set of custom elements definitions, meaning the same tag name can refer to different custom elements depending on where they are in the DOM.

CSS shape() is a reimagining of path() that, rather than using SVG path syntax, uses a CSS syntax, allowing for mixed units and calc(). In practice, this makes it much easier to design responsive clip-paths and offset-paths.

And more, including CSS contrast-color, accent-color, dialog closedby, popover="hint", fetch upload streams, IDB getAllRecords(), media pseudo-classes such as :playing, and the Navigation API's precommitHandler.

Existing feature reliability improvements

Like in previous years, the backbone of Interop is in improving the reliability of existing features, removing frustrations for web developers.

In 2026, we'll be focusing these efforts on particular edge cases in:

Some of these are carried over from 2025 focus areas, as shortcomings in the tests and specs were fixed, but too late to be included in Interop 2025.

Again, these are less headline-grabbing than the shiny new features, but it's these edge cases where us web developers lose hours of our time. Frustrating, frustrating, hours.

Interop investigations

Sometimes, we see a focus area proposal that's clearly important, but doesn't fit the requirements of Interop. This is usually because the tests for the feature aren't sufficient, are in the wrong format, or browsers are missing automation features that are needed to make the feature testable.

In these cases, we identify what's missing, and set up an investigation area.

For interop 2026, we're looking at…

Accessibility. This is a continuation of work in 2025. Ultimately, we want browsers to produce consistent accessibility trees from the same DOM and CSS, but before we can write tests for this, we need to improve our testing infrastructure.

Mobile testing. Another continuation from 2025. In particular, in 2026, we want to figure out an approach for testing viewport changes caused by dynamic UI, such as the location bar and virtual keyboard.

JPEG XL. The current tests for this are sparse. Existing decoders have more comprehensive test suites, but we need to figure out how these relate to browsers. For example, progressive rendering is an important feature for developers, but how and when browsers should do this (to avoid performance issues) is currently being debated.

WebVTT. This feature allows for text to be synchronised to video content. The investigation is to go through the test suite and ensure it's fit for purpose, and amend it where necessary.

It begins… again

The selected focus areas mean we've committed to more work compared to the other browsers, which is quite the challenge being the only engine that isn't owned by billionaires. But it's a challenge we're happy to take on!

Together with other members of the Interop group, we're looking forward to delivering features and fixes over the next year. You can follow along with the progress of all browsers on the Interop dashboard.

If your favorite feature is missing from Interop 2026, that doesn't mean it won't be worked on. JPEG XL is a good example of this. The current test suite meant it wasn't a good fit for Interop 2026, but we've challenged the JPEG XL team at Google Research to build a memory-safe decoder in Rust, which we're currently experimenting with in Firefox, as is Chrome.

Interop isn't the limit of what we're working on, but it is a cross-browser commitment.

If you're interested in details of features as they land in Firefox, and discussions of future features from spec groups, you can follow us on:

Partner Announcements

This is a team effort, and we've all made announcement posts like this one. Get other members' take on it:

The post Launching Interop 2026 appeared first on Mozilla Hacks - the Web developer blog.

12 Feb 2026 5:07pm GMT

Mozilla Localization (L10N): Pontoon Translation Search: Unifying Localization Across Mozilla

Here at Mozilla, we are tirelessly working to bring our products to a global audience. Pontoon, our in-house translation management system plays a central role, where volunteer localizers work to bring translations for Firefox, Thunderbird, SUMO and other Mozilla products.

Recently, we have been working to unify localization tools and give localizers and developers smoother, more streamlined workflows. This is why we are excited to introduce Pontoon's new Translation Search feature, where everyone can search for strings across all projects and locales at Mozilla.

What is the Translation Search Feature?

Translation Search is Pontoon's latest way to access our extensive collection of translations, built up through years of localization work by fellow Mozillians. This new feature allows localizers to search for strings across all projects and all locales at Mozilla. Inspired by the functionality of Transvision, it is intended to be a suitable replacement and includes many of the various features that localizers rely on.

Let's go through some of its features and how they can apply to your localization workflows.

Searching for Translations

Pontoon's new Translation Search, where users can search for strings through all projects and locales.

Searching for strings in Translation Search is simple. Similar to how Transvision operates, you can search within a specific project and locale, as well as filter by string identifiers, case sensitivity and whole word search. Unlike Transvision, Pontoon Translation Search covers all products localized at Mozilla. It is also completely integrated with other Pontoon elements, including Translate, such that you can seamlessly navigate to Translate after your search.

Transvision's search functionality, which we intend to replace.

Finding Entity Translations

Pontoon's new Entity Translations page, which lists available translations for a source string.

If you want to get a better picture of a source string with different translations, go to the Entity Translations page. By clicking the "All Locales" button in Translation Search for a string, you can see the source string translated into every available locale. This is useful for comparing similar locale translations and getting a broader picture of a string's context. This feature is intended to replace Transvision's translation list for a particular entity.

Transvision's string translation list, which we intend to replace.

Searching from Firefox Address Bar

If you have the Pontoon Add-on installed to the latest version, you can now search for strings directly from the address bar in Firefox: you can select Pontoon from the list of search engines, or start typing pontoon and press TAB.

How to use Translation Search with Pontoon Add-on.

Pontoon Translation Search is Live!

This feature is available now and ready for you to use. Head over to pontoon.mozilla.org/search to try out the new search experience and streamline your localization work! If you have any questions or concerns about Translation Search, do not hesitate to contact us on Matrix or file an issue. You can also consult the documentation here.

12 Feb 2026 8:14am GMT

The Rust Programming Language Blog: Announcing Rust 1.93.1

The Rust team has published a new point release of Rust, 1.93.1. Rust is a programming language that is empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, getting Rust 1.93.1 is as easy as:

rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website.

What's in 1.93.1

Rust 1.93.1 resolves three regressions that were introduced in the 1.93.0 release.

Contributors to 1.93.1

Many people came together to create Rust 1.93.1. We couldn't have done it without all of you. Thanks!

12 Feb 2026 12:00am GMT

11 Feb 2026

feedPlanet Mozilla

Thunderbird Blog: Thunderbird Monthly Development Digest: February 2026

Welcome back to the Thunderbird blog and the first post of 2026! We're rested, recharged, and ready to keep our community updated on all of our progress on the desktop and mobile clients and with Thunderbird Pro!

Hello again from the Thunderbird development team! After a restful and reflective break over the December holidays, the team returned recharged and ready to take on the mountain of priorities ahead.

To everyone we met during the recent FOSDEM weekend, thank you! The conversations, encouragement, and thoughtful feedback you shared were genuinely energizing, and many of your insights are already helping us better understand the real-world challenges you're facing. The timing couldn't have been better, as FOSDEM provided a strong early-year boost of inspiration, collaboration, and perspective.

FOSDEM - Collaboration, learning and real conversations

This year, a larger contingent of the Thunderbird team joined our Mozilla colleagues in Brussels for an intense and rewarding FOSDEM weekend. Across talks, hallway chats, and long discussions at the Thunderbird booth, we dug into standards, shared hard-won lessons, debated solutions, and explored what's next for open communication tools.

The highlight, as always, was meeting users face-to-face. Hearing your stories about what's working, what's painful, and what you'd like to see next continues to be one of the most motivating parts of our work.

Several recurring themes stood out in these discussions, and we're keen to help move the needle on some of the bigger, knottier challenges, including:

These conversations don't end when FOSDEM does but help shape our priorities for the months ahead, and we're grateful to everyone who took the time to stop by, ask questions, or share their experiences.

Exchange Email Support

After releasing Exchange support for email to the Monthly release channel, we've had some great feedback and helpful diagnosis of edge case problems that we've been prioritizing for the past few weeks

Work completed during this period includes:

Work on supporting the Graph API protocol for email is moving steadily through the early stages, with these basic components already shipped to Daily:

Keep track of our Graph API implementation here.

Account Hub

The team met in person following FOSDEM and have planned out work to allow the new Account Hub UX to be used as the default experience in our next Extended Support Release this summer, which will ensure users benefit from changes we've made to enable custom Oauth settings and configuration specific to Microsoft Exchange.

Follow progress in the meta bugs for the last few pieces of phase 3 and telemetry, as well as the work we've defined to enable an interim experience for users setting up Thunderbird for the first time.

Calendar UI Rebuild

The new Calendar UI work has advanced at a good pace in recent weeks and the team met in person to break the work apart into chunks which have been prioritized alongside some of the "First Time User Experience" milestones. The team has recently:

Stay tuned to our milestones here:

Maintenance, Upstream adaptations, Recent Features and Fixes

Over the past couple of months, a significant portion of the team's time has gone into responding to upstream changes that have impacted build stability, test reliability, and CI. Sheriffing continues to be a challenge, with frequent breakages requiring careful investigation to separate upstream regressions from Thunderbird-specific changes.

Alongside this ongoing maintenance work, we've also benefited greatly from contributions across the wider development community. Thanks to that collective effort, a steady stream of fixes and improvements has landed.

More broadly and focusing on our roadmap, the last two months have seen solid progress on Fluent migrations, as well as planning and early groundwork for rolling out Redux and the Design System more widely across the codebase.

Support from the community and team has resulted in some notable patches landing in recent weeks, with the following of particular help:

If you would like to see new features as they land, and help us find some early bugs, you can try running daily and check the pushlog to see what has recently landed. This assistance is immensely helpful for catching problems early.

Toby Pilling

Senior Manager, Desktop Engineering

The post Thunderbird Monthly Development Digest: February 2026 appeared first on The Thunderbird Blog.

11 Feb 2026 5:50pm GMT

Support.Mozilla.Org: What’s up with SUMO – H2 2025

Hi everyone,

We may already be a few weeks into 2026, but it's never too late to say Happy New Year! As we dive into the year ahead, we also want to take a moment to reflect on everything we accomplished together in the second half of 2025.

In this recap, you'll find highlights from community campaigns, major platform updates and product launches, as well as forum and Knowledge Base data that offer a clearer picture of how the community performed. We hope this snapshot helps celebrate what went well, while also shining a light on areas where we can continue to grow together.

Let's jump in!

Highlights

Community stats

Forum Support

General stats

The forum continues to show encouraging signs of community growth and maturity. Most notably, the solve rate more than doubled, jumping by 124% to reach 11.9%. This is a clear signal that contributors are not only engaging with users, but successfully resolving their issues at a much higher rate. We also saw a 9.8% increase in OP reply rate, suggesting stronger two-way engagement between users and contributors.

Improvements in speed reinforce this trend: first response time dropped by nearly 30%, while time to resolution was cut in half, falling by 48.9%. Combined with a 12.7% rise in reply rate and 15.7% more threads being actively supported, these results point to a community that's not just growing, but becoming more efficient, responsive, and impactful.

With the automatic spam moderation introduced in the first half of year, we've seen fewer total questions coming in H2 2025 but higher quality interactions overall. This shift suggests a more focused and intentional support environment. Taken together, these trends suggest that it's time to elevate solve rate from a "nice to have" to a core success metric, a meaningful reflection of contributor expertise, community trust, and the maturity of our Community Forums.

Total valid questions 14803 (-20%)
Reply rate 63.5 (+12.67%)
Solve rate 11.9% (+124%)
Total responses posted 14191 (+20.4%)
Total threads interacted 9599 (+15.7%)
Average first response time (in hour) 22.4 (-29.8%)
Average time to resolution (in day) 2.55 (-48.9%)
Total new registration 455k (+0.5%)
Total contributors 963 (-1.3%)
Helpful rate 60.8% (+3.92%)
OP reply rate 27% (+9.8%)

Top forum contributors

All credit for this impressive performance goes to our incredible forum community, who continue to raise the bar with each quarter. Their dedication, consistency, and responsiveness are what make these results possible.

We're proud to highlight the top 3 contributors on the English forum, along with the leading contributors across other locales. This shows a true reflection of the global impact of our support network.

Contributor name Total responses Total threads engaged
Paul Wright (en-US) 1900 1395
Denyshon (en-US) 1284 924
Jefferson Scher (en-US) 930 871
@next (it) 557 438
Gerardo (es) 523 457
Mark Heijl (nl) 186 155
Selim (tr) 126 87
Ansamb (cs) 87 65
Poljos-moz (cs) 81 59
Sandromonteiro (pt-BR) 15 15
Balázs Meskó (hu) 51 48
Vexi (sl) 5 5

Emerging forum contributors

Contributor name Total responses Total threads engaged
George Kitsoukakis 202 171
Mark 136 110
sjohnn 65 45
t.r.ernst 64 60
Jeff-g 61 54

Knowledge Base

General stats

We've seen an impressive uptick in article contributions in the second half of 2025, with 925 revisions submitted to the English Knowledge Base, a 21.9% increase compared to the previous period. This continued growth reflects not just dedication, but real momentum of the growing spirit to keep our Knowledge Base fresh and helpful for users worldwide.

This level of participation directly supports our broader direction towards improving and streamlining the content request workflow. As we continue investing in clearer processes and better documentation, it's clear that contributors are willing to step up when the pathway to impact is well defined.

Total en-US revisions 925 (+21.9%)
Total articles 248 (+2.9%)
Total revisions reviewed 821 (+19.9%)
Total revisions approved 778 (+17.7%)
Total authors 97
Total reviewers 19 (+11.8%)

Top KB contributors

The numbers may show progress, but the real story is the people behind them. Behind these revisions, 97 unique contributors stepped in to create the updates and 19 reviewers helped guide their contributions. And here's just a glimpse of the top 5 contributors:

Contributor name Total revisions Total articles Total reviews
AliceWyman 467 246 334
Pierre Mozinet 125 100 -
Mark Heijl 101 88 -
Michele Rodaro 50 46 35
Paul Wright 26 21 5

Article Localization

The localization community delivered an outstanding performance in H2 2025, despite undergoing significant changes. We saw 4807 non-English revisions submitted, a 37.5% increase, covering 2664 articles across locales (+29.7%). In total, 4,259 revisions were approved and 4,296 reviewed, reflecting consistent contributor dedication to quality and accuracy. Most notably, 314 unique contributors stepped up to author content, representing a 54.7% increase from earlier this year.

These results are especially meaningful given the rollout of Machine Translation in August, a major shift in localization workflow that understandably sparked concern and discussion across the community. Adjusting to MT required both flexibility and trust, and we're grateful that many contributors responded by showing up in full force. Your continued involvement ensured that translations remained thoughtful, context-aware, and aligned with Mozilla's values of openness and quality. This success is a testament to the strength, resilience, and care of our contributor base, and we're deeply grateful for your ongoing contribution.

General stats (minus sumoBot)

Total non en-US revisions 4807 (+37.5%)
Total articles 2664 (+29.7%)
Total revisions reviewed 4296 (+33.5%)
Total revisions approved 4259 (+33.6%)
Total authors 314 (+54.7%)
Total reviewers 45 (-6%)

Top localization contributors

Contributor name Total revisions Total articles Total reviews
Michele Rodaro (it) 819 393 801
Jim Spentzos (el) 727 566 555
Valery Ledovskoy (ru) 627 400 635
Mark Heijl (nl) 575 359 -
Milupo (dsb & hsb) 460 224 330

Emerging localization contributors

Contributor name Total revisions Total articles
普莱是袋熊 (zh-CN) 35 31
Zhengyang3552 (zh-CN) 22 21
xanhAD (vi) 13 11

Stay connected with the community

Join the Conversation

Attend Our Monthly Community Call

Stay Informed

Explore What We're Building

You can also view our latest release notes to stay informed about recent changes and improvements.

11 Feb 2026 7:00am GMT

This Week In Rust: This Week in Rust 638

Hello and welcome to another issue of This Week in Rust! Rust is a programming language empowering everyone to build reliable and efficient software. This is a weekly summary of its progress and community. Want something mentioned? Tag us at @thisweekinrust.bsky.social on Bluesky or @ThisWeekinRust on mastodon.social, or send us a pull request. Want to get involved? We love contributions.

This Week in Rust is openly developed on GitHub and archives can be viewed at this-week-in-rust.org. If you find any errors in this week's issue, please submit a PR.

Want TWIR in your inbox? Subscribe here.

Updates from Rust Community

Newsletters
Project/Tooling Updates
Observations/Thoughts
Rust Walkthroughs

Crate of the Week

This week's crate is zedbar, a crate to read QR codes and a bunch of other barcode formats from images.

Thanks to Brian Donovan for the self-suggestion!

Please submit your suggestions and votes for next week!

Calls for Testing

An important step for RFC implementation is for people to experiment with the implementation and give feedback, especially before stabilization.

If you are a feature implementer and would like your RFC to appear in this list, add a call-for-testing label to your RFC along with a comment providing testing instructions and/or guidance on which aspect(s) of the feature need testing.

No calls for testing were issued this week by Rust, Cargo, Rustup or Rust language RFCs.

Let us know if you would like your feature to be tracked as a part of this list.

Call for Participation; projects and speakers

CFP - Projects

Always wanted to contribute to open-source projects but did not know where to start? Every week we highlight some tasks from the Rust community for you to pick and get started!

Some of these tasks may also have mentors available, visit the task page for more information.

No Calls for participation were submitted this week.

If you are a Rust project owner and are looking for contributors, please submit tasks here or through a PR to TWiR or by reaching out on Bluesky or Mastodon!

CFP - Events

Are you a new or experienced speaker looking for a place to share something cool? This section highlights events that are being planned and are accepting submissions to join their event as a speaker.

If you are an event organizer hoping to expand the reach of your event, please submit a link to the website through a PR to TWiR or by reaching out on Bluesky or Mastodon!

Updates from the Rust Project

569 pull requests were merged in the last week

Compiler
Library
Cargo
Clippy
Rust-Analyzer
Rust Compiler Performance Triage

This week we saw quite a few improvements. Largest one comes from adding two targeted with_capacity calls in #151929. Another source of multiple improvements is the ongoing migration away from using external files to store diagnostic messages.

Triage done by @panstromek. Revision range: a60d12cb..39219ceb

Summary:

(instructions:u) mean range count
Regressions ❌
(primary)
2.0% [2.0%, 2.0%] 1
Regressions ❌
(secondary)
0.6% [0.0%, 2.0%] 22
Improvements ✅
(primary)
-0.8% [-2.8%, -0.2%] 179
Improvements ✅
(secondary)
-3.1% [-31.1%, -0.0%] 211
All ❌✅ (primary) -0.7% [-2.8%, 2.0%] 180

1 Regression, 6 Improvements, 7 Mixed; 9 of them in rollups 36 artifact comparisons made in total

Full report here

Approved RFCs

Changes to Rust follow the Rust RFC (request for comments) process. These are the RFCs that were approved for implementation this week:

Final Comment Period

Every week, the team announces the 'final comment period' for RFCs and key PRs which are reaching a decision. Express your opinions now.

Tracking Issues & PRs

Rust

Compiler Team (MCPs only)

Cargo

No Items entered Final Comment Period this week for Rust RFCs, Language Team, Language Reference, Leadership Council, or Unsafe Code Guidelines.

Let us know if you would like your PRs, Tracking Issues or RFCs to be tracked as a part of this list.

New and Updated RFCs

Upcoming Events

Rusty Events between 2026-02-11 - 2026-03-11 🦀

Virtual
Asia
Europe
North America
Oceania

If you are running a Rust event please add it to the calendar to get it mentioned here. Please remember to add a link to the event too. Email the Rust Community Team for access.

Jobs

Please see the latest Who's Hiring thread on r/rust

Quote of the Week

Unpopular opinion: error handling in Rust is actually fantastic. Once you know the right patterns, which regrettably are NOT always obvious 😂

- Ian Wagner on fosstodon

Despite another week with a lamentable lack of suggestions, llogiq is pleased with what he found.

Please submit quotes and vote for next week!

This Week in Rust is edited by:

Email list hosting is sponsored by The Rust Foundation

Discuss on r/rust

11 Feb 2026 5:00am GMT

Niko Matsakis: Dada: moves and mutation

Let's continue with working through Dada. In my previous post, I introduced some string manipulation. Let's start talking about permissions. This is where Dada will start to resemble Rust a bit more.

Class struggle

Classes in Dada are one of the basic ways that we declare new types (there are also enums, we'll get to that later).

The most convenient way to declare a class is to put the fields in parentheses. This implicitly declares a constructor at the same time:

class Point(x: u32, y: u32) {}

This is in fact sugar for a more Rust like form:

class Point {
    x: u32
    y: u32
    fn new() -> Point {
        Point { x, y }
    }
}

And you can create an instance of a class by calling the constructor:

let p = Point(22, 44) // sugar for Point.new(22, 44)

Mutating fields

I can mutate the fields of p as you would expect:

p.x += 1
p.x = p.y

Read by default

In Dada, the default when you declare a parameter is that you are getting read-only access:

fn print_point(p: Point) {
    print("The point is {p.x}, {p.y}")
}

let p = Point(22, 44)
print_point(p)

If you attempt to mutate the fields of a parameter, that would get you an error:

fn print_point(p: Point) {
    p.x += 1 # <-- ERROR!
}

Use ! to mutate

If you declare a parameter with !, then it becomes a mutable reference to a class instance from your caller:

fn translate_point(point!: Point, x: u32, y: u32) {
    point.x += x
    point.y += y
}

In Rust, this would be like point: &mut Point. When you call translate_point, you also put a ! to indicate that you are passing a mutable reference:

let p = Point(22, 44)     # Create point
print_point(p)            # Prints 22, 44
translate_point(p!, 2, 2) # Mutate point
print_point(p)            # Prints 24, 46 

As you can see, when translate_point modifies p.x, that changes p in place.

Moves are explicit

If you're familiar with Rust, that last example may be a bit surprising. In Rust, a call like print_point(p) would move p, giving ownership away. Trying to use it later would give an error. That's because the default in Dada is to give a read-only reference, like &x in Rust (this gives the right intuition but is also misleading; we'll see in a future post that references in Dada are different from Rust in one very important way).

If you have a function that needs ownership of its parameter, you declare that with given:

fn take_point(p: given Point) {
    // ...
}

And on the caller's side, you call such a function with .give:

let p = Point(22, 44)
take_point(p.give)
take_point(p.give) # <-- Error! Can't give twice.

Comparing with Rust

It's interesting to compare some Rust and Dada code side-by-side:

Rust Dada
vec.len() vec.len()
map.get(&key) map.get(key)
vec.push(element) vec!.push(element.give)
vec.append(&mut other) vec!.append(other!)
message.send_to(&channel) message.give.send_to(channel)

Design rationale and objectives

Convenient is the default

The most convenient things are the shortest and most common. So we make reads the default.

Everything is explicit but unobtrusive

The . operator in Rust can do a wide variety of things depending on the method being called. It might mutate, move, create a temporary, etc. In Dada, these things are all visible at the callsite- but they are unobtrusive.

This actually dates from Dada's "gradual programming" days - after all, if you don't have type annotations on the method, then you can't decide foo.bar() should take a shared or mutable borrow of foo. So we needed a notation where everything is visible at the call-site and explicit.

Postfix operators play more nicely with others

Dada tries hard to avoid prefix operators like &mut, since they don't compose well with . notation.

11 Feb 2026 12:29am GMT

09 Feb 2026

feedPlanet Mozilla

Dave Townsend: Can't you do this faster with AI?

I'm hearing this question asked a lot lately. Both within Mozilla and from others in the industry. You come up with a plan for implementing some feature, put your best estimate on how long it will take to implement, and then you get push back from folks several levels removed from the project along the lines of "Wouldn't this be faster if you used AI?", or "Can't Claude Code do most of this?".

09 Feb 2026 6:00pm GMT

Niko Matsakis: Hello, Dada!

Following on my Fun with Dada post, this post is going to start teaching Dada. I'm going to keep each post short - basically just what I can write while having my morning coffee.1

You have the right to write code

Here is a very first Dada program

println("Hello, Dada!")

I think all of you will be able to guess what it does. Still, there is something worth noting even in this simple program:

"You have the right to write code. If you don't write a main function explicitly, one will be provided for you." Early on I made the change to let users omit the main function and I was surprised by what a difference it made in how light the language felt. Easy change, easy win.

Convenient is the default

Here is another Dada program

let name = "Dada"
println("Hello, {name}!")

Unsurprisingly, this program does the same thing as the last one.

"Convenient is the default." Strings support interpolation (i.e., {name}) by default. In fact, that's not all they support, you can also break them across lines very conveniently. This program does the same thing as the others we've seen:

let name = "Dada"
println("
    Hello, {name}!
")

When you have a " immediately followed by a newline, the leading and trailing newline are stripped, along with the "whitespace prefix" from the subsequent lines. Internal newlines are kept, so something like this:

let name = "Dada"
println("
    Hello, {name}!
    
    How are you doing?
")

would print

Hello, Dada!

How are you doing?

Just one familiar String

Of course you could also annotate the type of the name variable explicitly:

let name: String = "Dada"
println("Hello, {name}!")

You will find that it is String. This in and of itself is not notable, unless you are accustomed to Rust, where the type would be &'static str. This is of course a perennial stumbling block for new Rust users, but more than that, I find it to be a big annoyance - I hate that I have to write "Foo".to_string() or format!("Foo") everywhere that I mix constant strings with strings that are constructed.

Similar to most modern languages, strings in Dada are immutable. So you can create them and copy them around:

let name: String = "Dada"
let greeting: String = "Hello, {name}"
let name2: String = name

Next up: mutation, permissions

OK, we really just scratched the surface here! This is just the "friendly veneer" of Dada, which looks and feels like a million other languages. Next time I'll start getting into the permission system and mutation, where things get a bit more interesting.


  1. My habit is to wake around 5am and spend the first hour of the day doing "fun side projects". But for the last N months I've actually been doing Rust stuff, like symposium.dev and preparing the 2026 Rust Project Goals. Both of these are super engaging, but all Rust and no play makes Niko a dull boy. Also a grouchy boy. ↩︎

09 Feb 2026 11:03am GMT

Niko Matsakis: Fun With Dada

Waaaaaay back in 2021, I started experimenting with a new programming language I call "Dada". I've been tinkering with it ever since and I just realized that (oh my gosh!) I've never written even a single blog post about it! I figured I should fix that. This post will introduce some of the basic concepts of Dada as it is now.

Before you get any ideas, Dada isn't fit for use. In fact the compiler doesn't even really work because I keep changing the language before I get it all the way working. Honestly, Dada is more of a "stress relief" valve for me than anything else1 - it's fun to tinker with a programming language where I don't have to worry about backwards compatibility, or RFCs, or anything else.

That said, Dada has been a very fertile source of ideas that I think could be applicable to Rust. And not just for language design: playing with the compiler is also what led to the new salsa design2, which is now used by both rust-analyzer and Astral's ty. So I really want to get those ideas out there!

I took a break, but I'm back baby!

I stopped hacking on Dada about a year ago3, but over the last few days I've started working on it again. And I realized, hey, this is a perfect time to start blogging! After all, I have to rediscover what I was doing anyway, and writing about things is always the best way to work out the details.

Dada started as a gradual programming experiment, but no longer

Dada has gone through many phases. Early on, the goal was to build a gradually typed programming language that I thought would be easier for people to learn.

The idea was that you could start writing without any types at all and just execute the program. There was an interactive playground that would let you step through and visualize the "borrow checker" state (what Dada calls permissions) as you go. My hope was that people would find that easier to learn than working with type checker checker.

I got this working and it was actually pretty cool. I gave a talk about it at the Programming Language Mentoring Workshop in 2022, though skimming that video it doesn't seem like I really demo'd the permission modeling. Too bad.

At the same time, I found myself unconvinced that the gradually typed approach made sense. What I wanted was that when you executed the program without type annotations, you would get errors at the point where you violated a borrow. And that meant that the program had to track a lot of extra data, kind of like miri does, and it was really only practical as a teaching tool. I still would like to explore that, but it also felt like it was adding a lot of complexity to the language design for something that would only be of interest very early in a developer's journey4.

Therefore, I decided to start over, this time, to just focus on the static type checking part of Dada.

Dada is like a streamlined Rust

Dada today is like Rust but streamlined. The goal is that Dada has the same basic "ownership-oriented" feel of Rust, but with a lot fewer choices and nitty-gritty details you have to deal with.5

Rust often has types that are semantically equivalent, but different in representation. Consider &Option<String> vs Option<&String>: both of them are equivalent in terms of what you can do with them, but of course Rust makes you carefully distinguish between them. In Dada, they are the same type. Dada also makes &Vec<String>, &Vec<&String>, &[String], &[&str], and many other variations all the same type too. And before you ask, it does it without heap allocating everything or using a garbage collector.

To put it pithily, Dada aims to be "Rust where you never have to call as_ref()".

Dada has a fancier borrow checker

Dada also has a fancier borrow checker, one which already demonstrates much of the borrow checker within, although it doesn't have view types. Dada's borrow checker supports internal borrows (e.g., you can make a struct that has fields that borrow from other fields) and it supports borrow checking without lifetimes. Much of this stuff can be brought to Rust, although I did tweak a few things in Dada that made some aspects easier.

Dada targets WebAssembly natively

Somewhere along the line in refocusing Dada, I decided to focus exclusively on building WebAssembly components. Initially I felt like targeting WebAssembly would be really convenient:

WebAssembly and on-demand compilation = compile-time reflection almost for free

But I came to realize that targeting WebAssembly has another advantage: it makes compile-time reflection almost trivial. The Dada compiler is structured in a purely on-demand fashion. This means we can compile one function all the way to WebAssembly bytecode and leave the rest of the crate untouched.

And once we have the WebAssembly bytecode, we can run that from inside the compiler! With wasmtime, we have a high quality JIT that runs very fast. The code is even sandboxed!

So we can have a function that we compile and run during execution and use to produce other code that will be used by other parts of the compilation step. In other words, we get something like miri or Zig's comptime for free, essentially. Woah.

Wish you could try it? Me too!

Man, writing this blog post made ME excited to play with Dada. Too bad it doesn't actually work. Ha! But I plan to keep plugging away on the compiler and get it to the point of a live demo as soon as I can. Hard to say exactly how long that will take.

In the meantime, to help me rediscover how things work, I'm going to try to write up a series of blog posts about the type system, borrow checker, and the compiler architecture, all of which I think are pretty interesting.


  1. Yes, I relax by designing new programming languages. Doesn't everyone? ↩︎

  2. Designing a new version of salsa so that I could write the Dada compiler in the way I wanted really was an epic yak shave, now that I think about it. ↩︎

  3. I lost motivation as I got interested in LLMs. To be frank, I felt like I had to learn enough about them to understand if designing a programming language was "fighting the last war". Having messed a bunch with LLMs, I definitely feel that they make the choice of programming language less relevant. But I also think they really benefit from higher-level abstractions, even more than humans do, and so I like to think that Dada could still be useful. Besides, it's fun. ↩︎

  4. And, with LLMs, that period of learning is shorter than ever. ↩︎

  5. Of course this also makes Dada less flexible. I doubt a project like Rust for Linux would work with Dada. ↩︎

09 Feb 2026 2:20am GMT

08 Feb 2026

feedPlanet Mozilla

Jonathan Almeida: Update jj bookmarks to the latest revision

Got this one from another colleague as well but it seems like most folks use some version of this daily that it might be good to have this built-in.

Before I can jj git push my current bookmark to my remote, I need to update where my (tracked) bookmark is, to the latest change:

@  ptuqwsty git@jonalmeida.com 2026-01-05 16:00:22 451384bf <-- move 'main' here.
TIL: Update remote bookmark to the latest revision
◆  xoqwkuvu git@jonalmeida.com 2025-12-30 19:50:51 main git_head() 9ad7ce11
TIL: Preserve image scale with ImageMagick
~

A quick one-liner jj tug does that for me:

@  ptuqwsty git@jonalmeida.com 2026-01-05 16:03:54 main* 6e7173b4
TIL: Update remote bookmark to the latest revision
◆  xoqwkuvu git@jonalmeida.com 2025-12-30 19:50:51 main@origin git_head() 9ad7ce11
TIL: Preserve image scale with ImageMagick
~

The alias is quite straight-forward:

[aliases]
# Update your bookmarks to your latest rev.
tug = ["bookmark", "move", "--from", "heads(::@ & bookmarks())", "--to", "@"]

08 Feb 2026 5:14am GMT

06 Feb 2026

feedPlanet Mozilla

Jonathan Almeida: Test a Firefox Android variant alongside your daily driver

In the Mozilla Android team, we want engineers to talk with Product and UX more and hash out ideas sooner. Prototype an idea, then discuss the feature's merits. For this, we built TryFox to make it easier for everyone to get the latest version of Firefox Nightly or install a "try" build with a link to the build on our CI servers.

The downside with using a Try build is that you sometimes have to uninstall your existing version of Nightly before you can install another and that means losing app data. Typically, if you were doing this on your daily driver, you don't want to do that. A quick work around is to add a temporary patch above your stack of commits which changes the App ID suffix (and optionally the application name) so that there is no conflict.

Here is an example diff from a patch that changed an animation, so having it install alongside what we shipped let you compare them easily:

diff --git a/mobile/android/fenix/app/build.gradle b/mobile/android/fenix/app/build.gradle
index 019fdb7ab4..772cc6cc3d 100644
--- a/mobile/android/fenix/app/build.gradle
+++ b/mobile/android/fenix/app/build.gradle
@@ -127,7 +127,7 @@
         debug {
             shrinkResources = false
             minifyEnabled = false
-            applicationIdSuffix ".fenix.debug"
+            applicationIdSuffix ".fenix.debug_animator"
             resValue "bool", "IS_DEBUG", "true"
             pseudoLocalesEnabled = true
         }
diff --git a/mobile/android/fenix/app/src/main/res/values/static_strings.xml b/mobile/android/fenix/app/src/main/res/values/static_strings.xml
index 4f6703eb35..1a57988477 100644
--- a/mobile/android/fenix/app/src/main/res/values/static_strings.xml
+++ b/mobile/android/fenix/app/src/main/res/values/static_strings.xml
@@ -4,7 +4,7 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <resources xmlns:moz="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools">
     <!-- Name of the application -->
-    <string name="app_name" translatable="false">Firefox Fenix</string>
+    <string name="app_name" translatable="false">Firefox Fenix (animator)</string>
     <string name="firefox" translatable="false">Firefox</string>

     <!-- Preference for developers -->

In the future, we can add mach try support to do this automatically for any push.

06 Feb 2026 12:00am GMT