mozilla

Mozilla Nederland LogoDe Nederlandse
Mozilla-gemeenschap

Chris H-C: In Lighter News…

Mozilla planet - to, 28/04/2016 - 15:14

…Windows XP Firefox users may soon be able to properly render poop.

winxpPoo

Here at Mozilla, we take these things seriously.

:chutten


Categorieën: Mozilla-nl planet

Mozilla Looking For a New Home For Thunderbird - iProgrammer

Nieuws verzameld via Google - to, 28/04/2016 - 15:13

Mozilla Looking For a New Home For Thunderbird
iProgrammer
When, together with Firefox, it first emerged nearly 15 years ago as part of the Mozilla Application Suite it took the revolutionary approach of using HTML and JavaScript. Even after Thunderbird and Firefox were turned into separate products, they ...

Categorieën: Mozilla-nl planet

Firefox: Mozilla patches critical flaws that let attackers execute malicious code - ZDNet

Nieuws verzameld via Google - to, 28/04/2016 - 13:11

ZDNet

Firefox: Mozilla patches critical flaws that let attackers execute malicious code
ZDNet
The new version of Firefox includes fixes for 10 security issues found in earlier releases. Image: Mozilla. Mozilla has released Firefox 46 and patched several memory bugs that could let an attacker take control of a system. The new version of Firefox ...
Mozilla fixed a bug in Firefox that was discovered by British spy agency GCHQBusiness Insider UK
Mozilla slings Firefox patches at flaw found by GCHQ's infosec armThe Register
Mozilla Firefox 47.0 Is Now in Beta, Enables the VP9 Video Codec for Fast PCsSoftpedia News
myce.com -The World Beast (blog) -InfoQ.com
alle 19 nieuwsartikelen »
Categorieën: Mozilla-nl planet

Mozilla slings Firefox patches at flaw found by GCHQ's infosec arm - The Register

Nieuws verzameld via Google - to, 28/04/2016 - 08:27

The Register

Mozilla slings Firefox patches at flaw found by GCHQ's infosec arm
The Register
Mozilla has patched 10 vulnerabilities, some some rated either critical or high-severity, that permitted code execution in version 46 of its popular Firefox web browser. One of the patched high-severity flaws was burnt reported by the ...
Mozilla Firefox 47.0 Is Now in Beta, Enables the VP9 Video Codec for Fast PCsSoftpedia News
Mozilla patches 4 critical vulnerabilities with the release of Firefox 46myce.com
Google Chrome VS Mozilla FirefoxThe World Beast (blog)
InfoQ.com -Threatpost -VentureBeat
alle 17 nieuwsartikelen »
Categorieën: Mozilla-nl planet

Ian Bicking: A Product Journal: Data Up and Data Down

Mozilla planet - to, 28/04/2016 - 07:00

I’m blogging about the development of a new product in Mozilla, look here for my other posts in this series

We’re in the process of reviewing the KPI (Key Performance Indicators) for Firefox Hello (relatedly I joined the Firefox Hello team as engineering manager in October). Mozilla is trying (like everyone else) to make data-driven decisions. Basing decisions on data has some potential to remove or at least reveal bias. It provides a feedback mechanism that can provide continuity even as there are personnel changes. It provides some accountability over time. Data might also provide insight about product opportunities which we might otherwise miss.

Enter the KPI: for Hello (like most products) the key performance indicators are number of users, growth in users over time, user retention, and user sentiment (e.g., we use the Net Promoter Score). But like most projects those are not actually our success criteria: product engagement is necessary but not sufficient for organizational goals. Real goals might be revenue, social or political impact, or improvement in brand sentiment.

The value of KPI is often summarized as “letting us know how we’re doing”. I think the value KPI offers is more select:

  1. When you think a product is doing well, but it’s not, KPI is revealing.
  2. When you know a product isn’t doing well, KPI let’s you triage: is it hopeless? Do we need to make significant changes? Do we need to maintain our approach but try harder?
  3. When a product is doing well the KPI gives you a sense of the potential. You can also triage success: Should we invest heavily? Stay the path? Is there no potential to scale the success far enough?

