惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cisco Blogs
Cyberwarzone
Cyberwarzone
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler
T
Tor Project blog
N
Netflix TechBlog - Medium
C
Cybersecurity and Infrastructure Security Agency CISA
V
Vulnerabilities – Threatpost
V
Visual Studio Blog
GbyAI
GbyAI
PCI Perspectives
PCI Perspectives
D
DataBreaches.Net
Jina AI
Jina AI
H
Heimdal Security Blog
云风的 BLOG
云风的 BLOG
P
Privacy International News Feed
A
About on SuperTechFans
J
Java Code Geeks
美团技术团队
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
News | PayPal Newsroom
有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
博客园 - 司徒正美
C
Check Point Blog
T
Threat Research - Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
宝玉的分享
宝玉的分享
AI
AI
Simon Willison's Weblog
Simon Willison's Weblog
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
Apple Machine Learning Research
Apple Machine Learning Research
Hugging Face - Blog
Hugging Face - Blog
The Last Watchdog
The Last Watchdog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Vercel News
Vercel News
I
InfoQ
阮一峰的网络日志
阮一峰的网络日志
Cisco Talos Blog
Cisco Talos Blog
W
WeLiveSecurity
Hacker News: Ask HN
Hacker News: Ask HN
Recent Commits to openclaw:main
Recent Commits to openclaw:main
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
D
Docker
博客园 - Franky
Security Archives - TechRepublic
Security Archives - TechRepublic

LWN.net comments

