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 | |
|
Brief one-paragraph explanation of the feature being proposed. |
||
1 |
RFC-0001: String Literals | |
|
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 |
||
2 |
RFC-0002: RFC Process and Specification Workflow | |
|
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
- Principle one - Description of core design principle
- Principle two - Another guiding principle for this feature
- 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
- Do what I mean - Default behavior matches common intent: interpolation enabled, indentation automatically handled
- Rust-like syntax - Use familiar
{}for interpolation, maintaining consistency with Rust’s formatting approach - 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:
- Begins with a newline immediately after the opening quote
- 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,\fas 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
Stringvalues (similar to Rust’sDisplay)
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 fromTokenizer::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-stringsto0001-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\nbefore 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
assertsyntax - 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
- Incremental integration - RFCs integrate spec text during implementation, not after acceptance
- Visual discoverability - Users can see stable content by default with clear indicators of pending changes
- 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:
- Spec text is written directly in the main specification with RFC annotations
- Tests reference spec paragraphs using
#:speccomments for validation - Multiple views available - stable spec vs RFC-enhanced variants
- 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:
| Directive | Meaning |
|---|---|
:::{spec} syntax.foo | Stable paragraph |
:::{spec} syntax.foo rfc123 | Modified/added by RFC 123 |
:::{spec} syntax.foo rfc123 rfc456 | Modified by multiple RFCs |
:::{spec} syntax.foo !rfc123 | Deleted by RFC 123 |
:::{spec} syntax.foo rfc100 !rfc200 | Added 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.,
basic→basic.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:
- Parses paragraph IDs and RFC tags from directive arguments
- Generates HTML with appropriate CSS classes for filtering
- Builds a paragraph registry for test validation
- 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:
- Remove the
rfcNtag from the directive (e.g.,:::{spec} syntax.foo rfc123becomes:::{spec} syntax.foo) - Optionally create a versioned paragraph ID (e.g.,
basic→basic.v2) to maintain history - 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.