ActivityPub Viewer

A small tool to view real-world ActivityPub objects as JSON! Enter a URL or username from Mastodon or a similar service below, and we'll send a request with the right Accept header to the server to view the underlying object.

Open in browser →
{ "@context": [ "https://www.w3.org/ns/activitystreams", { "ostatus": "http://ostatus.org#", "atomUri": "ostatus:atomUri", "inReplyToAtomUri": "ostatus:inReplyToAtomUri", "conversation": "ostatus:conversation", "sensitive": "as:sensitive", "toot": "http://joinmastodon.org/ns#", "votersCount": "toot:votersCount", "litepub": "http://litepub.social/ns#", "directMessage": "litepub:directMessage", "Hashtag": "as:Hashtag" } ], "id": "https://infosec.exchange/users/david_chisnall/statuses/113491875237258631", "type": "Note", "summary": null, "inReplyTo": null, "published": "2024-11-16T09:16:24Z", "url": "https://infosec.exchange/@david_chisnall/113491875237258631", "attributedTo": "https://infosec.exchange/users/david_chisnall", "to": [ "https://www.w3.org/ns/activitystreams#Public" ], "cc": [ "https://infosec.exchange/users/david_chisnall/followers" ], "sensitive": false, "atomUri": "https://infosec.exchange/users/david_chisnall/statuses/113491875237258631", "inReplyToAtomUri": null, "conversation": "tag:infosec.exchange,2024-11-16:objectId=213612970:objectType=Conversation", "content": "<p>Okay, I finally understand the <a href=\"https://infosec.exchange/tags/cpp\" class=\"mention hashtag\" rel=\"tag\">#<span>cpp</span></a> contracts proposal. It <em>is</em> possible to implement, it’s just not possible to implement in a way that’s useful. I am even more convinced that adding P2900 to C++26 would be actively harmful than I previously was. If it does get in, I would strongly recommend that you don’t use it.</p><p>First, I learned that ‘zero cost’ when contracts are disabled does not mean ‘things will not get slower in a sensible implementation’, it means ‘no extra steps will be executed in the C++ abstract machine’. This is practically tautological, because obviously things have no overhead <em>in the abstract machine</em> when they are not executed.</p><p>Second, the proposal allows contracts to be checked or ignored (not the only options, but the problems arise from executed or not executed, finer divisions within the ‘executed’ space are less problematic) as a compile-time option. One of the main arguments why we need contracts is that macro (or <code>if constexpr</code> / template) assertions are ODR violations if you link two implementations together, one with the checks enabled and one with them disabled. With P2900, this is not the case, but not in any useful way. It is implementation-defined what happens, and so the most likely outcome is that these will be COMDATs with the ‘any’ merging policy (the only one ELF linkers support), meaning that you will get a random version and, within the C++ abstract machine, have no way of reasoning about the behaviour. Practically, this means that you either globally enable contract checking or you globally disable it if you want to understand what your program is going to do when you execute it. Conveniently, if you’re doing this then constexpr-based checks introduce no ODR violations, so contracts provide nothing of value here.</p><p>Oh, and this makes some existing optimisations unsound. If you have a function in a COMDAT that starts with a null check and call it from a call site that also does a null check, it is currently sound to elide the guard in the caller. This is safe because it’s an ODR violation (and therefore undefined behaviour) if the linker discards your version of the COMDAT and replaces it with one that does not do the null check. If that null check came from a contract check, it is now valid for the linker replace it with one that does not do the checking. This means compilers now need to differentiate between things that analysis can see across function boundaries based on whether they came from contracts.</p><p>The paper also says that contracts can be disabled at link or run time, which I thought was impossible to implement as zero cost, until I learned that ‘zero cost’ meant ‘with a slowdown of unbounded size as long as it is not visible in a semantic model that excludes a notion of time’. So that’s fine, but it will be slow and I doubt anyone will want to enable the option to toggle it at run time in production builds. I’m not sure if toolchains will even bother implementing it, given that it will require a lot of code duplication (which will make builds much slower and I haven’t heard anyone complain that C++ compile times were too small) and come with a lot of downsides.</p><p>And, of course, the latter is not something usefully under your control because there is a <em>single global toggle</em> for whether contracts are enabled. Every assertion framework I’ve used (or implemented) that postdates C99 lets you turn on checks per subsystem (with the definition of ‘subsystem’ left to the user, can be a single function) so that you don’t need to pay the costs of expensive checks in someone else’s code while checking yours (or you can if it’s adding extra checks for API misuse, but skip their internal consistency checks). Not so with P2900, it’s either on or off. So if you want pre and post conditions and assertions you’re back to implementing them the same way we have for the last decade or so: templated wrappers that take a <code>bool</code> that’s default initialised to a <code>constexpr</code> global and perform check in the true overload and not in the false one, before and after calling the implementation (for pre and post condition checks) and <code>if constexpr</code> on the same Boolean (often with a wrapper) for invariants.</p><p>Oh, and there’s a single global handler. Because everyone loved Visual Basic’s <code>ON ERROR</code> so much. Want to handle failures in third-party code one way and failures in your own code differently? Sorry, contracts are not for you.</p><p>I admit to being predisposed to dislike contracts. To me, they embody a style of programming that I thought we’d moved on from a decade or so ago. Good modern code tries to make invalid states unrepresentable, it doesn’t define YOLO interfaces and then crash if you did the wrong thing, I see things that people propose for contracts as two categories:</p><ul><li>Things that can be statically checked and expressed via a type system. The quantities and units proposal will add a bunch of nice standard-library tools for these. Concepts made a lot of these things better. These move you close to a world where ‘it compiles’ and ‘it is correct’ are the same (you’ll never get quite there, but you can get a lot closer). Contracts do not help at all here.</li><li>Things that may happen dynamically in a way that should be recoverable. These should be handled and functions should return option types, throw exceptions, or report errors in some other way that lets callers handle the error gracefully. Oh, and the fact that contract checks can be ignored means that you now need to write these checks twice if you actually want to handle them because you can’t rely on contract checks being run.</li></ul><p>The third case, where contracts are potentially useful, are internal consistency checks. Something has gone wrong somewhere: it’s detectable but not recoverable. There are places where this is necessary, but the goal should be to minimise these, not build language features that treat them as normal.</p><p>There are some really nice features coming up that make life easier for people trying to write correct code in C++. My favourite (okay, second favourite. Quantities and Units has some problems but it’s <em>so</em> close to being really nice and I expect it to get there in a few revisions) is the compile-time formatting of strings that will let you build nice static-assert messages. This, in combination with <code>consteval</code>, makes it possible to write wrapper types that do compile-time checks and report nice error messages when they fail, or fall back to dynamic checks if they are not constructed from constants. This makes it possible to add a load of Ada-like features purely in libraries, without needing language support.</p><p>So what does P2900 actually give us? Not much:</p><ul><li>A very limited form of function decorator. I would actually support a paper to add function decorators to C++, and with the reflection support that I expect to see in C++26 it would be possible to build a <em>really</em> nice library for preconditions and postconditions on top of such a thing.</li><li>A thing where some forms of ODR violations are weakened from undefined to implementation-defined behaviour, in a way that blocks some optimisations and is hard to reason about for programmers.</li><li>Some other things that are optional and no one really knows how to implement yet.</li></ul><p>It’s not the worst proposal up for consideration (that honour goes to Fibres) but it’s a close second.</p>", "contentMap": { "en": "<p>Okay, I finally understand the <a href=\"https://infosec.exchange/tags/cpp\" class=\"mention hashtag\" rel=\"tag\">#<span>cpp</span></a> contracts proposal. It <em>is</em> possible to implement, it’s just not possible to implement in a way that’s useful. I am even more convinced that adding P2900 to C++26 would be actively harmful than I previously was. If it does get in, I would strongly recommend that you don’t use it.</p><p>First, I learned that ‘zero cost’ when contracts are disabled does not mean ‘things will not get slower in a sensible implementation’, it means ‘no extra steps will be executed in the C++ abstract machine’. This is practically tautological, because obviously things have no overhead <em>in the abstract machine</em> when they are not executed.</p><p>Second, the proposal allows contracts to be checked or ignored (not the only options, but the problems arise from executed or not executed, finer divisions within the ‘executed’ space are less problematic) as a compile-time option. One of the main arguments why we need contracts is that macro (or <code>if constexpr</code> / template) assertions are ODR violations if you link two implementations together, one with the checks enabled and one with them disabled. With P2900, this is not the case, but not in any useful way. It is implementation-defined what happens, and so the most likely outcome is that these will be COMDATs with the ‘any’ merging policy (the only one ELF linkers support), meaning that you will get a random version and, within the C++ abstract machine, have no way of reasoning about the behaviour. Practically, this means that you either globally enable contract checking or you globally disable it if you want to understand what your program is going to do when you execute it. Conveniently, if you’re doing this then constexpr-based checks introduce no ODR violations, so contracts provide nothing of value here.</p><p>Oh, and this makes some existing optimisations unsound. If you have a function in a COMDAT that starts with a null check and call it from a call site that also does a null check, it is currently sound to elide the guard in the caller. This is safe because it’s an ODR violation (and therefore undefined behaviour) if the linker discards your version of the COMDAT and replaces it with one that does not do the null check. If that null check came from a contract check, it is now valid for the linker replace it with one that does not do the checking. This means compilers now need to differentiate between things that analysis can see across function boundaries based on whether they came from contracts.</p><p>The paper also says that contracts can be disabled at link or run time, which I thought was impossible to implement as zero cost, until I learned that ‘zero cost’ meant ‘with a slowdown of unbounded size as long as it is not visible in a semantic model that excludes a notion of time’. So that’s fine, but it will be slow and I doubt anyone will want to enable the option to toggle it at run time in production builds. I’m not sure if toolchains will even bother implementing it, given that it will require a lot of code duplication (which will make builds much slower and I haven’t heard anyone complain that C++ compile times were too small) and come with a lot of downsides.</p><p>And, of course, the latter is not something usefully under your control because there is a <em>single global toggle</em> for whether contracts are enabled. Every assertion framework I’ve used (or implemented) that postdates C99 lets you turn on checks per subsystem (with the definition of ‘subsystem’ left to the user, can be a single function) so that you don’t need to pay the costs of expensive checks in someone else’s code while checking yours (or you can if it’s adding extra checks for API misuse, but skip their internal consistency checks). Not so with P2900, it’s either on or off. So if you want pre and post conditions and assertions you’re back to implementing them the same way we have for the last decade or so: templated wrappers that take a <code>bool</code> that’s default initialised to a <code>constexpr</code> global and perform check in the true overload and not in the false one, before and after calling the implementation (for pre and post condition checks) and <code>if constexpr</code> on the same Boolean (often with a wrapper) for invariants.</p><p>Oh, and there’s a single global handler. Because everyone loved Visual Basic’s <code>ON ERROR</code> so much. Want to handle failures in third-party code one way and failures in your own code differently? Sorry, contracts are not for you.</p><p>I admit to being predisposed to dislike contracts. To me, they embody a style of programming that I thought we’d moved on from a decade or so ago. Good modern code tries to make invalid states unrepresentable, it doesn’t define YOLO interfaces and then crash if you did the wrong thing, I see things that people propose for contracts as two categories:</p><ul><li>Things that can be statically checked and expressed via a type system. The quantities and units proposal will add a bunch of nice standard-library tools for these. Concepts made a lot of these things better. These move you close to a world where ‘it compiles’ and ‘it is correct’ are the same (you’ll never get quite there, but you can get a lot closer). Contracts do not help at all here.</li><li>Things that may happen dynamically in a way that should be recoverable. These should be handled and functions should return option types, throw exceptions, or report errors in some other way that lets callers handle the error gracefully. Oh, and the fact that contract checks can be ignored means that you now need to write these checks twice if you actually want to handle them because you can’t rely on contract checks being run.</li></ul><p>The third case, where contracts are potentially useful, are internal consistency checks. Something has gone wrong somewhere: it’s detectable but not recoverable. There are places where this is necessary, but the goal should be to minimise these, not build language features that treat them as normal.</p><p>There are some really nice features coming up that make life easier for people trying to write correct code in C++. My favourite (okay, second favourite. Quantities and Units has some problems but it’s <em>so</em> close to being really nice and I expect it to get there in a few revisions) is the compile-time formatting of strings that will let you build nice static-assert messages. This, in combination with <code>consteval</code>, makes it possible to write wrapper types that do compile-time checks and report nice error messages when they fail, or fall back to dynamic checks if they are not constructed from constants. This makes it possible to add a load of Ada-like features purely in libraries, without needing language support.</p><p>So what does P2900 actually give us? Not much:</p><ul><li>A very limited form of function decorator. I would actually support a paper to add function decorators to C++, and with the reflection support that I expect to see in C++26 it would be possible to build a <em>really</em> nice library for preconditions and postconditions on top of such a thing.</li><li>A thing where some forms of ODR violations are weakened from undefined to implementation-defined behaviour, in a way that blocks some optimisations and is hard to reason about for programmers.</li><li>Some other things that are optional and no one really knows how to implement yet.</li></ul><p>It’s not the worst proposal up for consideration (that honour goes to Fibres) but it’s a close second.</p>" }, "attachment": [], "tag": [ { "type": "Hashtag", "href": "https://infosec.exchange/tags/cpp", "name": "#cpp" } ], "replies": { "id": "https://infosec.exchange/users/david_chisnall/statuses/113491875237258631/replies", "type": "Collection", "first": { "type": "CollectionPage", "next": "https://infosec.exchange/users/david_chisnall/statuses/113491875237258631/replies?only_other_accounts=true&page=true", "partOf": "https://infosec.exchange/users/david_chisnall/statuses/113491875237258631/replies", "items": [] } }, "likes": { "id": "https://infosec.exchange/users/david_chisnall/statuses/113491875237258631/likes", "type": "Collection", "totalItems": 16 }, "shares": { "id": "https://infosec.exchange/users/david_chisnall/statuses/113491875237258631/shares", "type": "Collection", "totalItems": 8 } }