ktsu.Semantics.Cpp 5.4.2

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package ktsu.Semantics.Cpp --version 5.4.2
                    
NuGet\Install-Package ktsu.Semantics.Cpp -Version 5.4.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ktsu.Semantics.Cpp" Version="5.4.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ktsu.Semantics.Cpp" Version="5.4.2" />
                    
Directory.Packages.props
<PackageReference Include="ktsu.Semantics.Cpp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ktsu.Semantics.Cpp --version 5.4.2
                    
#r "nuget: ktsu.Semantics.Cpp, 5.4.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ktsu.Semantics.Cpp@5.4.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ktsu.Semantics.Cpp&version=5.4.2
                    
Install as a Cake Addin
#tool nuget:?package=ktsu.Semantics.Cpp&version=5.4.2
                    
Install as a Cake Tool

ktsu.Semantics

License NuGet Version NuGet Version NuGet Downloads GitHub commit activity GitHub contributors GitHub Actions Workflow Status

A .NET family of libraries for replacing primitive obsession with strongly-typed, self-validating domain models. Each pillar ships as its own NuGet package, so you take only what you need.

  • Semantic Strings: type-safe wrappers like EmailAddress, UserId, BlogSlug with attribute-driven validation, plus a batteries-included identifiers package (Uuid, Ulid, Iban, Isbn, CreditCardNumber, JwtToken).
  • Semantic Paths: a polymorphic IPath hierarchy for files, directories, absolute, relative, and combinations.
  • Semantic Quantities: a metadata-generated, type-safe quantity system with a unified IVector0..IVector4 model covering 60+ physical dimensions and 200+ generated types. Optional per-storage-type alias packages let you write Mass instead of Mass<double>.
  • Semantic Music: immutable musical value types (Pitch, Interval, Scale, Chord, Key, Duration, TimeSignature), with chord-symbol parsing and voicing, plus a harmonic and structural analysis layer.
  • Semantic Color: a physically-grounded Color type with linear-RGB math, perceptual Oklab operations, and built-in WCAG accessibility checks.

Packages

Each package has its own README with the full API surface, examples, and reference tables. This document is the family overview.

Package What it provides Details
ktsu.Semantics.Strings SemanticString<T> framework and validation attributes README
ktsu.Semantics.Strings.Identifiers Ready-made identifier types (Uuid, Iban, Isbn, ...) README
ktsu.Semantics.Paths Polymorphic, typed file system path types README
ktsu.Semantics.Quantities Generated, dimensionally-safe physical quantities README
ktsu.Semantics.Quantities.Double double storage-type aliases README
ktsu.Semantics.Quantities.Float float storage-type aliases README
ktsu.Semantics.Quantities.Decimal decimal storage-type aliases README
ktsu.Semantics.Quantities.Precise ktsu.PreciseNumber storage-type aliases README
ktsu.Semantics.Music Musical value types and harmonic analysis README
ktsu.Semantics.Color Linear/perceptual color with accessibility tooling README

All packages target net8.0net10.0. Strings, Identifiers, Paths, Music, and Color additionally target netstandard2.0/netstandard2.1. Quantities and its alias packages are net8.0+ (they require INumber<T>).

Semantic strings

Define a string-shaped domain type, attach validation attributes, and get a compile-time-distinct type that validates on construction.

using ktsu.Semantics.Strings;

[IsEmailAddress]
public sealed record EmailAddress : SemanticString<EmailAddress> { }

[StartsWith("USER_"), HasNonWhitespaceContent]
public sealed record UserId : SemanticString<UserId> { }

EmailAddress email = EmailAddress.Create("user@example.com");
UserId userId = UserId.Create("USER_12345");

public void SendWelcomeEmail(EmailAddress to, UserId who) { /* ... */ }
// SendWelcomeEmail(userId, email);   // does not compile

The ktsu.Semantics.Strings.Identifiers package adds ready-made identifier types with real check-digit and structural validation:

using ktsu.Semantics.Strings.Identifiers;

Uuid id = Uuid.Create("123E4567-E89B-12D3-A456-426614174000"); // canonicalised to lowercase
Iban iban = Iban.Create("GB82 WEST 1234 5698 7654 32");        // whitespace stripped, mod-97 validated

Full detail: Semantics.Strings README and Semantics.Strings.Identifiers README.

Semantic paths

A path is a type that encodes whether it names a file or a directory and whether it is absolute or relative. Compose them with /, decompose with typed properties, and hold mixed paths behind IPath.

using ktsu.Semantics.Paths;

AbsoluteDirectoryPath projectDir = AbsoluteDirectoryPath.Create(@"C:\repos\app");
AbsoluteFilePath source = projectDir / RelativeFilePath.Create(@"src\Program.cs");

FileName name = source.FileName;              // Program.cs
FileExtension ext = source.FileExtension;     // .cs
RelativeFilePath rel = source.AsRelative(projectDir);

Full detail: Semantics.Paths README.

Semantic quantities

