ddn.var¶
Practical examples demonstrating everyday usage of the ddn.var dynamic value type.
Basic Value Assignment¶
Create and assign values of different types to var:
/+ dub.sdl:
name "var-basic"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
// Null value (default)
var empty;
writeln("Empty: ", empty); // Output: null
// Boolean
var flag = true;
writeln("Flag: ", flag); // Output: true
// Integers
var count = 42;
var bigNum = 9_223_372_036_854_775_807L; // long.max
writeln("Count: ", count); // Output: 42
writeln("BigNum: ", bigNum); // Output: 9223372036854775807
// Floating point
var pi = 3.14159;
var temperature = -40.0f;
writeln("Pi: ", pi); // Output: 3.14159
writeln("Temp: ", temperature); // Output: -40
// Characters
var letter = 'D';
var emoji = '👍';
writeln("Letter: ", letter); // Output: D
writeln("Emoji: ", emoji); // Output: 👍
// String
var greeting = "Hello, World!";
writeln("Greeting: ", greeting); // Output: "Hello, World!"
}
Type Conversion with as!T¶
Extract values as specific D types:
/+ dub.sdl:
name "var-conversion"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
var num = 42;
// Convert to different numeric types
int i = num.as!int;
long l = num.as!long;
double d = num.as!double;
string s = num.as!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
var zero = 0;
var nonZero = 5;
writeln("Zero as bool: ", zero.as!bool); // Output: false
writeln("NonZero as bool: ", nonZero.as!bool); // Output: true
// String to numeric (when parsing)
var strNum = "123";
writeln("String value: ", strNum.as!string); // Output: 123
}
Working with Arrays¶
Create and manipulate dynamic arrays:
/+ dub.sdl:
name "var-arrays"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
// Create an array from D array literal
var numbers = [1, 2, 3, 4, 5];
writeln("Numbers: ", numbers); // Output: [1,2,3,4,5]
writeln("Length: ", numbers.length); // Output: 5
// Access elements by index
writeln("First: ", numbers[0].as!int); // Output: 1
writeln("Last: ", numbers[4].as!int); // Output: 5
// Modify elements
numbers[0].opAssign(100);
writeln("Modified: ", numbers); // Output: [100,2,3,4,5]
// Mixed-type arrays
var mixed = var([var(1), var("two"), var(3.0), var(true)]);
writeln("Mixed: ", mixed); // Output: [1,"two",3,true]
// Iterate over array elements
var fruits = var([var("apple"), var("banana"), var("cherry")]);
write("Fruits: ");
foreach (ref el; fruits.as!(var[])) {
write(el.as!string, " ");
}
writeln(); // Output: Fruits: apple banana cherry
}
Working with Objects (Maps)¶
Create and manipulate key-value maps:
/+ dub.sdl:
name "var-objects"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
// Create an object using indexing
var 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"].as!string); // Output: Alice
writeln("Age: ", person["age"].as!int); // Output: 30
// Use opDispatch for field-like access
var config;
config.host = "localhost";
config.port = 8080;
config.debug_ = true; // Use underscore for reserved words
writeln("Host: ", config.host.as!string); // Output: localhost
writeln("Port: ", config.port.as!int); // Output: 8080
// Check if key exists
writeln("Has 'name': ", person.contains("name")); // Output: true
writeln("Has 'email': ", person.contains("email")); // Output: false
// Get with default value
var email = person.get("email", var("unknown@example.com"));
writeln("Email: ", email.as!string); // Output: unknown@example.com
// Get all keys and values
writeln("Keys: ", person.keys()); // Output: ["active", "age", "name"]
writeln("Values: ", person.values()); // Output: [true, 30, "Alice"]
}
Nested Structures¶
Work with complex nested data:
/+ dub.sdl:
name "var-nested"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
// Build a nested structure
var company;
company["name"] = "TechCorp";
company["founded"] = 2020;
// Nested object
var address;
address["street"] = "123 Main St";
address["city"] = "Springfield";
address["zip"] = "12345";
company["address"] = address;
// Nested array of objects
var employees = var([var.init, var.init]);
employees[0]["name"] = "Bob";
employees[0]["role"] = "Developer";
employees[1]["name"] = "Carol";
employees[1]["role"] = "Designer";
company["employees"] = employees;
// Access nested data
writeln("Company: ", company["name"].as!string);
writeln("City: ", company["address"]["city"].as!string);
writeln("First employee: ", company["employees"][0]["name"].as!string);
// Pretty-print as JSON
writeln("\nFull structure:");
writeln(company.toJSON());
}
Arithmetic Operations¶
Perform arithmetic on numeric values:
/+ dub.sdl:
name "var-arithmetic"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
var a = 10;
var b = 3;
// Basic operations
writeln("a + b = ", (a + b).as!int); // Output: 13
writeln("a - b = ", (a - b).as!int); // Output: 7
writeln("a * b = ", (a * b).as!int); // Output: 30
writeln("a / b = ", (a / b).as!int); // Output: 3
writeln("a % b = ", (a % b).as!int); // Output: 1
// Floating point arithmetic
var x = 10.0;
var y = 3.0;
writeln("x / y = ", (x / y).as!double); // Output: 3.33333...
// Mixed integer/float promotes to float
var intVal = 5;
var floatVal = 2.5;
writeln("int + float = ", (intVal + floatVal).as!double); // Output: 7.5
// Division by zero returns NULL (safe behavior)
var zero = 0;
var result = a / zero;
writeln("10 / 0 type: ", result.type); // Output: NULL
// Unary operations
var n = 42;
writeln("-n = ", (-n).as!int); // Output: -42
writeln("+n = ", (+n).as!int); // Output: 42
}
Comparison Operations¶
Compare var values:
/+ dub.sdl:
name "var-comparison"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
var a = 10;
var b = 20;
var c = 10;
// Equality
writeln("a == c: ", a == c); // Output: true
writeln("a == b: ", a == b); // Output: false
writeln("a != b: ", a != b); // Output: true
// Ordering
writeln("a < b: ", a < b); // Output: true
writeln("a <= c: ", a <= c); // Output: true
writeln("b > a: ", b > a); // Output: true
// String comparison
var s1 = "apple";
var s2 = "banana";
writeln("apple < banana: ", s1 < s2); // Output: true
// Type-aware comparison
var intTen = 10;
var doubleTen = 10.0;
writeln("int 10 == double 10.0: ", intTen == doubleTen); // Output: true
}
Deep Copy with dup()¶
Understand aliasing and create independent copies:
/+ dub.sdl:
name "var-deepcopy"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
// Assignment aliases arrays and objects
var original = var([1, 2, 3]);
var alias_ = original;
alias_[0].opAssign(999);
writeln("Original after alias modification: ", original);
// Output: [999,2,3] - both point to same data!
// Use dup() for independent copy
var source = var([10, 20, 30]);
var copy = source.dup;
copy[0].opAssign(999);
writeln("Source after copy modification: ", source); // Output: [10,20,30]
writeln("Copy: ", copy); // Output: [999,20,30]
// Deep copy works for nested structures too
var nested;
nested["data"] = var([1, 2, 3]);
var nestedCopy = nested.dup;
nestedCopy["data"][0].opAssign(100);
writeln("Original nested: ", nested["data"]); // Output: [1,2,3]
writeln("Copied nested: ", nestedCopy["data"]); // Output: [100,2,3]
}
JSON Serialization¶
Convert var values to JSON strings:
/+ dub.sdl:
name "var-json"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
// Simple values
var num = 42;
var str = "hello";
var flag = true;
writeln(num.toJSON()); // Output: 42
writeln(str.toJSON()); // Output: "hello"
writeln(flag.toJSON()); // Output: true
// Arrays
var arr = var([var(1), var(2), var(3)]);
writeln(arr.toJSON()); // Output: [1,2,3]
// Objects (keys are sorted alphabetically)
var obj;
obj["zebra"] = 1;
obj["apple"] = 2;
obj["mango"] = 3;
writeln(obj.toJSON()); // Output: {"apple":2,"mango":3,"zebra":1}
// Complex nested structure
var config;
config["server"] = "localhost";
config["ports"] = var([var(80), var(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 a var:
/+ dub.sdl:
name "var-types"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
var values = [
var.init, // NULL
var(true), // BOOL
var(42), // INT
var(3.14), // DOUBLE
var("text"), // STRING
var([var(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
var data = var([var(1), var(2), var(3)]);
if (data.type == var.Type.ARRAY) {
writeln("Processing array with ", data.length, " elements");
} else if (data.type == var.Type.OBJECT) {
writeln("Processing object with ", data.length, " keys");
} else {
writeln("Processing scalar value");
}
}
Error Handling Patterns¶
Handle edge cases gracefully:
/+ dub.sdl:
name "var-errors"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
void main() {
// Safe access with get() and default values
var config;
config["host"] = "localhost";
// Key exists
writeln("Host: ", config.get("host", var("default")).as!string);
// Output: localhost
// Key doesn't exist - returns default
writeln("Port: ", config.get("port", var(8080)).as!int);
// Output: 8080
// Check before access
if (config.contains("timeout")) {
writeln("Timeout: ", config["timeout"].as!int);
} else {
writeln("Timeout not configured, using default");
}
// Division by zero returns NULL instead of crashing
var a = 100;
var b = 0;
var result = a / b;
if (result.type == var.Type.NULL) {
writeln("Division by zero detected!");
}
// Safe type conversion - incompatible types return T.init
var text = "not a number";
int num = text.as!int; // Returns 0 (int.init)
writeln("Text as int: ", num); // Output: 0
}
Practical Example: Configuration Parser¶
A complete example showing real-world usage:
/+ dub.sdl:
name "var-config"
dependency "ddn" path="../.."
+/
import ddn.var;
import std.stdio;
struct AppConfig {
string host;
int port;
bool debug_;
string[] allowedOrigins;
}
AppConfig parseConfig(var config) {
AppConfig result;
result.host = config.get("host", var("localhost")).as!string;
result.port = config.get("port", var(8080)).as!int;
result.debug_ = config.get("debug", var(false)).as!bool;
// Parse array of strings
if (config.contains("allowedOrigins")) {
auto origins = config["allowedOrigins"].as!(var[]);
foreach (ref o; origins) {
result.allowedOrigins ~= o.as!string;
}
}
return result;
}
void main() {
// Simulate configuration data
var config;
config["host"] = "api.example.com";
config["port"] = 443;
config["debug"] = true;
config["allowedOrigins"] = var([
var("https://example.com"),
var("https://app.example.com")
]);
auto appConfig = parseConfig(config);
writeln("Server Configuration:");
writeln(" Host: ", appConfig.host);
writeln(" Port: ", appConfig.port);
writeln(" Debug: ", appConfig.debug_);
writeln(" Allowed Origins:");
foreach (origin; appConfig.allowedOrigins) {
writeln(" - ", origin);
}
}
See Also¶
- ddn.var Overview — Comprehensive module overview
- ddn.var API Reference — Complete API documentation
- ddn.adam Examples — Memory-efficient alternative
- ddn.data.json5 Examples — JSON5 parsing and serialization