Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dada RFCs

This book contains RFCs (Request for Comments) for the Dada programming language. RFCs are proposals for language changes that document design decisions, rationale, and implementation plans.

RFC Process

Each RFC goes through several stages:

  • Active: Under discussion and refinement
  • Accepted: Approved for implementation
  • Implemented: Completed with working code
  • Rejected: Not proceeding (kept for historical reference)
  • Withdrawn: Author chose not to proceed

Contributing

See the RFC workflow documentation for details on creating and maintaining RFCs.

All RFCs

This page provides an overview of all RFCs (Request for Comments) in the Dada language development process.

Active RFCs

RFCs currently under discussion and development.

(None yet)

Accepted RFCs

RFCs that have been accepted but not yet implemented.

(None yet)

Implemented RFCs

RFCs that have been fully implemented and are part of the language.

(None yet)

Draft RFCs

RFCs that are still being written or refined.

0
RFC-0000: Template RFC Status

Brief one-paragraph explanation of the feature being proposed.

1
RFC-0001: String Literals RFC Status

Define string literal syntax for Dada that makes string interpolation the default behavior, learning from the evolution of string handling in languages like Rust and the success of template literals in JavaScript/TypeScript. String literals in Dada have type my String.

2
RFC-0002: RFC Process and Specification Workflow RFC Status

Establish a comprehensive RFC and specification workflow that enables incremental development of language features while maintaining clear separation between design documentation (RFCs) and normative specification text.

RFC-0000: Template

Note: To create a new RFC, run cargo xtask rfc new feature-name


status: draft tracking-issue: #123 # optional implemented-version: 0.1.0 # optional, for implemented RFCs

Summary

Brief one-paragraph explanation of the feature being proposed.

Design tenets

  1. Principle one - Description of core design principle
  2. Principle two - Another guiding principle for this feature
  3. Principle three - Final key design constraint or goal

Motivation

Why are we doing this? What use cases does it support? What problems does this solve for Dada users?

Guide-level explanation

Explain the proposal as if teaching it to another Dada programmer. Use examples to show how the feature works and how users should think about it.

# Example code showing the feature
example := "code here"

Reference-level explanation

Technical details of the design. Cover syntax, type system interactions, implementation considerations, and corner cases.

Frequently asked questions

What should I put in this section?

Give additional rationale for design decisions; explain why you preferred this alternatives to others. Include any questions raised in RFC threads or other discussion areas. The goal is to capture the design space.

Future possibilities

What this proposal enables for future development. Extensions, follow-up RFCs, or natural next steps.

Implementation notes

Status: Not started

Implementation plan

  • Task one
  • Task two
  • Task three

Pull requests

  • #NNN - Description of PR

Testing

  • Unit tests added
  • Integration tests added
  • Documentation updated

Notes

Track implementation decisions, deviations from the RFC, or lessons learned.

Specification draft

Draft specification text that will be integrated into the main specification when this RFC is implemented.

Section name

r[category.feature.rule-name] Specification paragraph content. Each paragraph should specify one independent, testable rule.

r[category.feature.another-rule] Another specification paragraph with its own semantic identifier.

Notes

  • This is draft text that may change during implementation
  • Final spec integration may reorganize this content
  • Use semantic IDs that will remain stable as the spec evolves

RFC-0001: String Literals


status: active

Summary

Define string literal syntax for Dada that makes string interpolation the default behavior, learning from the evolution of string handling in languages like Rust and the success of template literals in JavaScript/TypeScript. String literals in Dada have type my String.