I’m skeptical that KPI can provide the inverse of 1: when you think a product is doing poorly, can KPI reveal that it is doing well? Because there’s another set of criteria that defines “success”, KPI is necessary but not sufficient. It requires a carefully objective executive to revise their negative opinion about the potential of a project based on KPI, and they may have reasonably lost faith that a project’s KPI-defined success can translate into success given organizational goals.

The other theoretical value of KPI is that you could correlate KPI with changes to the product, testing whether each change improves your product’s core value. I’m sure people manage to do this, with both very fine grained measurements and fine grained deployments of changes. But it seems more likely to me that for most projects given a change in KPI you’ll simply have to say “yup” and come up with unverified theories about that change.

The metrics that actually support the development of the product are not “key”, they are “incidental”. These are metrics that find bugs in the product design, hint at unexplored opportunities, confirm the small wins. These are metrics that are actionable by the people making the product: how do people interact with the tool? What do they use it for? Where do they get lost? What paths lead to greater engagement?

What is KPI for?

I’m trying to think more consciously about the difference between managing up and managing down. A softer way of phrasing this is managing in and managing out – but in this case I think the power dynamics are worth highlighting.

KPI is data that goes up. It lets someone outside the project – and above the project – make choices: about investment, redirection, cancellation. KPI data doesn’t go down, it does little to help the people doing the work. Feeling joy or despair about your project based on KPI is not actionable for those people on the inside of a project.

Incentive or support

I would also distinguish two kinds of management here: one perspective on management is that the organization should set up the right incentives and consequences so that rewards are aligned with organizational goals. The right incentives might make people adapt their behavior to get alignment; how they adapt is undefined. The right incentives might also exclude those who aren’t in alignment, culling misalignment from the organization. Another perspective is that the organization should work to support people, that misalignment of purpose between a person and the organization is more likely a bug than a misalignment of intention. Are people black boxes that we can nudge via punishment and reward? Are there less mechanical ways to influence change?

Student performance measurement are another kind of KPI. It lets someone on the outside (of the classroom) know if things are going well or poorly for the students. It says little about why, and it doesn’t support improvement. School reform based on measurement presumes that teachers and schools are able to achieve the desired outcomes, but simply not willing. A risk of top-down reform: the people on the top use a perspective from the top. As an authority figure, how do I make decisions? The resulting reform is disempowering, supporting decisions from above, as opposed to using data to support the empowerment of those making the many day-to-day decisions that might effect a positive outcome.

Of course, having data available to inform decisions at all levels – from the executive to the implementor – would be great. But there’s a better criteria for data: it should support decision making processes. What are your most important decisions?

As an example from Mozilla, we have data about how much Firefox is used and its marketshare. How much should we pay attention to this data? We certainly don’t have the granularity to connect changes in this KPI to individual changes we make in the project. The only real way to do that is through controlled experiments (which we are trying). We aren’t really willing to triage the project; no one is asking “should we just give up on Firefox?” The only real choice we can make is: are we investing enough in Firefox, or should we invest more? That’s a question worth asking, but we need to keep our attention on the question and not the data. For instance, if we decide to increase investment in Firefox, the immediate questions are: what kind of investment? Over what timescale? Data can be helpful to answer those questions, but not just any data.

Exploratory data

Weeks after I wrote (but didn’t publish) this post I encountered Why Greatness Cannot Be Planned: The Myth of the Objective, a presentation by Kenneth Stanley:

“Setting an objective can block its own achievement. It can be an obstacle to creativity and innovation in general. Without protection of individual autonomy collaboration can become dangerously objective.”

The example he uses is manually searching a space of nonlinear image generation to find interesting images. The positive example is one where people explore, branching from novel examples until something recognizable emerges:

One negative example is one where an algorithm explores with a goal in mind:

Another negative example is selection by voting, instead of personal exploration; a product of convergent consensus instead of divergent treasure hunting:

