Featured image of post Reading and Writing YAML

Reading and Writing YAML

In C++, C#, Go, Python, and Rust

YAML: the beautiful, human-readable, indentation-sensitive cousin of JSON that somehow manages to cause equal amounts of joy and frustration.

If you’ve ever dealt with configuration files, you’ve probably encountered YAML. And if you’ve ever been tasked with reading or writing YAML in different programming languages, you know the struggle of finding the right library, avoiding dependency hell, and figuring out why your indentation keeps breaking things.

C++: The Land of Headers and Templates

C++ doesn’t come with YAML support out of the box (big surprise), but luckily, some great libraries exist to make our lives easier.

YAML-CPP

YAML-CPP is the de facto YAML library for C++.

Installation:

1
2
3
4
5
git clone https://github.com/jbeder/yaml-cpp.git
cd yaml-cpp
mkdir build && cd build
cmake ..
make && make install

Reading YAML in C++:

1
2
3
4
5
6
7
8
#include <iostream>
#include "yaml-cpp/yaml.h"

int main() {
    YAML::Node config = YAML::LoadFile("config.yaml");
    std::cout << "Title: " << config["title"].as<std::string>() << std::endl;
    return 0;
}

Writing YAML in C++:

1
2
3
4
5
YAML::Emitter out;
out << YAML::BeginMap;
out << YAML::Key << "name" << YAML::Value << "C++ Programmer";
out << YAML::EndMap;
std::cout << out.c_str();

It’s clean, efficient, and mostly pain-free—until you inevitably mess up CMake.

C#: The Comfort of .NET

C# developers get to use the excellent YamlDotNet library, which is well-maintained and integrates smoothly into .NET projects.

Installation:

1
dotnet add package YamlDotNet

Reading YAML in C#:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
using System;
using YamlDotNet.Serialization;
using System.IO;

class Program {
    static void Main() {
        var deserializer = new DeserializerBuilder().Build();
        var yaml = File.ReadAllText("config.yaml");
        var obj = deserializer.Deserialize<dynamic>(yaml);
        Console.WriteLine(obj["title"]);
    }
}

Writing YAML in C#:

1
2
3
var serializer = new SerializerBuilder().Build();
var yaml = serializer.Serialize(new { name = "C# Developer" });
Console.WriteLine(yaml);

With LINQ and dynamic objects, C# makes YAML handling a breeze.

Go: The Simple and Elegant Way

Go has a fantastic YAML library called gopkg.in/yaml.v3.

Installation:

1
go get gopkg.in/yaml.v3

Reading YAML in Go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package main

import (
    "fmt"
    "gopkg.in/yaml.v3"
    "os"
)

type Config struct {
    Title string `yaml:"title"`
}

func main() {
    file, _ := os.ReadFile("config.yaml")
    var config Config
    yaml.Unmarshal(file, &config)
    fmt.Println("Title:", config.Title)
}

Writing YAML in Go:

1
2
3
config := Config{Title: "Gopher Life"}
out, _ := yaml.Marshal(&config)
fmt.Println(string(out))

Go keeps it straightforward—no surprises here.

Python: YAML, But Make It Pythonic

Python developers get the joy of using PyYAML, which makes YAML handling almost too easy.

Installation:

1
pip install pyyaml

Reading YAML in Python:

1
2
3
4
5
import yaml

with open("config.yaml", "r") as f:
    config = yaml.safe_load(f)
    print("Title:", config["title"])

Writing YAML in Python:

1
2
3
config = {"name": "Pythonista"}
with open("output.yaml", "w") as f:
    yaml.dump(config, f)

Python, as always, makes things simple and intuitive.

Rust: The Safe and Speedy Choice

Rust’s package ecosystem includes serde_yaml, which integrates seamlessly with Serde.

Installation:

1
cargo add serde_yaml serde --features derive

Reading YAML in Rust:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
use serde::Deserialize;
use serde_yaml;
use std::fs;

#[derive(Debug, Deserialize)]
struct Config {
    title: String,
}

fn main() {
    let yaml = fs::read_to_string("config.yaml").unwrap();
    let config: Config = serde_yaml::from_str(&yaml).unwrap();
    println!("Title: {}", config.title);
}

Writing YAML in Rust:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use serde::Serialize;
use serde_yaml;

#[derive(Serialize)]
struct Config {
    name: String,
}

fn main() {
    let config = Config { name: "Rustacean".to_string() };
    let yaml = serde_yaml::to_string(&config).unwrap();
    println!("{}", yaml);
}

Key Ideas

Key IdeaSummary
C++ with YAML-CPPA clean and efficient C++ library for YAML.
C# with YamlDotNetSimple and intuitive YAML handling in .NET.
Go with gopkg.in/yaml.v3A lightweight and elegant YAML library.
Python with PyYAMLThe easiest way to handle YAML.
Rust with serde_yamlSafe, fast, and integrates well with Serde.

References