Every quantity is a vector whose direction-space dimensionality is part of the type. Operators flow from a metadata definition, so Force · Displacement yields Energy at compile time.

using ktsu.Semantics.Quantities;

Mass<double> m = Mass<double>.FromKilogram(2.0);
Speed<double> v = Speed<double>.FromMeterPerSecond(3.0);
MomentumMagnitude<double> p = m * v;          // Mass * Speed -> MomentumMagnitude

Force3D<double> f = new() { X = 3.0, Y = 4.0, Z = 0.0 };
ForceMagnitude<double> mag = f.Magnitude();   // 5.0

If a project uses one storage type throughout, reference an alias package and drop the generic argument entirely:

using ktsu.Semantics.Quantities;   // with ktsu.Semantics.Quantities.Double referenced

Mass mass = Mass.FromKilogram(10.0);
Speed speed = Speed.FromMeterPerSecond(15.0);

Full detail: Semantics.Quantities README. The unified vector model and generator are documented in docs/strategy-unified-vector-quantities.md and docs/physics-generator.md.

Semantic music

Immutable, validated musical value types plus an analysis layer that models harmony nested inside structure. Pure logic, no I/O. The pitch convention is MIDI 60 = C4.

using ktsu.Semantics.Music;

Progression prog = Progression.Parse("| Dm7 | G7 | Cmaj7 |");
Key key = prog.InferKey()!;                             // C major
IReadOnlyList<string> roman = prog.RomanNumerals(key);  // ii7, V7, Imaj7

Chord cmaj7 = Chord.Parse("Cmaj7");
IReadOnlyList<Pitch> voicing = cmaj7.Voice(octave: 4);  // C4, E4, G4, B4

Full detail: Semantics.Music README.

Semantic color

The canonical Color stores linear RGBA, so mixing, interpolation, and luminance are physically correct. Perceptual work happens in Oklab, and WCAG accessibility tooling is built in.

using ktsu.Semantics.Color;

Color text = Color.FromHex("#777777");
Color background = NamedColors.White;

if (text.AccessibilityLevelAgainst(background) < AccessibilityLevel.AA)
{
    text = text.AdjustForContrast(background, AccessibilityLevel.AA);
}

IReadOnlyList<Color> ramp = NamedColors.Red.Gradient(NamedColors.Blue, 5); // Oklab gradient

Full detail: Semantics.Color README.

Dependency injection

services.AddTransient<ISemanticStringFactory<EmailAddress>, SemanticStringFactory<EmailAddress>>();

public class UserService(ISemanticStringFactory<EmailAddress> emails)
{
    public User CreateUser(string raw) =>
        emails.TryFromString(raw, out EmailAddress? email)
            ? new User(email!)
            : throw new ArgumentException("invalid email");
}

Performance

Every release measures a fixed set of benchmarks and adds a point to a chart per library. The numbers behind them are in docs/benchmarks/, and the suite is Semantics.Benchmarks.

Read the two halves of every chart differently. Allocation is exact — the same code allocates the same bytes on any machine, so a step in the top row is always a real change. Time is measured on shared CI runners, where the host a job happens to land on varies more than most releases do, so each time is divided by a reference workload measured in the same job. That cancels most of the difference between machines; what is left is indicative rather than precise. One caveat on the paths chart: its inputs are built per platform, because whether a path is absolute is a question the operating system answers differently, so its allocation row can step when the measuring host changes rather than when the library does. The other two charts take their inputs from compile-time constants and do not have that exposure.

Quantities

<picture> <source media="(prefers-color-scheme: dark)" srcset="docs/benchmarks/performance-dark.svg"> <img alt="Allocated bytes per operation, and time relative to a fixed reference workload, for each Semantics.Quantities release" src="docs/benchmarks/performance.svg"> </picture>

The grid is one operation per storage type rather than every operation at one storage type. A quantity is a readonly record struct over its T and does almost nothing of its own — a value is held in the SI base unit, so an operator is the storage type's arithmetic and a struct initialiser — so the same line of user code costs different things depending on the T it was written against, and a release changes it per T.

Strings

<picture> <source media="(prefers-color-scheme: dark)" srcset="docs/benchmarks/strings-performance-dark.svg"> <img alt="Allocated bytes per operation, and time relative to a fixed reference workload, for each Semantics.Strings release" src="docs/benchmarks/strings-performance.svg"> </picture>

The axis here is validation weight, because that is where a semantic string spends. Create goes through Activator.CreateInstance, a PropertyInfo.SetValue, and a reflective walk of the type's validation attributes on every call, so the top row walks from that machinery alone up through a character set check, a format check, and a mod-97 check. The bottom row is what surrounds it: both failure paths, the cross-type conversion that is a full creation in disguise, and the hash a dictionary of semantic strings pays on every lookup.

This is a different answer from the quantities one, and worth stating plainly rather than leaving to be inferred from a chart: a quantity's wrapper is free, and a semantic string's is not. What it buys is that an invalid value cannot exist, checked once at the boundary instead of everywhere the value is used.

Paths