tcmalloc's weird hack [LWN.net] Fixed? [LWN.net] mpd [LWN.net] Userspace AX.25 [LWN.net] RIP [LWN.net] My two cents... [LWN.net] pipx [LWN.net] Tragedy [LWN.net] A young man destined for glory [LWN.net] And 'less' won't let you search [LWN.net] A great loss [LWN.net] Sad and shocking news [LWN.net] Easy migration from Clementine [LWN.net] Sad coincidence [LWN.net] GNOME is actually usable thanks to Seth et al [LWN.net] Sad news :( [LWN.net] armhf supports preempt_rt [LWN.net] MusicBrainz accurracy [LWN.net] On open source maintainership [LWN.net] Let's stop here [LWN.net] Not a new thing [LWN.net] uv is indeed great pgmoneta Some comments on this on a Postgres blog feed [LWN.net] uv [LWN.net] going to Debian [LWN.net] Upgrading 64-bit-capable systems to 64-bit kernels? [LWN.net] Free Software foundations Maintainers can wait for code review but not for publish review? A reasonably extreme point of view [LWN.net] Maintaining old code Varieties of filesystems and schedulers, so why not for IPC mechanisms too? [LWN.net] AI and documentation [LWN.net] Delegating the work to a subsidiary [LWN.net] Maybe they should provide their reviews to the world [LWN.net] Something can be a bug but not a vulnerability [LWN.net] History is a little backwards ... [LWN.net] A reasonably extreme point of view [LWN.net] Let’s stop here [LWN.net] authd [LWN.net] Suggestion for bug report [LWN.net] Software pain points for long-term equipment [LWN.net] Wrong direction [LWN.net] mjg59 has lost the plot there [LWN.net] Role of German law in this? [LWN.net] Without beer? [LWN.net] Feels soul destroying [LWN.net] No zswap in Debian cloud kernel [LWN.net] No Beer?!? [LWN.net] The other fam [LWN.net] Thank you Andrew [LWN.net] Brave! [LWN.net] I second the cost factor [LWN.net] cassandra [LWN.net] Proprietary tools [LWN.net] familiar [LWN.net] ... is also staging. [LWN.net] Python package managers [LWN.net] Pour one out for AX.25... [LWN.net] tun/tap? [LWN.net] Another article at gnulinux.ch [LWN.net] Transitive checks [LWN.net] Just execute from stdin [LWN.net] Cross-compile Vacation [LWN.net] Concrete steps toward RFC 3550 (new Range types) You can rip with Windows apps too! Have the tempfile issues raised in the release notes been fixed? onlyoffice tried to add stuff in the fine print, and failed Work w/o publication is not science Removing art like offensive fortunes is a mistake. [LWN.net] De-googling (was Wtf) [LWN.net] I liked pdfmark [LWN.net] Juice then tag [LWN.net] why did PREEMPT_LAZY caused more preemptions than PREEMPT_NONE with THP disabled? [LWN.net] x86-64 was first introduced in 2003 [LWN.net] no memory safety? [LWN.net] False positive identification rate [LWN.net] "Defensive" AI use [LWN.net] LTS release? [LWN.net] ironic (ugly, good) [LWN.net] Moving away from LLVM [LWN.net] ironic (ugly, good) [LWN.net] Abandoning vim(1) ASAP [LWN.net] "Picard" naming [LWN.net] circular reasoning is a potential source of unsoundness [LWN.net] Nice to see an update [LWN.net] Writable THPs [LWN.net] Whole network messages [LWN.net] I'll fix my code ... [LWN.net] Can also recommend beets [LWN.net] Jack the CD ripper [LWN.net] How about the bad CDs? [LWN.net] systemd-boot [LWN.net] Significant raise of reports [LWN.net] IMO, it's appropriate [LWN.net] How about the bad CDs? [LWN.net] Update to include Part 4? [LWN.net] Pandoc also is invauable for a cheap-and-dirty retrieval augmented generation. [LWN.net] Whole network messages [LWN.net]
C++ 26 contracts [LWN.net]
NYKevin · 2026-05-12 · via LWN.net comments

I do like type invariants, but sometimes a contract facility has better ergonomics. If I can't have both I guess I'll take type invariants, but I would prefer both.

C++ 26 contracts

Posted May 12, 2026 17:32 UTC (Tue) by NYKevin (subscriber, #129325) [Link]

One clever (but unfortunately Rust-only) pattern I have discovered is the static enum. It goes like this:

// TODO: Replace Infallible with ! when the latter is stabilized.
use std::convert::Infallible;

pub trait Variant: Sized {
    // Type bounds added for ergonomics, not essential.
    type OnlyLeft: Copy + 'static;
    type OnlyRight: Copy + 'static;
    fn into_left<T, U>(e: Either<Self, T, U>, x: Self::OnlyLeft) -> T;
    fn into_right<T, U>(e: Either<Self, T, U>, x: Self::OnlyRight) -> U;
    fn select<T, U>(t: T, u: U) -> Either<Self, T, U>;
}

pub enum Either<V: Variant, T, U>{
    Left(T, V::OnlyLeft),
    Right(U, V::OnlyRight),
}

pub struct LeftVariant;
pub struct RightVariant;

impl Variant for LeftVariant {
    type OnlyLeft = ();
    type OnlyRight = Infallible;
    fn into_left<T, U>(e: Either<Self, T, U>, _: Self::OnlyLeft) -> T{
        let Either::<Self, T, U>::Left(v, _) = e;
        v
    }
    // TODO: When replacing Infallible with !, we can simplify this to just return x directly.
    fn into_right<T, U>(_: Either<Self, T, U>, x: Self::OnlyRight) -> U{
        match x {}
    }
    fn select<T, U>(t: T, _: U) -> Either<Self, T, U>{
        Either::Left(t, ())
    }
}

impl Variant for RightVariant {
    type OnlyLeft = Infallible;
    type OnlyRight = ();
    fn into_left<T, U>(_: Either<Self, T, U>, x: Self::OnlyLeft) -> T{
        match x {}
    }
    fn into_right<T, U>(e: Either<Self, T, U>, _: Self::OnlyRight) -> U{
        let Either::<Self, T, U>::Right(v, _) = e;
        v
    }
    fn select<T, U>(_: T, u: U) -> Either<Self, T, U>{
        Either::Right(u, ())
    }
}

// Need a macro so that we only evaluate one or the other of t and u. They can both e.g. move
// from the same places, have overlapping mutable borrows, etc.
// XXX: It is somewhat ugly to take a type as an argument. Better syntax would look like this:
// new_either!<V>(t, u).
// But macro_rules! cannot consume that syntax, and proc macros are overkill. Oh well.
macro_rules! new_either{
    ($v:ty, $t:expr, $u:expr) => {
        match <$v as $crate::Variant>::select((), ()) {
            $crate::Either::Left(_, x) => $crate::Either::Left($t, x),
            $crate::Either::Right(_, x) => $crate::Either::Right($u, x),
        }
    }
}

// Either should provide various methods for manipulating its contents, not shown here.
// It should also blanket impl some std traits when T and U impl those traits.

The point is that destructuring an Either instance inside of a match expression will only emit code for the branch that is actually taken. This means that we can write simple and obvious code that looks like a runtime branch, but is actually resolved at compile time. For example, new_either!() is a zero-overhead (branchless) operation despite containing a match with two arms. After monomorphization, one of those arms will always materialize an empty type (as the value of x), and the compiler will regard that as conclusive evidence that the arm is unreachable (or UB).

It also means we can pass around these OnlyLeft and OnlyRight tokens freely to prove which variant is active, and later use the into_left() and into_right() functions as needed. Since the tokens are either ZSTs or empty types, they never emit any code whatsoever.

I suspect, but cannot easily prove, that most or all design-by-contract use cases can be reformulated in terms of ZSTs, empty types, and similar constructs to what I show above. But retrofitting this much type system complexity into C++ is probably not a good idea.