Design tenets

  1. Do what I mean - Default behavior matches common intent: interpolation enabled, indentation automatically handled
  2. Rust-like syntax - Use familiar {} for interpolation, maintaining consistency with Rust’s formatting approach
  3. Simple escape hatch - When you need exact control, a single character prefix ("\) disables all magic

Motivation

String manipulation is one of the most common operations in programming. Languages have evolved different approaches:

Rust’s Evolution: Rust started with C-like static string literals ("hello"), requiring explicit formatting macros for variable interpolation:

#![allow(unused)]
fn main() {
let name = "Alice";
let message = format!("Hello, {}!", name);
}

Over time, Rust has added increasingly convenient forms:

  • println! and other macros for common cases
  • Recent discussions about f-strings or similar interpolation syntax
  • Recognition that the default (static strings) doesn’t match the common case

JavaScript/TypeScript Success: Template literals have become the preferred string syntax:

const name = "Alice";
const message = `Hello, ${name}!`;

This success demonstrates that making interpolation easy and default improves developer experience.

Dada’s Opportunity: As a new language, Dada can learn from this evolution and make the convenient choice the default choice. Rather than requiring special syntax or function calls for the common case of building strings with dynamic content, Dada should support interpolation in the standard string literal syntax.

Guide-level explanation

In Dada, string literals enclosed in double quotes support embedding expressions using curly braces:

name := "Alice"
age := 30
message := "Hello, {name}! You are {age} years old."

This is the default and only form of string literal in Dada. Any valid expression can be placed inside {}:

# Field access
greeting := "Welcome, {user.name}!"

# Method calls  
result := "The sum is {calculate_sum(a, b)}"

# Complex expressions
status := "Processing {completed}/{total} items ({(completed * 100 / total).round()}%)"

For cases where literal braces are needed, they can be escaped with a backslash:

json := "\{ \"name\": \"{name}\" \}"  # Produces: { "name": "Alice" }

Triple-quoted strings

String literals can also be delimited by triple quotes (""") to allow embedded quotes without escaping:

# No need to escape quotes
message := """She said "Hello, {name}!" with enthusiasm."""
assert message == "She said \"Hello, Alice!\" with enthusiasm."

# Triple quotes behave identically to single quotes
simple := """foo bar"""
assert simple == "foo bar"

# Interpolation works the same way
dialogue := """
    "{character1}" asked, "How are you?"
    "{character2}" replied, "I'm doing great!"
"""

Triple-quoted strings follow all the same rules as regular string literals, including interpolation and multiline dedenting behavior.

Multiline String Literals

Dada supports multiline string literals with automatic indentation handling. When a string literal:

  1. Begins with a newline immediately after the opening quote
  2. Has each subsequent line either empty or with a consistent whitespace prefix

Then the string literal’s value will be:

  • The leading and trailing whitespace trimmed
  • The common whitespace prefix removed from the start of each line
# Automatic indentation handling
name := "Alice"
message := "
    Hello, {name}!
    Welcome to Dada.
    This is a multiline string.
"
assert message == "Hello, Alice!\nWelcome to Dada.\nThis is a multiline string."

# Nested indentation preserved
user_name := "Bob"
login_time := "10:30 AM"
post_count := 5
report := "
    Status Report
    =============
    User: {user_name}
    
    Recent activities:
      - Logged in at {login_time}
      - Updated profile
      - Posted {post_count} messages
"
assert report == "Status Report\n=============\nUser: Bob\n\nRecent activities:\n  - Logged in at 10:30 AM\n  - Updated profile\n  - Posted 5 messages"

To disable automatic indentation handling, begin the string with "\ followed by a newline. This preserves the string exactly as written, including the leading newline and all indentation:

# Preserve exact formatting (note: leading newline is preserved)
name := "Alice"
raw_message := "\
    Hello, {name}!
    Welcome to Dada.
    This is preserved exactly as written.
"
assert raw_message == "\n    Hello, Alice!\n    Welcome to Dada.\n    This is preserved exactly as written.\n"

Leading and trailing whitespace is stripped; only internal content is preserved. Escape sequences like \n are part of the content, not whitespace, so they survive stripping:

# Without trailing newline (default)
without_newline := "
    Line 1
    Line 2
    Line 3
"
assert without_newline == "Line 1\nLine 2\nLine 3"

# With trailing newline via escape sequence
with_newline := "
    Line 1
    Line 2
    Line 3\n
"
assert with_newline == "Line 1\nLine 2\nLine 3\n"

Interpolation works seamlessly with multiline strings:

host := "localhost"
port := 8080
db_url := "postgres://localhost/mydb"
pool_size := 10
config := "
    [server]
    host = {host}
    port = {port}
    
    [database]
    url = {db_url}
    pool_size = {pool_size}
"
assert config == "[server]\nhost = localhost\nport = 8080\n\n[database]\nurl = postgres://localhost/mydb\npool_size = 10"

Reference-level explanation

Syntax

String literals are delimited by either:

  • Double quotes (")
  • Triple quotes (""")

Both forms may contain interpolation expressions within curly braces ({expression}). Triple-quoted strings allow embedded double quotes without escaping.

Lexical Analysis

String literals with interpolation are recognized by the lexer, which understands the structure of interpolated expressions. This means that:

  • Characters inside {} are treated as part of the interpolated expression, not the string literal
  • Quotes inside interpolated expressions do not terminate the string literal

For example:

greeting := "Hello{", world"}"  # Results in: Hello, world
message := "Say {"hello"}"      # Results in: Say hello

The lexer tracks brace nesting to correctly identify where interpolated expressions end:

nested := "Result: {if true { "yes" } else { "no" }}"  # Results in: Result: yes

Expression Evaluation

  • Expressions inside {} are evaluated at runtime in the current scope
  • Results are converted to strings following Dada’s standard conversion rules
  • Evaluation proceeds left-to-right
  • The permission system applies normally to interpolated expressions

Escape Sequences

  • \{ produces a literal {
  • \} produces a literal }
  • \" produces a literal quote (not needed in triple-quoted strings)
  • \n, \r, \t, \\ follow standard conventions
  • Triple-quoted strings cannot contain three consecutive quote characters

Type Requirements

  • String literals have type my String
  • Interpolated expressions must produce values that can be converted to strings
  • This is checked at compile time
  • The exact conversion mechanism depends on Dada’s trait/interface system (future RFC)

Frequently asked questions

Q: Why make interpolation the default instead of having separate syntax like backticks? A: Experience from Rust and other languages shows that building strings with dynamic content is the common case. Making the common case require special syntax (format macros, template literals, etc.) creates friction. Dada chooses to optimize for the common case.

Q: What about purely static strings with no interpolation? A: The compiler can easily detect string literals that contain no interpolation expressions and optimize them accordingly.

Q: Why {} instead of ${} like JavaScript? A: The simpler {} syntax is more consistent with Rust’s format strings and requires less visual noise. Since interpolation is the default, the syntax should be as lightweight as possible.

Q: Why \{ instead of {{ to escape braces? A: Two reasons. First, Dada string literals already use backslash escapes (\n, \t, \\, \"), so \{ is consistent with the existing escape system — it would be odd to have two different escaping mechanisms in the same literal. Second, keeping {{ free means it works as an interpolated block expression, which is useful for embedding multiline code:

result := "the value is {{
    x := foo()
    bar(x)
}}"

Languages like Rust and Python use {{ for brace escaping because their interpolation lives in format macros or f-strings where backslash escapes aren’t available. Dada strings have backslash escapes natively, so there’s no reason not to use them.

Future possibilities

  • Raw string literals - A syntax to disable escape sequence processing (e.g., r"C:\path\to\file" would not interpret \p, \t, \f as escape sequences)
  • Method-based formatting - Rather than format specifiers like {x:02}, Dada will use method calls like {x.padded(2)} to maintain syntactic consistency
  • Display trait - Once Dada’s trait system is designed, add a trait to allow interpolating expressions that don’t directly produce String values (similar to Rust’s Display)

Implementation notes

This file tracks implementation progress for RFC-0001: String Literals

Status

In progress

Completed

  • Escape sequence processing (\n, \t, \\, \", \{, \}, \r)
  • Triple-quoted strings (disambiguation, termination, embedded quotes)
  • String type (my String)
  • Invalid escape sequence errors
  • Brace escaping (\{, \})
  • Multiline strings: leading newline removal, trailing whitespace removal, auto-dedenting
  • Escape sequences treated as content during dedenting
  • Raw strings ("\ prefix disables dedenting)
  • Ast probe infrastructure for tokenizer-level TDD

Remaining

  • String interpolation: curly brace expressions inside strings
  • Lexer brace nesting depth tracking
  • Nested quotes inside interpolated expressions
  • Interpolation scope — evaluated in enclosing scope
  • Interpolation evaluation order — left-to-right
  • Type checking for interpolated expressions
  • Permission system for interpolated expressions
  • String conversion mechanism — blocked on trait/interface RFC

Spec Paragraphs

14/22 spec paragraphs implemented in spec/src/syntax/string-literals.md. 8 remaining: 7 interpolation + 1 string conversion.

Notes

  • Spec paragraphs authored directly in the spec (not in rfcs/src/0001-string-literals/spec.md), validating the RFC-0002 workflow
  • Ast probe (#? Ast:) enables TDD for tokenizer-level features
  • process_escape_sequences() standalone function duplicates logic from Tokenizer::escape_sequence() — if escape rules change, both must be updated

TODO and Session Notes

This file tracks ongoing work and provides context for resuming sessions

Current Status

RFC drafted with multiline string support, ready for implementation planning

Open Questions

  • Exact string conversion mechanism (depends on trait/interface system)
  • Raw string syntax (future RFC)
  • Precise rules for determining common whitespace prefix in edge cases

Next Steps

  • Begin implementation planning
  • Define lexer changes needed
  • Design AST representation for interpolated strings

Session Notes

2025-01-06

  • Renamed RFC directory from 0001-interpolated-strings to 0001-string-literals
  • Added multiline string literal design:
    • Automatic dedenting when string starts with newline after opening quote
    • Common whitespace prefix removal
    • "\ syntax to disable dedenting
    • \n before closing quote for trailing newline
  • Spec paragraphs are authored directly in spec/src/syntax/string-literals.md (not in a separate RFC spec.md)
  • Created executable examples using assert syntax
  • Added design tenets section with three core principles:
    • Do what I mean
    • Rust-like syntax
    • Simple escape hatch
  • Added triple-quoted string literals (""") for embedded quotes
  • Restructured spec paragraphs with cleaner rule separation

RFC-0002: RFC Process and Specification Workflow


status: draft

Summary

Establish a comprehensive RFC and specification workflow that enables incremental development of language features while maintaining clear separation between design documentation (RFCs) and normative specification text.

Design tenets

  1. Incremental integration - RFCs integrate spec text during implementation, not after acceptance
  2. Visual discoverability - Users can see stable content by default with clear indicators of pending changes
  3. Flexible tooling - Choose tools that support complex conditional content and interactive documentation

Motivation

Dada needs a systematic way to:

  • Document language design decisions and rationale (RFCs)
  • Maintain authoritative specification text that evolves with the language
  • Link tests to specific specification paragraphs for validation
  • Enable developers to see how RFCs would change the current specification

Currently, we have basic RFC infrastructure but lack the integration between RFCs, specifications, and tests needed for effective language development.

Guide-level explanation

The workflow supports concurrent RFC development while maintaining spec stability:

RFC-to-Spec Integration

When an RFC reaches active implementation:

  1. Spec text is written directly in the main specification with RFC annotations
  2. Tests reference spec paragraphs using #:spec comments for validation
  3. Multiple views available - stable spec vs RFC-enhanced variants
  4. Visual indicators show where RFC content differs from stable

Example spec paragraph using MyST directive syntax:

:::{spec} syntax.string-literals.basic
String literals are enclosed in double quotes: `"hello"`.
:::

After RFC-123 implementation begins, add the RFC tag:

:::{spec} syntax.string-literals.basic rfc123
String literals support both single and double quotes: `"hello"` or `'hello'`.
:::

New paragraphs introduced by an RFC:

:::{spec} syntax.string-literals.raw rfc123
Raw string literals use backticks and preserve whitespace.
:::

Content deleted by an RFC uses the ! prefix:

:::{spec} syntax.old-feature !rfc123
This feature is removed.
:::

Interactive Specification View

The specification viewer provides:

  • Default: Stable content only
  • Visual indicators: Badges showing available RFC variants
  • Expandable sections: Click to reveal RFC changes inline
  • Toggle controls: Show/hide specific RFCs globally

Test Integration

Tests link to specification paragraphs:

#:spec syntax.string-literals.basic

class TestStringLiterals {
    assert "hello" == 'hello'  # This will fail in stable spec
}

The #:spec system uses prefix matching - syntax.string-literals matches all sub-paragraphs for comprehensive coverage.

Reference-level explanation

Specification Paragraph Syntax

Specification paragraphs use MyST directive syntax with the {spec} directive:

:::{spec} <paragraph-id> [rfc-tags...]
Paragraph content.
:::

Paragraph identifiers: The first argument is always a semantic ID like syntax.string-literals.basic. These use dotted paths that describe the content, remaining stable during document reorganization.

RFC tags: Optional space-separated tags following the paragraph ID:

  • rfcN - Content added or modified by RFC N
  • !rfcN - Content deleted by RFC N

Examples:

DirectiveMeaning
:::{spec} syntax.fooStable paragraph
:::{spec} syntax.foo rfc123Modified/added by RFC 123
:::{spec} syntax.foo rfc123 rfc456Modified by multiple RFCs
:::{spec} syntax.foo !rfc123Deleted by RFC 123
:::{spec} syntax.foo rfc100 !rfc200Added by RFC 100, later deleted by RFC 200

Version management rules:

  • Paragraphs with RFC tags can be freely modified without version bumps
  • Removing RFC tags (stabilizing content) may warrant creating a new paragraph version (e.g., basicbasic.v2) to maintain history
  • Non-normative prose between directives remains as regular markdown

Test Validation System

Syntax: Tests use #:spec topic.subtopic.detail in file headers to declare which spec paragraphs they validate.

Prefix matching: Test references match all sub-paragraphs (e.g., #:spec syntax.string-literals matches syntax.string-literals.basic, syntax.string-literals.escape-sequences, etc.).

Validation: The test runner parses the specification to extract paragraph IDs from {spec} directives and validates that #:spec references point to existing paragraphs.

Tooling Implementation

The specification uses MyST Markdown with Sphinx, enabling:

  • Native directive support: The {spec} directive integrates naturally with MyST’s syntax
  • Custom Sphinx extension: Processes {spec} directives to generate interactive HTML
  • Layered output: Default view shows stable content; JavaScript controls reveal RFC variants
  • Cross-referencing: Sphinx’s mature reference system links tests, RFCs, and spec paragraphs

The custom {spec} directive extension:

  1. Parses paragraph IDs and RFC tags from directive arguments
  2. Generates HTML with appropriate CSS classes for filtering
  3. Builds a paragraph registry for test validation
  4. Produces visual indicators (badges) for RFC-modified content

Frequently asked questions

Why not use build-time filtering only?

While Sphinx supports build-time content exclusion, the desired user experience requires dynamic interaction. Users should be able to toggle RFC content on/off while reading to understand the differences, not navigate between separate build artifacts. The {spec} directive generates all content with CSS classes, enabling JavaScript-based filtering at runtime.

Why MyST directive syntax?

MyST (Markedly Structured Text) provides a standard way to extend Markdown with directives and roles, widely used with Sphinx. Using :::{spec} rather than a custom syntax like r[...]:

  • Integrates with existing MyST tooling and editors
  • Provides a familiar pattern for contributors who’ve used Sphinx/RST
  • Enables a single directive to carry both paragraph ID and RFC metadata
  • Allows the spec to leverage Sphinx’s ecosystem (cross-references, indexing, etc.)

Why semantic paragraph IDs instead of numeric ones?

Semantic identifiers (e.g., syntax.string-literals.basic vs 4.2.1) remain stable during specification reorganization. Numeric IDs break when sections are reordered, but semantic names describe the content regardless of document structure.

How do multiple concurrent RFCs avoid conflicts?

The directive syntax allows multiple RFC tags: :::{spec} topic.foo rfc123 rfc456. The “source code” model encourages early integration of spec changes during RFC development, making conflicts visible immediately rather than at merge time.

What happens to RFC tags after implementation?

Once an RFC is fully implemented and the feature is stable:

  1. Remove the rfcN tag from the directive (e.g., :::{spec} syntax.foo rfc123 becomes :::{spec} syntax.foo)
  2. Optionally create a versioned paragraph ID (e.g., basicbasic.v2) to maintain history
  3. Update any tests that should only reference the new stable version

Future possibilities

Enhanced Test Coverage Reporting

Generate visual reports showing specification coverage, highlighting untested paragraphs and orphaned tests. This could integrate with CI to require spec coverage for new features.

Multi-Language Specification Support

The paragraph ID system could support localized specifications by extending the annotation format to include language tags.

RFC Impact Analysis

Tooling could analyze which tests would be affected by RFC changes, helping developers understand the scope of proposed modifications.

Integration with Language Server

The #:spec references could provide jump-to-definition functionality in editors, linking test code directly to relevant specification paragraphs.

Implementation notes

Status: Not started

Implementation plan

  • Task one
  • Task two
  • Task three

Pull requests

  • #NNN - Description of PR

Testing

  • Unit tests added
  • Integration tests added
  • Documentation updated

Notes

Track implementation decisions, deviations from the RFC, or lessons learned.