If you decide what you are looking for, you are unlikely to find it. This generated image search space is deliberately nonlinear, so it’s difficult to understand how actions affect outcomes. Though artificial, I think the example is still valid: in a competitive environment, the thing you are searching for is hard to find, because if it was not hard then someone would have found it. And it’s probably hard because actions affect outcomes in unexpected ways.

You could describe this observation as another way of describing the pitfalls of hill climbing: getting stuck at local maximums. Maybe an easy fix is to add a little randomness, to bounce around, to see what lies past the hill you’ve found. But the hills themselves can be distractions: each hill supposes a measurement. The divergent search doesn’t just reveal novel solutions, but it can reveal a novel rubric for success.

This is also a similar observation to that in Innovator’s Dilemma: specifically that in these cases good management consistently and deliberately keeps a company away from novelty and onto the established track, and it does so by paying attention to the feedback that defines the company’s (current) success. The disruptive innovation, a term somewhat synonymous with the book, is an innovation that requires a change in metrics, and that a large portion of the innovation is finding the metric (and so finding the market), not implementing the maximizing solution.

But I digress from the topic of data. If we’re going to be data driven to entirely new directions, we may need data that doesn’t answer a question, doesn’t support a decision, but just tells us about things we don’t know. To support exploration, not based on a hypothesis which we confirm or reject based on the data, because we are still trying to discover our hypothesis. We use the data to look for the hidden variable, the unsolved need, the desire that has not been articulated.

I think we look for this kind of data more often than we would admit. Why else would we want complex visualizations? The visualizations are our attempt at finding a pattern we don’t expect to find.

In Conclusion

I’m lousy at conclusions. All those words up there are like data, and I’m curious what they mean, but I haven’t figured it out yet.

Categorieën: Mozilla-nl planet

Geoff Lankow: Does Firefox update despite being set to "never check for updates"? This might be why.

Mozilla planet - to, 28/04/2016 - 04:45

If, like me, you have set Firefox to "never check for updates" for some reason, and yet it does sometimes anyway, this could be your problem: the chrome debugger.

The chrome debugger uses a separate profile, with the preferences copied from your normal profile. But, if your prefs (such as app.update.enabled) have changed, they remain in the debugger profile as they were when you first opened the debugger.

App update can be started by any profile using the app, so the debugger profile sees the pref as it once was, and goes looking for updates.

Solution? Copy the app update prefs from the main profile to the debugger profile (mine was at ~/.cache/mozilla/firefox/31392shv.default/chrome_debugger_profile), or just destroy the debugger profile and have a new one created next time you use it.

Just thought you might like to know.

Categorieën: Mozilla-nl planet

Air Mozilla: Privacy Lab - April 2016 - Encryption vs. the FBI

Mozilla planet - to, 28/04/2016 - 03:00

Privacy Lab - April 2016 - Encryption vs. the FBI Riana Pfefferkorn, Cryptography Fellow at the Stanford Center for Internet and Society, will talk about the FBI's dispute with Apple over encrypted iPhones.

Categorieën: Mozilla-nl planet

Air Mozilla: Privacy Lab - April 2016 - Encryption vs. the FBI

Mozilla planet - to, 28/04/2016 - 03:00

Privacy Lab - April 2016 - Encryption vs. the FBI Riana Pfefferkorn, Cryptography Fellow at the Stanford Center for Internet and Society, will talk about the FBI's dispute with Apple over encrypted iPhones.

Categorieën: Mozilla-nl planet

Mozilla Firefox 47.0 Is Now in Beta, Enables the VP9 Video Codec for Fast PCs - Softpedia News

Nieuws verzameld via Google - to, 28/04/2016 - 02:25

Softpedia News

Mozilla Firefox 47.0 Is Now in Beta, Enables the VP9 Video Codec for Fast PCs
Softpedia News
Now that everyone is enjoying the recently released Firefox 46.0 web browser, it is time for the Mozilla devs to start working on the next major version, Mozilla Firefox 47.0. A first Beta build of the upcoming Mozilla Firefox 47.0 web browser has been ...
Mozilla patches 4 critical vulnerabilities with the release of Firefox 46myce.com
Google Chrome VS Mozilla FirefoxThe World Beast (blog)
Firefox 46 Tackles Security Issues, Improves PerformanceInfoQ.com
Threatpost -VentureBeat -Android Headlines - Android News
alle 16 nieuwsartikelen »
Categorieën: Mozilla-nl planet