<picture> <source media="(prefers-color-scheme: dark)" srcset="docs/benchmarks/paths-performance-dark.svg"> <img alt="Allocated bytes per operation, and time relative to a fixed reference workload, for each Semantics.Paths release" src="docs/benchmarks/paths-performance.svg"> </picture>

Building each kind of path, then operating on one. The two file name panels sit next to each other deliberately: FileNameWithoutExtension caches into a field, FileName rebuilds and revalidates on every read, and both look like field access at a call site.

Architecture

The quantity system is metadata-driven. The single source of truth is Semantics.SourceGenerators/Metadata/dimensions.json (with units.json, magnitudes.json, conversions.json, domains.json, and logarithmic.json alongside it), and a Roslyn incremental generator emits the quantity records, unit-conversion factories, cross-dimensional operators, and physical constants. Generated output is committed to Semantics.Quantities/Generated/ so the project compiles without first running the generator.

The string and path systems share an attribute → strategy → rule → factory validation pipeline. See docs/architecture.md.

Documentation

Per-package API detail lives in each package's own README, linked from the Packages table above.

Contributing

Contributions are welcome. Please open an issue first for major changes so we can discuss the direction. The branch's open work items are tracked as GitHub issues.

License

MIT. See LICENSE.md.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.4.3 0 9/21/2026
5.4.2 42 9/18/2026
5.4.1 57 9/17/2026
5.4.0 60 9/17/2026
5.3.4 88 9/16/2026
5.3.3 79 9/16/2026
5.3.2 79 9/16/2026
5.3.1 79 9/15/2026
5.3.0 87 9/14/2026
5.2.4 93 9/14/2026
5.2.3 90 9/14/2026
5.2.2 88 9/14/2026
5.2.1 95 9/13/2026
5.2.0 96 9/13/2026
5.1.0 89 9/13/2026
5.0.1 92 9/13/2026
5.0.0 89 9/12/2026
4.3.2 97 9/12/2026
4.3.1 83 9/12/2026
4.3.0 98 9/12/2026
Loading failed

## v5.4.2 (patch)

Changes since v5.4.1:

- Merge main into the strings and paths benchmark work ([@matt-edmondson](https://github.com/matt-edmondson))
- Fix whole-branch review findings in benchmark docs [patch] ([@matt-edmondson](https://github.com/matt-edmondson))
- Fix review findings: bullet count and heading nesting ([@matt-edmondson](https://github.com/matt-edmondson))
- Document the strings and paths benchmarks [patch] ([@matt-edmondson](https://github.com/matt-edmondson))
- Backfill the strings and paths histories ([@matt-edmondson](https://github.com/matt-edmondson))
- Seed the strings and paths histories at 5.3.4 ([@matt-edmondson](https://github.com/matt-edmondson))
- Record what the validation ladder actually measured ([@matt-edmondson](https://github.com/matt-edmondson))
- Redirect stdin from /dev/null in the subject loops ([@matt-edmondson](https://github.com/matt-edmondson))
- Measure three subjects per run ([@matt-edmondson](https://github.com/matt-edmondson))
- Fix strings XML doc to describe HashCode, not CompareTo ([@matt-edmondson](https://github.com/matt-edmondson))
- Describe the panel the strings chart actually draws ([@matt-edmondson](https://github.com/matt-edmondson))
- Explain the Create ratio's outlier size in the source, not just the report ([@matt-edmondson](https://github.com/matt-edmondson))
- Draw the strings and paths charts ([@matt-edmondson](https://github.com/matt-edmondson))
- Pair the path types against System.IO.Path ([@matt-edmondson](https://github.com/matt-edmondson))
- Declare the relative path specimen as a const ([@matt-edmondson](https://github.com/matt-edmondson))
- Make RelativeFile a const, not a suppressed readonly field ([@matt-edmondson](https://github.com/matt-edmondson))
- Measure the path types, building and operating ([@matt-edmondson](https://github.com/matt-edmondson))
- Fix Ordering baseline to match the culture-sensitive comparison it pairs against ([@matt-edmondson](https://github.com/matt-edmondson))
- Compare like with like in the string ordering pair ([@matt-edmondson](https://github.com/matt-edmondson))
- Pair the string types against hand-written validation ([@matt-edmondson](https://github.com/matt-edmondson))
- Chart GetHashCode rather than CompareTo for strings ([@matt-edmondson](https://github.com/matt-edmondson))
- Measure a semantic string after it exists ([@matt-edmondson](https://github.com/matt-edmondson))
- Correct the expected cost of the two string failure paths ([@matt-edmondson](https://github.com/matt-edmondson))
- Measure creating a semantic string across the validation ladder ([@matt-edmondson](https://github.com/matt-edmondson))
- Make the release chart renderer subject-aware ([@matt-edmondson](https://github.com/matt-edmondson))
- Plan the strings and paths benchmark work ([@matt-edmondson](https://github.com/matt-edmondson))
- Design the benchmark history and charts for strings and paths ([@matt-edmondson](https://github.com/matt-edmondson))