ddn.adam¶
Practical examples demonstrating everyday usage of the ddn.adam compact dynamic value type.
Overview¶
adam is a memory-efficient alternative to ddn.var, using only 16 bytes on 64-bit platforms (vs. 24+ bytes for typical variant types). It provides the same API and semantics as var while minimizing memory footprint.
Basic Value Assignment¶
Create and assign values of different types:
/+ dub.sdl:
name "adam-basic"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
// Null value (default)
adam empty;
writeln("Empty: ", empty); // Output: null
// Boolean
adam flag = true;
writeln("Flag: ", flag); // Output: true
// Integers
adam count = 42;
adam bigNum = 9_223_372_036_854_775_807L; // long.max
writeln("Count: ", count); // Output: 42
writeln("BigNum: ", bigNum); // Output: 9223372036854775807
// Floating point
adam pi = 3.14159;
adam temperature = -40.0f;
writeln("Pi: ", pi); // Output: 3.14159
writeln("Temp: ", temperature); // Output: -40
// Characters (normalized to dchar)
adam letter = 'D';
adam emoji = '👍';
writeln("Letter: ", letter); // Output: D
writeln("Emoji: ", emoji); // Output: 👍
// String
adam greeting = "Hello, World!";
writeln("Greeting: ", greeting); // Output: "Hello, World!"
// Check memory footprint
writeln("\nadam.sizeof = ", adam.sizeof, " bytes"); // Output: 16 bytes
}
Type Conversion with get!T¶
Extract values as specific D types:
/+ dub.sdl:
name "adam-conversion"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
adam num = 42;
// Convert to different numeric types
int i = num.get!int;
long l = num.get!long;
double d = num.get!double;
string s = num.get!string;
writeln("As int: ", i); // Output: 42
writeln("As long: ", l); // Output: 42
writeln("As double: ", d); // Output: 42
writeln("As string: ", s); // Output: 42
// Boolean conversion
adam zero = 0;
adam nonZero = 5;
writeln("Zero as bool: ", zero.get!bool); // Output: false
writeln("NonZero as bool: ", nonZero.get!bool); // Output: true
// Type normalization
adam charVal = 'A';
writeln("Char type: ", charVal.type); // Output: DCHAR (normalized)
}
Working with Arrays¶
Create and manipulate dynamic arrays:
/+ dub.sdl:
name "adam-arrays"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
// Create an array
adam arr = [adam(1), adam(2), adam(3)];
writeln("Array: ", arr); // Output: [1,2,3]
writeln("Length: ", arr.length); // Output: 3
// Access elements by index
writeln("First: ", arr[0].get!int); // Output: 1
writeln("Last: ", arr[2].get!int); // Output: 3
// Modify elements
arr[0] = 100;
writeln("Modified: ", arr); // Output: [100,2,3]
// Mixed-type arrays
adam mixed = [adam(1), adam("two"), adam(3.0), adam(true)];
writeln("Mixed: ", mixed); // Output: [1,"two",3,true]
// Iterate over array elements
adam fruits = [adam("apple"), adam("banana"), adam("cherry")];
write("Fruits: ");
foreach (i; 0 .. fruits.length) {
write(fruits[i].get!string, " ");
}
writeln(); // Output: Fruits: apple banana cherry
}
Working with Objects (Maps)¶
Create and manipulate key-value maps:
/+ dub.sdl:
name "adam-objects"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
// Create an object using indexing
adam person;
person["name"] = "Alice";
person["age"] = 30;
person["active"] = true;
writeln("Person: ", person);
// Output: {"active":true,"age":30,"name":"Alice"}
// Access values
writeln("Name: ", person["name"].get!string); // Output: Alice
writeln("Age: ", person["age"].get!int); // Output: 30
// Check if key exists
writeln("Has 'name': ", person.contains("name")); // Output: true
writeln("Has 'email': ", person.contains("email")); // Output: false
// Get all keys
writeln("Keys: ", person.keys()); // Output: ["active", "age", "name"]
}
Nested Structures¶
Work with complex nested data:
/+ dub.sdl:
name "adam-nested"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
// Build a nested structure
adam company;
company["name"] = "TechCorp";
company["founded"] = 2020;
// Nested object
adam address;
address["street"] = "123 Main St";
address["city"] = "Springfield";
address["zip"] = "12345";
company["address"] = address;
// Nested array
adam tags = [adam("tech"), adam("startup"), adam("innovation")];
company["tags"] = tags;
// Access nested data
writeln("Company: ", company["name"].get!string);
writeln("City: ", company["address"]["city"].get!string);
writeln("First tag: ", company["tags"][0].get!string);
// Serialize to JSON
writeln("\nFull structure:");
writeln(company.toJSON());
}
Arithmetic Operations¶
Perform arithmetic on numeric values:
/+ dub.sdl:
name "adam-arithmetic"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
adam a = 10;
adam b = 3;
// Basic operations
writeln("a + b = ", (a + b).get!int); // Output: 13
writeln("a - b = ", (a - b).get!int); // Output: 7
writeln("a * b = ", (a * b).get!int); // Output: 30
writeln("a / b = ", (a / b).get!int); // Output: 3
writeln("a % b = ", (a % b).get!int); // Output: 1
// Floating point arithmetic
adam x = 10.0;
adam y = 3.0;
writeln("x / y = ", (x / y).get!double); // Output: 3.33333...
// Mixed integer/float promotes to float
adam intVal = 5;
adam floatVal = 2.5;
writeln("int + float = ", (intVal + floatVal).get!double); // Output: 7.5
// Unary operations
adam n = 42;
writeln("-n = ", (-n).get!int); // Output: -42
}
Comparison Operations¶
Compare adam values:
/+ dub.sdl:
name "adam-comparison"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
adam a = 10;
adam b = 20;
adam c = 10;
// Equality
writeln("a == c: ", a == c); // Output: true
writeln("a == b: ", a == b); // Output: false
// Ordering
writeln("a < b: ", a < b); // Output: true
writeln("a <= c: ", a <= c); // Output: true
writeln("b > a: ", b > a); // Output: true
// String comparison
adam s1 = "apple";
adam s2 = "banana";
writeln("apple < banana: ", s1 < s2); // Output: true
}
JSON Serialization¶
Convert adam values to JSON strings:
/+ dub.sdl:
name "adam-json"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
// Simple values
adam num = 42;
adam str = "hello";
adam flag = true;
writeln(num.toJSON()); // Output: 42
writeln(str.toJSON()); // Output: "hello"
writeln(flag.toJSON()); // Output: true
// Arrays
adam arr = [adam(1), adam(2), adam(3)];
writeln(arr.toJSON()); // Output: [1,2,3]
// Objects (keys are sorted alphabetically)
adam obj;
obj["zebra"] = 1;
obj["apple"] = 2;
obj["mango"] = 3;
writeln(obj.toJSON()); // Output: {"apple":2,"mango":3,"zebra":1}
// Complex nested structure
adam config;
config["server"] = "localhost";
config["ports"] = [adam(80), adam(443)];
config["ssl"] = true;
writeln("\nConfig JSON:");
writeln(config.toJSON());
// Output: {"ports":[80,443],"server":"localhost","ssl":true}
}
Type Checking¶
Inspect the runtime type of an adam value:
/+ dub.sdl:
name "adam-types"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
void main() {
adam[] values = [
adam.init, // NULL
adam(true), // BOOL
adam(42), // INT
adam(3.14), // DOUBLE
adam("text"), // STRING
adam([adam(1)]), // ARRAY
];
string[] names = ["null", "bool", "int", "double", "string", "array"];
foreach (i, v; values) {
writefln("%s: type = %s", names[i], v.type);
}
// Output:
// null: type = NULL
// bool: type = BOOL
// int: type = INT
// double: type = DOUBLE
// string: type = STRING
// array: type = ARRAY
// Type-based dispatch
adam data = [adam(1), adam(2), adam(3)];
if (data.type == adam.Type.ARRAY) {
writeln("Processing array with ", data.length, " elements");
} else if (data.type == adam.Type.OBJECT) {
writeln("Processing object");
} else {
writeln("Processing scalar value");
}
}
Memory Efficiency Comparison¶
Demonstrate the memory savings of adam vs var:
/+ dub.sdl:
name "adam-memory"
dependency "ddn" path="../.."
+/
import ddn.adam;
import ddn.var;
import std.stdio;
void main() {
writeln("Size comparison:");
writeln(" adam.sizeof = ", adam.sizeof, " bytes");
writeln(" var.sizeof = ", var.sizeof, " bytes");
// For large collections, the savings add up
enum N = 10_000;
writeln("\nFor ", N, " elements:");
writeln(" adam[] would use ~", N * adam.sizeof / 1024, " KB");
writeln(" var[] would use ~", N * var.sizeof / 1024, " KB");
// Both types work the same way
adam a = 42;
var v = 42;
writeln("\nBoth produce same JSON:");
writeln(" adam: ", a.toJSON());
writeln(" var: ", v.toJSON());
}
Practical Example: Compact Data Store¶
A complete example showing real-world usage for memory-efficient data storage:
/+ dub.sdl:
name "adam-datastore"
dependency "ddn" path="../.."
+/
import ddn.adam;
import std.stdio;
import std.array : appender;
/// A simple in-memory data store using adam for compact storage
struct DataStore {
adam[] records;
void add(adam record) {
records ~= record;
}
adam[] findByField(string field, adam value) {
auto results = appender!(adam[]);
foreach (ref rec; records) {
if (rec.type == adam.Type.OBJECT && rec.contains(field)) {
if (rec[field] == value) {
results ~= rec;
}
}
}
return results[];
}
string toJSON() {
adam arr = records;
return arr.toJSON();
}
}
void main() {
DataStore store;
// Add some records
adam user1;
user1["id"] = 1;
user1["name"] = "Alice";
user1["role"] = "admin";
store.add(user1);
adam user2;
user2["id"] = 2;
user2["name"] = "Bob";
user2["role"] = "user";
store.add(user2);
adam user3;
user3["id"] = 3;
user3["name"] = "Carol";
user3["role"] = "user";
store.add(user3);
// Query the store
writeln("All records:");
writeln(store.toJSON());
writeln("\nUsers with role 'user':");
auto users = store.findByField("role", adam("user"));
foreach (ref u; users) {
writeln(" - ", u["name"].get!string);
}
writeln("\nMemory used: ~", store.records.length * adam.sizeof, " bytes for values");
}
When to Use adam vs var¶
/+ dub.sdl:
name "adam-choice"
dependency "ddn" path="../.."
+/
import ddn.adam;
import ddn.var;
import std.stdio;
void main() {
writeln("Use adam when:");
writeln(" - Memory is constrained");
writeln(" - Storing large collections of dynamic values");
writeln(" - Network serialization with size limits");
writeln(" - Embedded systems or high-density data");
writeln("\nUse var when:");
writeln(" - Maximum API compatibility is needed");
writeln(" - Working with existing var-based code");
writeln(" - Memory is not a primary concern");
writeln("\nBoth types:");
writeln(" - Support the same value types");
writeln(" - Have compatible JSON serialization");
writeln(" - Support arrays and objects");
writeln(" - Are @safe and GC-friendly");
}
See Also¶
- ddn.adam Overview — Comprehensive module overview
- ddn.adam API Reference — Complete API documentation
- ddn.var Examples — Full-featured dynamic value type
- ddn.data.json5 Examples — JSON5 parsing and serialization