sml

SML { ❄ }

Downloads Questions, bug reports, or just to say hi: sal@mail.swebase.cn 中文 EN

Chapter 3: Fragment Inheritance

In real projects, many configuration blocks look similar - for example, multiple services require region, timeout, dns. Repetitive writing is both verbose and prone to inconsistency. SML uses fragments to solve this problem.

One sentence: Fragment is “value reuse” - defining a set of fields once and expanding them everywhere by referencing.

3.1 Definition fragment: @name

Define a reusable field using @Name { }:

@net {
    region: cn-north-1
    dns: internal.example.com
    timeout: 30
}

Note that @net itself will not appear in the parsing results, it is just a “template”.

3.2 Quoted excerpt: &name

Expand the fragment using &Name:

network: &net

After parsing, network will obtain:

network {
    region: cn-north-1
    dns: internal.example.com
    timeout: 30
}

3.3 References within Blocks

Fragments are commonly used to inject common fields into multiple services:

@base {
    region: cn-north-1
    timeout: 30
}

service auth {
    cfg: &base
    port: 7100
    name: auth-svc
}
service billing {
    cfg: &base
    port: 7200
    name: billing-svc
}

service auth is equivalent to:

service auth {
    cfg: { region: cn-north-1, timeout: 30 }
    port: 7100
    name: auth-svc
}

service billing also obtained the same region/timeout via its cfg key, but port/name were different from each other. Reuse+individuality, perfect.

3.4 Important Details: &name will not be unfolded when written naked within the block

This is the easiest pit for beginners to step into:

server {
    &base            # ❌  Wrong: &base is parsed as a "key name"; fields are NOT expanded
    port: 8080
}

The correct way to write it is to assign a fragment as a value to a key:

server {
    net: &base       # ✅  Key "net" receives all fields of base
    port: 8080
}

Alternatively, &base itself can be used as the source of the value (such as the writing style of service auth { &base ... } in 3.3, which “starts the block directly with &base and then with additional fields”, the parser will treat it as “expanding the fragment first and merging subsequent fields”). * * Remember: Fragments are “values” and should appear at the value position of Key: Value. **

3.5 Fragment vs Contract (Preview)

You may wonder, “Do fragments and contracts (Chapter 5) sound like each other?” Their positioning is completely different:

Fragment @base/&base Contract @contract/@is
Essence Value Reuse ** Shape Constraints**
What to do Expand a set of fields Validate the structure and add default values
Result Data copied and filled Data checked and filled in

The two are orthogonal and can be used together (first unfold the fragment, then use contract verification).

3.6 Give it a try with your hands

Write configuration for a game server cluster, with three servers sharing region and max_players:

@common {
    region: ap-east-1
    max_players: 64
}

lobby { &common port: 25565 name: hall }
pvp { &common port: 25566 name: arena }
survival { &common port: 25567 name: survival }

→ Chapter 4: Include and namespaces

Hands on practice

After reading this chapter, directly modify SML in the editor below and click “Run” to immediately see the parsing results or validation errors - having output is necessary for efficient learning.

✍ Hands-on exercise Define @base { region, timeout }, and then write two service blocks (auth, billing) both &base, each covering port and name.
💡 Hint: Miswrite&base as the naked word (remove&) and see what happens.
✍ Self-check quiz: Chapter 3 Self testing: Fragment Inheritance Score 0 / 4
Q1. Which symbol is used to define reusable fragments?
Q2. In service auth { &base port: 7100 }, if @base has already defined port: 7000, what is the result port?
Q3. Judgment:&base must be placed on the first line of the block to take effect.
Q4. What problems does fragment inheritance mainly solve?