Mozilla Offers WebAssembly New Parallelism Boost - HTML Goodies

Nieuws verzameld via Google - to, 28/04/2016 - 01:05

Mozilla Offers WebAssembly New Parallelism Boost
HTML Goodies
Mozilla continues to improve compilation in both the WebAssembly portable bytecode format and asm.js JavaScript subset by leveraging parallelization in their Firefox browser. By using parallelism, an engineer at Mozilla worked on reducing startup times ...

Google Nieuws
Categorieën: Mozilla-nl planet

Mike Hommey: Announcing git-cinnabar 0.3.2

Mozilla planet - to, 28/04/2016 - 00:42

Git-cinnabar is a git remote helper to interact with mercurial repositories. It allows to clone, pull and push from/to mercurial remote repositories, using git.

Get it on github.

These release notes are also available on the git-cinnabar wiki.

This is mostly a bug and regression-fixing release.

What’s new since 0.3.1?
  • Fixed a performance regression when cloning big repositories on OSX.
  • git configuration items with line breaks are now supported.
  • Fixed a number of issues with corner cases in mercurial data (such as, but not limited to nodes with no first parent, malformed .hgtags, etc.)
  • Fixed a stack overflow, a buffer overflow and a use-after free in cinnabar-helper.
  • Better work with git worktrees, or when called from subdirectories.
  • Updated git to 2.7.4 for cinnabar-helper.
  • Properly remove all refs meant to be removed when using git version lower than 2.1.
Categorieën: Mozilla-nl planet

Mozilla Firefox 46.0 Lands in All Supported Ubuntu OSes with GTK3 Integration - Softpedia News

Nieuws verzameld via Google - to, 28/04/2016 - 00:23

Softpedia News

Mozilla Firefox 46.0 Lands in All Supported Ubuntu OSes with GTK3 Integration
Softpedia News
We reported the other day that Mozilla released version 46.0 of its Firefox web browser, which happens to be a very important milestone for GNU/Linux users, as it finally brings the long-anticipated GTK3 integration. Mozilla Firefox 46.0 is a pretty ...
Mozilla patches 4 critical vulnerabilities with the release of Firefox 46myce.com
Google Chrome VS Mozilla FirefoxThe World Beast (blog)
Firefox 46 Tackles Security Issues, Improves PerformanceInfoQ.com
Threatpost -VentureBeat -Android Headlines - Android News
alle 15 nieuwsartikelen »
Categorieën: Mozilla-nl planet

Mozilla Addons Blog: Join the Featured Add-ons Community Board

Mozilla planet - to, 28/04/2016 - 00:14

Are you a big fan of add-ons? Think you can help help identify the best content to spotlight on AMO? Then let’s talk!

All the add-ons featured on addons.mozilla.org (AMO) are selected by a board of community members. Each board consists of 5-8 members who nominate and select featured add-ons once a month for six months. Featured add-ons help users discover what’s new and useful, and downloads increase dramatically in the months they’re featured, so your participation really makes an impact.

And now the time has come to assemble a new board for the months July – December.

Anyone from the add-ons community is welcome to apply: power users, theme designers, developers, and evangelists. Priority will be given to applicants who have not served on the board before, followed by those from previous boards, and finally from the outgoing board. This page provides more information on the duties of a board member. To be considered, please email us at amo-featured@mozilla.org with your name, and tell us how you’re involved with AMO. The deadline is Friday, May 10, 2016 at 23:59 PDT. The new board will be announced about a week after.

We look forward to hearing from you!

Categorieën: Mozilla-nl planet

What’s New in Firefox Beta

Mozilla Futurereleases - wo, 27/04/2016 - 22:55

