📅

Rust Editions

Language Evolution with Backwards Compatibility

🚀 Edition Quick Reference

2015
Original
Core language features established
2018
Modern
Module system, async/await, NLL
2021
Polish
Disjoint captures, array iteration
Future
Evolution
~3 year cadence, RFC-driven

🎮 Edition Migration Explorer

Rust editions are a mechanism for evolving the Rust language while maintaining backwards compatibility. Each edition introduces new language features, changes default behaviors, and may modify syntax while ensuring that code written for older editions continues to work.

Editions allow the Rust language to grow and improve over time without breaking existing code. This approach enables rapid development and evolution while preserving the stability that systems programmers depend on.

📐 Edition Selection Grammar

Cargo.toml Edition Specification

[package] edition = " 2015 2018 2021 "

What Are Editions?

An edition is a collection of backwards-incompatible changes that are shipped together as a unit. These changes are opt-in per crate, meaning you can choose which edition to use for your project.

Key Edition Principles

  • Backwards Compatibility: Old code continues to work with new Rust versions
  • Opt-in Changes: Each crate chooses its edition explicitly
  • Interoperability: Crates using different editions can work together
  • Automatic Migration: Tools help upgrade code between editions

Edition Timeline

Rust 2015 (Original)

Released: May 15, 2015

The foundational edition establishing core language features including ownership, borrowing, traits, and pattern matching.

  • Ownership and borrowing system
  • Zero-cost abstractions
  • Pattern matching
  • Trait-based generics

Rust 2018

Released: December 6, 2018

Major ergonomic improvements including module system overhaul, async/await syntax, and non-lexical lifetimes.

  • Module system simplification
  • Async/await syntax
  • Raw identifiers
  • Non-lexical lifetimes

Rust 2021

Released: October 21, 2021

Polish and consistency improvements including disjoint captures, array iteration, and panic handling improvements.

  • Disjoint captures
  • Array IntoIterator
  • Panic macro consistency
  • Reserved syntax

✅ Edition Migration Examples

✅ Successful 2018 Migration

Rust 2015

extern crate serde;
extern crate tokio;

use ::std::collections::HashMap;

Rust 2018

use serde::{Deserialize, Serialize};
use tokio::runtime::Runtime;

use std::collections::HashMap;
❌ Edition Compatibility Issue
// This won't work in mixed edition scenarios
// Rust 2015 crate expecting specific module behavior
extern crate old_library;
use old_library::ModuleItem;  // May fail with 2018+ path resolution

🔍 Deep Dive: Module System Evolution

Rust 2015 Module System

The original module system required explicit extern crate declarations and absolute path resolution:

// Rust 2015
extern crate serde;
extern crate serde_derive;

use ::std::collections::HashMap;
use self::module::Item;
use super::parent_module::ParentItem;

Rust 2018 Improvements

Simplified module resolution with uniform paths:

// Rust 2018 - no extern crate needed
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::module::Item;
use super::parent_module::ParentItem;
Template use crate::{${module}::{${item}}} Uniform Path Resolution

⚡ Deep Dive: Async/Await Evolution

Pre-2018 Async Code

// Complex future combinators
fn fetch_data() -> impl Future {
    reqwest::get("https://api.example.com")
        .and_then(|response| response.text())
        .map(|text| format!("Received: {}", text))
}

Rust 2018 Async/Await

async fn fetch_data() -> Result {
    let response = reqwest::get("https://api.example.com").await?;
    let text = response.text().await?;
    Ok(format!("Received: {}", text))
}

🦀 Edition-Specific Quirks

🔗 Cross-Edition Dependencies

Dependencies can use different editions without issues, but some syntax differences might appear in examples:

// Your 2021 code
use dependency_2018::SomeType;  // Works fine
use dependency_2015::OtherType; // Also works fine

// But examples in docs might show different syntax

📏 Migration Tool Limitations

Automatic migration tools are helpful but not perfect - manual review is essential:

// cargo fix --edition might miss complex cases
use crate::complex::nested::Module;
// Check that paths resolve correctly after migration

🎯 Edition-Specific Features

Some features are only available in specific editions and cannot be backported:

// Rust 2021 only - disjoint captures
let data = SomeStruct { field1: 1, field2: 2 };
let closure = || println!("{}", data.field1); // Only captures field1
// data.field2 is still accessible in 2021

🤖 For AI Coding Agents: Edition Management

Machine-Readable Edition Specifications

This section provides structured data for AI agents to understand Rust edition management:

Edition Configuration Schema

{
  "edition_config": {
    "current_editions": ["2015", "2018", "2021"],
    "default_new_project": "2021",
    "compatibility_matrix": {
      "2015": {"compatible_with": ["2015", "2018", "2021"]},
      "2018": {"compatible_with": ["2015", "2018", "2021"]}, 
      "2021": {"compatible_with": ["2015", "2018", "2021"]}
    },
    "migration_tools": {
      "command": "cargo fix --edition",
      "preview": "cargo fix --edition --dry-run",
      "warnings": "cargo check"
    }
  },
  "feature_availability": {
    "async_await": {"min_edition": "2018"},
    "raw_identifiers": {"min_edition": "2018"},
    "disjoint_captures": {"min_edition": "2021"},
    "array_into_iterator": {"min_edition": "2021"}
  }
}
Template edition = "${edition_year}" Cargo.toml Configuration

Edition Selection Guidelines for AI

  • Always use the latest stable edition for new projects
  • Check feature compatibility when suggesting edition upgrades
  • Recommend migration tools for edition transitions
  • Warn about breaking changes between editions
  • Validate cross-edition dependency compatibility

📋 Migration Strategies

Automated Migration

# Check for issues
cargo check

# Auto-fix edition issues  
cargo fix --edition

# Preview changes
cargo fix --edition --dry-run

Use Rust's built-in migration tools for most common patterns.

Manual Review Points

  • Path resolutionCheck that module paths resolve correctly after migration, especially relative imports.
  • Macro usageSome macros may behave differently across editions.
  • DependenciesVerify that dependencies work with the new edition.
  • Feature flagsEdition-specific features may require conditional compilation.
← Notation Crates → ← Back to Reference