Today’s beta release of Firefox features a tool to view the open tabs that are synced across your desktop and mobile instances of Firefox.

Updates to Firefox for Android focus on a set of design changes that will make browsing safer and simpler for our users.

More information:

Categorieën: Mozilla-nl planet

Michael Kaply: Broken Add-ons in Firefox 46

Mozilla planet - wo, 27/04/2016 - 19:59

A lot of add-ons are being broken by a subtle change in Firefox 46, in particular the removal of legacy array/generator comprehension.

Most of these add-ons (including mine) did not use array comprehension intentionally, but they copied some code from this page on developer.mozilla.org for doing an md5 hash of a string. It looked like this:

var s = [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");

You should search through your source code for toHexString and make sure you aren’t using this. MDN was updated in January to fix this. Here’s what the new code looks like:

var s = Array.from(hash, (c, i) => toHexString(hash.charCodeAt(i))).join("");

The new code will only work in Firefox 32 and beyond. If for some reason you need an older version, you can go through the history of the page to find the array based version.

Using this old code will cause a syntax error, so it will cause much more breakage than you realize. You’ll want to get it fixed sooner than later because Firefox 46 started rolling out yesterday.

As a side note, Giorgio Maone caught this in January, but unfortunately all that was updated was the MDN page.

Categorieën: Mozilla-nl planet

Air Mozilla: The Joy of Coding - Episode 55

Mozilla planet - wo, 27/04/2016 - 19:00

The Joy of Coding - Episode 55 mconley livehacks on real Firefox bugs while thinking aloud.

Categorieën: Mozilla-nl planet

Air Mozilla: April 2016 Speaker Series: When Change is the Only Constant, Org Structure Doesn't Matter - Kirsten Wolberg

Mozilla planet - wo, 27/04/2016 - 19:00

 When Change is the Only Constant, Org Structure Doesn't Matter - Kirsten Wolberg Regardless of whether an organization is decentralized or command & control, large-scale changes are never simple nor straightforward. There's no silver bullets. And yet, when...

Categorieën: Mozilla-nl planet

Rail Aliiev: Firefox 46.0 and SHA512SUMS

Mozilla planet - wo, 27/04/2016 - 18:47

In my previous post I introduced the new release process we have been adopting in the 46.0 release cycle.

Release build promotion has been in production since Firefox 46.0 Beta 1. We have discovered some minor issues; some of them are already fixed, some still waiting.

One of the visible bugs is Bug 1260892. We generate a big SHA512SUMS file, which should contain all important checksums. With numerous changes to the process the file doesn't represent all required files anymore. Some files are missing, some have different names.

We are working on fixing the bug, but you can use the following work around to verify the files.

For example, if you want to verify http://ftp.mozilla.org/pub/firefox/releases/46.0/win64/ach/Firefox%20Setup%2046.0.exe, you need use the following 2 files:

http://ftp.mozilla.org/pub/firefox/candidates/46.0-candidates/build5/win64/ach/firefox-46.0.checksums

http://ftp.mozilla.org/pub/firefox/candidates/46.0-candidates/build5/win64/ach/firefox-46.0.checksums.asc

Example commands:

# download all required files $ wget -q http://ftp.mozilla.org/pub/firefox/releases/46.0/win64/ach/Firefox%20Setup%2046.0.exe $ wget -q http://ftp.mozilla.org/pub/firefox/candidates/46.0-candidates/build5/win64/ach/firefox-46.0.checksums $ wget -q http://ftp.mozilla.org/pub/firefox/candidates/46.0-candidates/build5/win64/ach/firefox-46.0.checksums.asc $ wget -q http://ftp.mozilla.org/pub/firefox/releases/46.0/KEY # Import Mozilla Releng key into a temporary GPG directory $ mkdir .tmp-gpg-home && chmod 700 .tmp-gpg-home $ gpg --homedir .tmp-gpg-home --import KEY # verify the signature of the checksums file $ gpg --homedir .tmp-gpg-home --verify firefox-46.0.checksums.asc && echo "OK" || echo "Not OK" # calculate the SHA512 checksum of the file $ sha512sum "Firefox Setup 46.0.exe" c2ed64298ac2140d8dbdaed28cabc90b38dd9444e9c0d6dd335a2a32cf043a35314945536a5c75124a88bf418a4e2ba77256be223425380e7fcc45a97da8f479 Firefox Setup 46.0.exe # lookup for the checksum in the checksums file $ grep c2ed64298ac2140d8dbdaed28cabc90b38dd9444e9c0d6dd335a2a32cf043a35314945536a5c75124a88bf418a4e2ba77256be223425380e7fcc45a97da8f479 firefox-46.0.checksums c2ed64298ac2140d8dbdaed28cabc90b38dd9444e9c0d6dd335a2a32cf043a35314945536a5c75124a88bf418a4e2ba77256be223425380e7fcc45a97da8f479 sha512 46275456 install/sea/firefox-46.0.ach.win64.installer.exe

This is just a temporary work around and the bug will be fixed ASAP.

Categorieën: Mozilla-nl planet

Air Mozilla: SuMo Community Call 27th April 2016

Mozilla planet - wo, 27/04/2016 - 18:00

SuMo Community Call 27th April 2016 This is the sumo weekly call We meet as a community every Wednesday 17:00 - 17:30 UTC The etherpad is here: https://public.etherpad-mozilla.org/p/sumo-2016-04-27

Categorieën: Mozilla-nl planet

Niko Matsakis: Non-lexical lifetimes: introduction

Mozilla planet - wo, 27/04/2016 - 16:52

Over the last few weeks, I’ve been devoting my free time to fleshing out the theory behind non-lexical lifetimes (NLL). I think I’ve arrived at a pretty good point and I plan to write various posts talking about it. Before getting into the details, though, I wanted to start out with a post that lays out roughly how today’s lexical lifetimes work and gives several examples of problem cases that we would like to solve.

The basic idea of the borrow checker is that values may not be mutated or moved while they are borrowed. But how do we know whether a value is borrowed? The idea is quite simple: whenever you create a borrow, the compiler assigns the resulting reference a lifetime. This lifetime corresponds to the span of the code where the reference may be used. The compiler will infer this lifetime to be the smallest lifetime that it can that still encompasses all the uses of the reference.

Note that Rust uses the term lifetime in a very particular way. In everyday speech, the word lifetime can be used in two distinct – but similar – ways:

  1. The lifetime of a reference, corresponding to the span of time in which that reference is used.
  2. The lifetime of a value, corresponding to the span of time before that value gets freed (or, put another way, before the destructor for the value runs).

This second span of time, which describes how long a value is valid, is of course very important. We refer to that span of time as the value’s scope. Naturally, lifetimes and scopes are linked to one another. Specifically, if you make a reference to a value, the lifetime of that reference cannot outlive the scope of that value, Otherwise your reference would be pointing into free memory.

To better see the distinction between lifetime and scope, let’s consider a simple example. In this example, the vector data is borrowed (mutably) and the resulting reference is passed to a function capitalize. Since capitalize does not return the reference back, the lifetime of this borrow will be confined to just that call. The scope of data, in contrast, is much larger, and corresponds to a suffix of the fn body, stretching from the let until the end of the enclosing scope.

1 2 3 4 5 6 7 8 9 10 11 12 fn foo() { let mut data = vec!['a', 'b', 'c']; // --+ 'scope capitalize(&mut data[..]); // | // ^~~~~~~~~~~~~~~~~~~~~~~~~ 'lifetime // | data.push('d'); // | data.push('e'); // | data.push('f'); // | } // <---------------------------------------+ fn capitalize(data: &mut [char]) { // do something }

This example also demonstrates something else. Lifetimes in Rust today are quite a bit more flexible than scopes (if not as flexible as we might like, hence this RFC):

  • A scope generally corresponds to some block (or, more specifically, a suffix of a block that stretches from the let until the end of the enclosing block) [1].
  • A lifetime, in contrast, can also span an individual expression, as this example demonstrates. The lifetime of the borrow in the example is confined to just the call to capitalize, and doesn’t extend into the rest of the block. This is why the calls to data.push that come below are legal.

So long as a reference is only used within one statement, today’s lifetimes are typically adequate. Problems arise however when you have a reference that spans multiple statements. In that case, the compiler requires the lifetime to be the innermost expression (which is often a block) that encloses both statements, and that is typically much bigger than is really necessary or desired. Let’s look at some example problem cases. Later on, we’ll see how non-lexical lifetimes fixes these cases.

Problem case #1: references assigned into a variable

One common problem case is when a reference is assigned into a variable. Consider this trivial variation of the previous example, where the &mut data[..] slice is not passed directly to capitalize, but is instead stored into a local variable:

1 2 3 4 5 6 7 8 fn bar() { let mut data = vec!['a', 'b', 'c']; let slice = &mut data[..]; // <-+ 'lifetime capitalize(slice); // | data.push('d'); // ERROR! // | data.push('e'); // ERROR! // | data.push('f'); // ERROR! // | } // <------------------------------+

The way that the compiler currently works, assigning a reference into a variable means that its lifetime must be as large as the entire scope of that variable. In this case, that means the lifetime is now extended all the way until the end of the block. This in turn means that the calls to data.push are now in error, because they occur during the lifetime of slice. It’s logical, but it’s annoying.

In this particular case, you could resolve the problem by putting slice into its own block:

1 2 3 4 5 6 7 8 9 10 fn bar() { let mut data = vec!['a', 'b', 'c']; { let slice = &mut data[..]; // <-+ 'lifetime capitalize(slice); // | } // <------------------------------+ data.push('d'); // OK data.push('e'); // OK data.push('f'); // OK }

Since we introduced a new block, the scope of slice is now smaller, and hence the resulting lifetime is smaller. Of course, introducing a block like this is kind of artificial and also not an entirely obvious solution.

Problem case #2: conditional control flow

Another common problem case is when references are used in only match arm. This most commonly arises around maps. Consider this function, which, given some key, processes the value found in map[key] if it exists, or else inserts a default value:

1 2 3 4 5 6 7 8 9 10 fn process_or_default<K,V:Default>(map: &mut HashMap<K,V>, key: K) { match map.get_mut(&key) { // -------------+ 'lifetime Some(value) => process(value), // | None => { // | map.insert(key, V::default()); // | // ^~~~~~ ERROR. // | } // | } // <------------------------------------+ }

This code will not compile today. The reason is that the map is borrowed as part of the call to get_mut, and that borrow must encompass not only the call to get_mut, but also the Some branch of the match. The innermost expression that encloses both of these expressions is the match itself (as depicted above), and hence the borrow is considered to extend until the end of the match. Unfortunately, the match encloses not only the Some branch, but also the None branch, and hence when we go to insert into the map in the None branch, we get an error that the map is still borrowed.

This particular example is relatively easy to workaround. One can (frequently) move the code for None out from the match like so:

1 2 3 4 5 6 7 8 9 10 11 12 fn process_or_default1<K,V:Default>(map: &mut HashMap<K,V>, key: K) { match map.get_mut(&key) { // -------------+ 'lifetime Some(value) => { // | process(value); // | return; // | } // | None => { // | } // | } // <------------------------------------+ map.insert(key, V::default()); }

When the code is adjusted this way, the call to map.insert is not part of the match, and hence it is not part of the borrow. While this works, it is of course unfortunate to require these sorts of manipulations, just as it was when we introduced an artificial block in the previous example.

Problem case #3: conditional control flow across functions

While we were able to work around problem case #2 in a relatively simple, if irritating, fashion. there are other variations of conditional control flow that cannot be so easily resolved. This is particularly true when you are returning a reference out of a function. Consider the following function, which returns the value for a key if it exists, and inserts a new value otherwise (for the purposes of this section, assume that the entry API for maps does not exist):

1 2 3 4 5 6 7 8 9 10 11 12 fn get_default<'m,K,V:Default>(map: &'m mut HashMap<K,V>, key: K) -> &'m mut V { match map.get_mut(&key) { // -------------+ 'm Some(value) => value, // | None => { // | map.insert(key, V::default()); // | // ^~~~~~ ERROR // | map.get_mut(&key).unwrap() // | } // | } // | } // v

At first glance, this code appears quite similar the code we saw before. And indeed, just as before, it will not compile. But in fact the lifetimes at play are quite different. The reason is that, in the Some branch, the value is being returned out to the caller. Since value is a reference into the map, this implies that the map will remain borrowed until some point in the caller (the point 'm, to be exact). To get a better intuition for what this lifetime parameter 'm represents, consider some hypothetical caller of get_default: the lifetime 'm then represents the span of code in which that caller will use the resulting reference:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fn caller() { let mut map = HashMap::new(); ... { let v = get_default(&mut map, key); // -+ 'm // +-- get_default() -----------+ // | // | match map.get_mut(&key) { | // | // | Some(value) => value, | // | // | None => { | // | // | .. | // | // | } | // | // +----------------------------+ // | process(v); // | } // <--------------------------------------+ ... }

If we attempt the same workaround for this case that we tried in the previous example, we will find that it does not work:

1 2 3 4 5 6 7 8 9 10 11 fn get_default1<'m,K,V:Default>(map: &'m mut HashMap<K,V>, key: K) -> &'m mut V { match map.get_mut(&key) { // -------------+ 'm Some(value) => return value, // | None => { } // | } // | map.insert(key, V::default()); // | // ^~~~~~ ERROR (still) | map.get_mut(&key).unwrap() // | } // v

Whereas before the lifetime of value was confined to the match, this new lifetime extends out into the caller, and therefore the borrow does not end just because we exited the match. Hence it is still in scope when we attempt to call insert after the match.

The workaround for this problem is a bit more involved. It relies on the fact that the borrow checker uses the precise control-flow of the function to determine what borrows are in scope.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 fn get_default2<'m,K,V:Default>(map: &'m mut HashMap<K,V>, key: K) -> &'m mut V { if map.contains(&key) { // ^~~~~~~~~~~~~~~~~~ 'n return match map.get_mut(&key) { // + 'm Some(value) => value, // | None => unreachable!() // | }; // v } // At this point, `map.get_mut` was never // called! (As opposed to having been called, // but its result no longer being in use.) map.insert(key, V::default()); // OK now. map.get_mut(&key).unwrap() }

What has changed here is that we moved the call to map.get_mut inside of an if, and we have set things up so that the if body unconditionally returns. What this means is that a borrow begins at the point of get_mut, and that borrow lasts until the point 'm in the caller, but the borrow checker can see that this borrow will not have even started outside of the if. So it does not consider the borrow in scope at the point where we call map.insert.

This workaround is more troublesome than the others, because the resulting code is actually less efficient at runtime, since it must do multiple lookups.

It’s worth noting that Rust’s hashmaps include an entry API that one could use to implement this function today. The resulting code is both nicer to read and more efficient even than the original version, since it avoids extra lookups on the not present path as well:

1 2 3 4 5 6 fn get_default3<'m,K,V:Default>(map: &'m mut HashMap<K,V>, key: K) -> &'m mut V { map.entry(key) .or_insert_with(|| V::default()) }

Regardless, the problem exists for other data structures besides HashMap, so it would be nice if the original code passed the borrow checker, even if in practice using the entry API would be preferable. (Interestingly, the limitation of the borrow checker here was one of the motivations for developing the entry API in the first place!)

Conclusion

This post looked at various examples of Rust code that do not compile today, and showed how they can be fixed using today’s system. While it’s good that workarounds exist, it’d be better if the code just compiled as is. In an upcoming post, I will outline my plan for how to modify the compiler to achieve just that.

Endnotes

1. Scopes always correspond to blocks with one exception: the scope of a temporary value is sometimes the enclosing statement.

Categorieën: Mozilla-nl planet

Pages