<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-05-03T12:18:43+00:00</updated><id>/feed.xml</id><title type="html">A coding column.</title><subtitle>My personal take on coding, software design and programming languages.</subtitle><entry><title type="html">Euro-Office: Sovereignty Theatre or Real Engineering?</title><link href="/blog/euro-office-sovereignty-theatre-or-real-engineering-2026" rel="alternate" type="text/html" title="Euro-Office: Sovereignty Theatre or Real Engineering?" /><published>2026-05-03T12:02:00+00:00</published><updated>2026-05-03T12:02:00+00:00</updated><id>/blog/euro-office-sovereignty%20theatre-or-real-engineering</id><content type="html" xml:base="/blog/euro-office-sovereignty-theatre-or-real-engineering-2026"><![CDATA[<p>I was genuinely excited when I first heard about Euro-Office. If you’re not deep in the self-hosted ecosystem, a bit of context: for years, anyone running their own cloud storage — typically via Nextcloud or similar platforms — has had two choices for browser-based document editing. Collabora Online, which is essentially LibreOffice running on a server and streaming rendered pages to your browser, is mature and deeply committed to open standards, but carries the weight of a 35-year-old codebase and puts a heavy load on the server. OnlyOffice, developed by Ascensio System SIA (a company with roots in Russia, now registered in Latvia), takes a more modern approach — JavaScript-based, lighter in the browser, with excellent Microsoft format compatibility — but has always been opaque about its development, rarely accepts outside contributions, and has made controversial decisions like disabling mobile editing in its free Community Edition. Neither option has been fully satisfying.</p>

<p>Euro-Office looks like it could break that stalemate: a fork of OnlyOffice’s modern codebase, but under European governance, with genuinely open development. I run my own Nextcloud instance and I’m looking forward to integrating it once it reaches a stable release.</p>

<p>But excitement is cheap. The interesting question is whether the engineering behind Euro-Office is actually solid, or whether this is just sovereignty theatre — a press release with a GitHub link. To find out, I cloned four of Euro-Office’s repositories<sup id="fnref:repos" role="doc-noteref"><a href="#fn:repos" class="footnote" rel="footnote">1</a></sup>, read the documentation and README files, and went through the commit logs line by line. What started as a quick look grew into one of my longest articles yet — there turned out to be a lot to say. What follows is based on that primary-source review, supplemented by the project’s public statements and third-party reporting.</p>

<h2 id="why-this-matters">Why This Matters</h2>

<p>I’ve wanted Europe — and Germany in particular — to become more independent in the IT sector for a long time. Not out of protectionism, but because depending on a handful of US vendors for the most basic tools of daily work — writing a document, editing a spreadsheet, collaborating on a presentation — is a structural vulnerability that can be weaponised at any moment. This isn’t hypothetical: when the Trump administration sanctioned the International Criminal Court, Microsoft shut down the ICC chief prosecutor’s email account<sup id="fnref:tuta-countries" role="doc-noteref"><a href="#fn:tuta-countries" class="footnote" rel="footnote">2</a></sup>. A court based in The Hague, central to Europe’s legal order, lost access to its own communications because a vendor in Redmond flipped a switch. The ICC has since announced it will move to openDesk<sup id="fnref:tuta-countries:1" role="doc-noteref"><a href="#fn:tuta-countries" class="footnote" rel="footnote">2</a></sup>. That incident alone should have been a wake-up call for every European institution still running on US-hosted productivity software.</p>

<p>The legal picture is equally uncomfortable. Under the US CLOUD Act and FISA Section 702, US-controlled cloud providers can be compelled to hand over European data — even if it’s stored on European soil — without notifying the data subject or any European authority<sup id="fnref:fisa" role="doc-noteref"><a href="#fn:fisa" class="footnote" rel="footnote">3</a></sup>. Under oath before the French Senate in June 2025, Microsoft’s legal chief for France admitted that he could not guarantee French data would never be transferred to the US government<sup id="fnref:tuta-sovereignty" role="doc-noteref"><a href="#fn:tuta-sovereignty" class="footnote" rel="footnote">4</a></sup>. The same conclusion has been reached at the EU level: the European Data Protection Supervisor found that the European Commission itself violated its own data protection regulations by using Microsoft 365<sup id="fnref:edps-m365" role="doc-noteref"><a href="#fn:edps-m365" class="footnote" rel="footnote">5</a></sup>.</p>

<p>I have to ask: how is any of this still GDPR-compliant? Microsoft’s own lawyer cannot guarantee that European data stays in Europe. US law explicitly empowers US agencies to access it without European knowledge or consent. The EDPS has found the Commission itself in violation. And yet Microsoft 365 remains the default across most of European government and industry. Did no one pick this up? Or are we simply too dependent — too scared — to act on what we already know?</p>

<p>It seems, though, that the tide is finally turning. On 18 March 2026, Germany’s IT-Planungsrat — the federal-state coordination body for government IT — adopted the Deutschland-Stack decision (B-2026/03-IT)<sup id="fnref:itpr" role="doc-noteref"><a href="#fn:itpr" class="footnote" rel="footnote">6</a></sup>, which defines binding standards for all federal, state, and municipal digital infrastructure. The accompanying standards annex explicitly lists ODF (Open Document Format) and PDF/UA as mandatory document formats<sup id="fnref:itpr-standards" role="doc-noteref"><a href="#fn:itpr-standards" class="footnote" rel="footnote">7</a></sup>. This isn’t a suggestion; it’s a binding resolution across all levels of German government.</p>

<p>Within Germany, the movement started at the state level. Schleswig-Holstein — the northernmost Bundesland — has migrated 80% of its 30,000 government workplaces to Linux and LibreOffice, and expects to save over €15 million in licence fees that would otherwise go to Microsoft’s upcoming price increases<sup id="fnref:tuta-countries:2" role="doc-noteref"><a href="#fn:tuta-countries" class="footnote" rel="footnote">2</a></sup>. With the Deutschland-Stack decision, that ambition has now reached the federal level as binding policy for all of Bund, Länder, and Kommunen.</p>

<p>But this is no longer just a German story. Denmark’s Ministry of Digital Affairs has announced that all its employees will work with Linux and LibreOffice instead of Microsoft<sup id="fnref:tuta-countries:3" role="doc-noteref"><a href="#fn:tuta-countries" class="footnote" rel="footnote">2</a></sup>. France, following the Senate testimony, announced in April 2026 that it would replace Microsoft on all government desktops with Linux<sup id="fnref:tuta-sovereignty:1" role="doc-noteref"><a href="#fn:tuta-sovereignty" class="footnote" rel="footnote">4</a></sup>. The Netherlands’ municipality of Amsterdam has published a ten-year Digital Autonomy Strategy targeting full sovereignty by 2035<sup id="fnref:tuta-countries:4" role="doc-noteref"><a href="#fn:tuta-countries" class="footnote" rel="footnote">2</a></sup>. Austria has launched its own sovereignty initiative under the Digital Austria Act 2.0<sup id="fnref:tuta-countries:5" role="doc-noteref"><a href="#fn:tuta-countries" class="footnote" rel="footnote">2</a></sup>. And at the EU level, the European Commission awarded a €180 million tender for sovereign cloud services to European companies<sup id="fnref:eurofocus" role="doc-noteref"><a href="#fn:eurofocus" class="footnote" rel="footnote">8</a></sup>. As Thierry Carrez, general manager of Linux Foundation Europe, put it at KubeCon Europe 2026, the sovereignty conversation is now “happening at all levels of the stack”<sup id="fnref:register" role="doc-noteref"><a href="#fn:register" class="footnote" rel="footnote">9</a></sup>.</p>

<p>What was once a personal conviction is now a procurement requirement — and that means there’s suddenly real demand for a credible European office suite that can actually deliver.</p>

<h2 id="what-euro-office-is">What Euro-Office Is</h2>

<p>Euro-Office was announced on 27 March 2026 at a press event in Berlin<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">10</a></sup>. It is a fork of OnlyOffice — specifically of OnlyOffice’s AGPL-licensed document editing engine — placed under European governance and open development. The coalition chose to fork OnlyOffice rather than build on LibreOffice/Collabora, explicitly citing OnlyOffice’s more modern architecture and superior browser performance compared to LibreOffice’s aging codebase<sup id="fnref:9" role="doc-noteref"><a href="#fn:9" class="footnote" rel="footnote">11</a></sup>.</p>

<p>The backing coalition is substantive: IONOS, Nextcloud, XWiki, OpenProject, Soverin, Abilian, BTactic, and EuroStack<sup id="fnref:7:1" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">10</a></sup>. Proton is also involved<sup id="fnref:8" role="doc-noteref"><a href="#fn:8" class="footnote" rel="footnote">12</a></sup>. Both IONOS and Nextcloud have committed to hiring double-digit numbers of developers each for Euro-Office<sup id="fnref:9:1" role="doc-noteref"><a href="#fn:9" class="footnote" rel="footnote">11</a></sup>. That represents serious, sustained funding — not a press-release-and-forget play.</p>

<p>Architecturally, Euro-Office is an integration component, not a standalone product. It handles document editing — word processing, spreadsheets, presentations, and PDF — but storage, navigation, permissions, and sharing must be provided by a host platform: Nextcloud Hub, Proton Drive, Seafile, XWiki, OpenProject, or others<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">13</a></sup>. The fact that it works independently of Nextcloud<sup id="fnref:12" role="doc-noteref"><a href="#fn:12" class="footnote" rel="footnote">14</a></sup> is important: it means the project isn’t captive to a single integrator’s roadmap.</p>

<p>As of the 22 April update, the project has a published roadmap, a governance model, and a contribution process<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">15</a></sup>. The governance follows a “who codes, decides” principle with consensus-based decision-making among project members<sup id="fnref:6:1" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">15</a></sup>. Regular contributors are added by consensus after sustained contribution (roughly 3–6 merged PRs over a few months). A Code of Conduct based on the Contributor Covenant is in place<sup id="fnref:2:1" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">13</a></sup>. This is lightweight, but appropriate for the current stage — formalising too early kills momentum in young open-source projects.</p>

<p>So: real companies, real money, real governance. A published roadmap with a stable 1.0 targeted for summer 2026<sup id="fnref:11" role="doc-noteref"><a href="#fn:11" class="footnote" rel="footnote">16</a></sup>. But roadmaps are cheap too. The question is whether the actual engineering matches the ambition — and whether the project can navigate the political noise that has surrounded it since launch.</p>

<h2 id="the-licence-dispute-briefly">The Licence Dispute, Briefly</h2>

<p>Unfortunately, the waters around Euro-Office have been muddied by a licensing dispute with OnlyOffice that has attracted more attention than the actual engineering.</p>

<p>OnlyOffice is licensed under the GNU Affero General Public License v3 (AGPLv3), which explicitly grants the right to fork, modify, and redistribute. OnlyOffice has, however, added an additional clause under Section 7 §3(b) requiring preservation of their branding and logos. This is where the dispute lies.</p>

<p>Euro-Office’s position is that they are attributing correctly. The Ascensio credit appears in the theming config, in the codebase, and on the About screens for both desktop and mobile — the engineering details are covered in the theming section below<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">17</a></sup>. Nextcloud has published a detailed legal analysis arguing that the Section 7 additions are non-obligatory under the AGPL<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">18</a></sup>. The Euro-Office community has also published a detailed account of the changes they’ve made to ensure licence compliance, including restoring mobile editing that OnlyOffice had artificially disabled and cleaning up the DesktopEditors dual-licence to pure AGPLv3<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">19</a></sup>.</p>

<p>OnlyOffice disputes this. They have publicly stated that Euro-Office constitutes “an evident and material violation of ONLYOFFICE licensing terms”<sup id="fnref:oo-neowin" role="doc-noteref"><a href="#fn:oo-neowin" class="footnote" rel="footnote">20</a></sup> and suspended their eight-year partnership with Nextcloud over the fork<sup id="fnref:oo-neowin:1" role="doc-noteref"><a href="#fn:oo-neowin" class="footnote" rel="footnote">20</a></sup>. They argue that the additional branding terms cannot be separated from the main licence.</p>

<p>I am not a lawyer and cannot judge the legal merits of either side. What I can say is that from my limited understanding, Euro-Office appears to be making a good-faith effort to properly attribute: the Ascensio credit is in the code, in the config, and on the About screens. The AGPL grants forking rights. Whether the Section 7 branding clause survives a fork is ultimately a legal question that may or may not be tested in court. But the fork itself is not a violation of open-source norms — it <em>is</em> the norm. That’s how the AGPL works.</p>

<p>Enough about lawyers. Let’s look at the code.</p>

<h2 id="what-the-commit-log-shows">What the Commit Log Shows</h2>

<p>The GitHub organisation hosts ~15 repositories covering the full stack<sup id="fnref:2:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">13</a></sup>: DocumentServer (orchestration, Docker builds, CI), core (C++ conversion engine), sdkjs (JavaScript editing SDK), web-apps (frontend UI), a Nextcloud integration app, DesktopEditors, desktop-apps, and supporting repos for dictionaries, fonts, document formats, and templates. A working Docker image is available<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">21</a></sup>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker pull ghcr.io/euro-office/documentserver:latest
</code></pre></div></div>

<p>This is a deployable document server, not a placeholder. The DocumentServer repo alone has over 300 commits on <code class="language-plaintext highlighter-rouge">main</code>. All key repos show commit activity through late April / early May 2026.</p>

<p>The commit log reveals several distinct work streams, each visible as clusters of commits.</p>

<h3 id="1-automated-licence-stripping-documentserver-26-march">1. Automated Licence Stripping (DocumentServer, 26 March)</h3>

<p>The single largest cluster of early commits — at least ten — built a GitHub Actions workflow that automatically strips the AGPL Section 7(b) trademark clause from all copyright headers after upstream merges (<code class="language-plaintext highlighter-rouge">a0f7c65</code>, <code class="language-plaintext highlighter-rouge">ca65168</code>, <code class="language-plaintext highlighter-rouge">5674745</code>, <code class="language-plaintext highlighter-rouge">1a14462</code>, among others). The iteration is telling: they refined edge cases around blank-line handling, commit message formatting, a check-mode-first safety step, and making the merge optional. A revert (<code class="language-plaintext highlighter-rouge">6c0d308</code>) and subsequent re-approach shows real engineering discipline — they broke something, backed out, and fixed it properly.</p>

<p>This is the foundational infrastructure for staying mergeable with upstream while maintaining their own licence posture. Getting it right early was the correct priority.</p>

<h3 id="2-build-system-overhaul-documentserver--core-2831-march">2. Build System Overhaul (DocumentServer + core, 28–31 March)</h3>

<p>The C++ dependency management was switched from Conan to vcpkg (<code class="language-plaintext highlighter-rouge">7873c20</code>). Docker builds were restructured around <code class="language-plaintext highlighter-rouge">docker buildx bake</code> for reproducible multi-stage builds (<code class="language-plaintext highlighter-rouge">f04a1a4</code>). A <code class="language-plaintext highlighter-rouge">.deb</code>/<code class="language-plaintext highlighter-rouge">.rpm</code> packaging pipeline was added (<code class="language-plaintext highlighter-rouge">8136765</code>, <code class="language-plaintext highlighter-rouge">9bbd9f7</code>), along with Vagrant VMs for Ubuntu 24.04, Debian 12, and Rocky Linux 9 to smoke-test produced packages<sup id="fnref:builddir" role="doc-noteref"><a href="#fn:builddir" class="footnote" rel="footnote">22</a></sup>. There are numerous fix commits wrestling with registry URLs, caching, and workflow files (<code class="language-plaintext highlighter-rouge">b6992c9</code>, <code class="language-plaintext highlighter-rouge">71168a4</code>, <code class="language-plaintext highlighter-rouge">dcc0114</code>, among others) — classic “getting CI green” work that anyone who has set up a non-trivial build pipeline will recognise.</p>

<p>OnlyOffice’s build process was one of the core grievances that motivated the fork: their README describes it as “unreliable, outdated or just plain broken”<sup id="fnref:2:3" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">13</a></sup>, with binary blobs and compiled/obfuscated code. The commit log shows Euro-Office is doing the work to fix this systematically.</p>

<h3 id="3-arm64-support-core-31-march--2-april">3. ARM64 Support (core, 31 March – 2 April)</h3>

<p>V8 and Boost were rebuilt for ARM64 (<code class="language-plaintext highlighter-rouge">1725c2b</code>). Emscripten was updated for ARM compatibility (<code class="language-plaintext highlighter-rouge">5057738</code>). Architecture-aware vcpkg triplets were introduced (<code class="language-plaintext highlighter-rouge">f320bdf</code>). The web-apps build skips <code class="language-plaintext highlighter-rouge">imagemin</code> on ARM64 since its native binaries are x86_64-only<sup id="fnref:devdir" role="doc-noteref"><a href="#fn:devdir" class="footnote" rel="footnote">23</a></sup>. There is no GHCR ARM64 image yet — ARM users must build locally — but the groundwork is laid.</p>

<h3 id="4-wasm--emscripten-core-28-march--16-april">4. WASM / Emscripten (core, 28 March – 16 April)</h3>

<p>Multiple commits address WebAssembly builds: fixes to DrawingFile and general layout (<code class="language-plaintext highlighter-rouge">52518f8</code>), the V8 build process (<code class="language-plaintext highlighter-rouge">ad832ca</code>), and a notable fix deferring FreeType function bindings until <code class="language-plaintext highlighter-rouge">onRuntimeInitialized</code> (<code class="language-plaintext highlighter-rouge">146975f</code>). This is browser-side rendering work. If mature, it would reduce the heavy server-side load that has always been Collabora Online’s architectural weakness — and it would be a significant differentiator.</p>

<h3 id="5-rebranding-and-theming-web-apps-19-march--22-april">5. Rebranding and Theming (web-apps, 19 March – 22 April)</h3>

<p>Icons were shifted from PNG to SVG (<code class="language-plaintext highlighter-rouge">5cd4c4e</code>, <code class="language-plaintext highlighter-rouge">d863b5b</code>, <code class="language-plaintext highlighter-rouge">3c81545</code>), including dark-theme variants. A theming system was introduced with <code class="language-plaintext highlighter-rouge">config.json</code> as single source of truth for brand values<sup id="fnref:5:1" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">17</a></sup> — company name, publisher URLs, logo filenames, and an attribution line reading <code class="language-plaintext highlighter-rouge">"Euro-Office was based on ONLYOFFICE by Ascensio System SIA"</code>. Two build pipelines consume the theme: Grunt for desktop (using `` token replacement) and webpack for mobile (using <code class="language-plaintext highlighter-rouge">DefinePlugin</code> constants and LESS globalVars). Hard-coded relative paths in build JSON files were replaced with a <code class="language-plaintext highlighter-rouge">$BUILD_ROOT</code> variable so the build works regardless of checkout location<sup id="fnref:5:2" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">17</a></sup>. About screens were updated with Euro-Office logos and Ascensio attribution on both desktop and mobile (<code class="language-plaintext highlighter-rouge">a8dd610</code>, <code class="language-plaintext highlighter-rouge">fbd8acc</code>, <code class="language-plaintext highlighter-rouge">4d5e670</code>, <code class="language-plaintext highlighter-rouge">cfdf091</code>).</p>

<p>This is proper fork infrastructure — making the codebase brandable and buildable by anyone, not just the original vendor.</p>

<h3 id="6-nextcloud-integration-modernisation-eurooffice-nextcloud-28-february--27-april">6. Nextcloud Integration Modernisation (eurooffice-nextcloud, 28 February – 27 April)</h3>

<p>This repo reveals that preparation started a full month before the public announcement. In late February, the frontend build was migrated from webpack to Vite (<code class="language-plaintext highlighter-rouge">c83a59b</code>), Vue and <code class="language-plaintext highlighter-rouge">@nextcloud/vue</code> were updated to v3+ (<code class="language-plaintext highlighter-rouge">323f6ac</code>), and raw-loader was removed (<code class="language-plaintext highlighter-rouge">ed84cc0</code>). In early March, a PHP refactoring pass improved type coverage (<code class="language-plaintext highlighter-rouge">272c9b1</code>), converted switch statements to match expressions (<code class="language-plaintext highlighter-rouge">414b549</code>), and removed redundant use statements (<code class="language-plaintext highlighter-rouge">ad68ba6</code>). PHP 8.4.x support was extended (<code class="language-plaintext highlighter-rouge">909d027</code>). Bug fixes addressed regex metacharacter escaping in MIME type handling (<code class="language-plaintext highlighter-rouge">e182df8</code>), file lookup error handling (<code class="language-plaintext highlighter-rouge">6c8114b</code>), and user ID prefix stripping (<code class="language-plaintext highlighter-rouge">09e6dc9</code>). Rebranding and repackaging for krankerl (Nextcloud app store tooling) followed on 26 March (<code class="language-plaintext highlighter-rouge">8131218</code>, <code class="language-plaintext highlighter-rouge">8de6d6d</code>, <code class="language-plaintext highlighter-rouge">cc4ac99</code>).</p>

<p>This was not a spontaneous fork. The Nextcloud integration was being quietly modernised and prepared for weeks before the Berlin launch.</p>

<h3 id="7-upstream-sync-web-apps-1017-march">7. Upstream Sync (web-apps, 10–17 March)</h3>

<p>Two merge commits pull in OnlyOffice upstream changes from December 2025 (<code class="language-plaintext highlighter-rouge">868b36a</code>) and March 2026 (<code class="language-plaintext highlighter-rouge">39110cb</code>). An upstream CI file that attempted to use AWS was removed (<code class="language-plaintext highlighter-rouge">022e602</code>). This confirms active tracking of upstream — they’re not just forking and walking away.</p>

<h3 id="8-mobile-dev-workflow-documentserver-1721-april">8. Mobile Dev Workflow (DocumentServer, 17–21 April)</h3>

<p>Mobile dev mode was made independent (<code class="language-plaintext highlighter-rouge">0e075de</code>). Trusted domains were updated for Android development (<code class="language-plaintext highlighter-rouge">d624d5f</code>, <code class="language-plaintext highlighter-rouge">e134fcb</code>). A <code class="language-plaintext highlighter-rouge">make mobile</code> target was added with automatic LAN IP detection for off-desktop testing<sup id="fnref:devdir:1" role="doc-noteref"><a href="#fn:devdir" class="footnote" rel="footnote">23</a></sup>. Documentation was updated accordingly (<code class="language-plaintext highlighter-rouge">2b18260</code>).</p>

<h3 id="9-governance-and-contribution-docs-documentserver-2022-april">9. Governance and Contribution Docs (DocumentServer, 20–22 April)</h3>

<p>CONTRIBUTING.md was written and refined across multiple commits (<code class="language-plaintext highlighter-rouge">598141c</code>, <code class="language-plaintext highlighter-rouge">fdb545b</code>, <code class="language-plaintext highlighter-rouge">4d3145d</code>, <code class="language-plaintext highlighter-rouge">5e4e087</code>). A CODEOWNERS file was added for the server team (<code class="language-plaintext highlighter-rouge">9540d86</code>). An attributions file was introduced (<code class="language-plaintext highlighter-rouge">e6b9bf8</code>). Coding guidelines were published.</p>

<h3 id="10-testing-core-1-april">10. Testing (core, 1 April)</h3>

<p>An ODT conversion test snapshot was updated for Japanese AIUEO numbering format (<code class="language-plaintext highlighter-rouge">03fcc6a</code>) — evidence that automated conversion and rendering tests are being maintained, not just inherited and ignored.</p>

<h2 id="assessment">Assessment</h2>

<p>Five weeks in, for a fork of a complex codebase, this is about as good as you could reasonably hope for. The commit log tells the story of a team doing the right things in the right order: licence automation first, build reproducibility second, ARM and WASM groundwork third, branding and theming fourth, governance and contribution docs fifth. The Nextcloud integration work predating the public launch by a month shows planning, not improvisation. The stable 1.0 is targeted for summer 2026<sup id="fnref:11:1" role="doc-noteref"><a href="#fn:11" class="footnote" rel="footnote">16</a></sup> — and given they’re building on a mature, already-functional codebase rather than starting from scratch, the timeline is plausible, though “summer” is doing some heavy lifting.</p>

<p>That said, several open questions will determine whether Euro-Office becomes a serious contender or just another well-intentioned European initiative that fizzles out.</p>

<p><strong>ODF as native format.</strong> The Document Foundation published a pointed response noting that the original Euro-Office press release didn’t mention ODF even once<sup id="fnref:10" role="doc-noteref"><a href="#fn:10" class="footnote" rel="footnote">24</a></sup>, and asking whether ODF will be the native format. That’s a legitimate architectural question: if Euro-Office inherits OnlyOffice’s OOXML-first posture, it’s sovereign in governance but still format-dependent on Microsoft’s specification. As discussed above, the Deutschland-Stack standards already mandate ODF for all German government IT<sup id="fnref:itpr-standards:1" role="doc-noteref"><a href="#fn:itpr-standards" class="footnote" rel="footnote">7</a></sup> — any office suite that wants to serve the European public sector needs ODF not just as a supported export option, but as a first-class citizen. The latest Nextcloud update lists “full ODF support” as a roadmap priority<sup id="fnref:6:2" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">15</a></sup>, which suggests they heard the criticism. But whether ODF becomes the <em>native</em> default or just a well-supported secondary format is an open question that will matter for procurement decisions across Europe.</p>

<p><strong>Upstream tracking vs. divergence.</strong> The commit log shows two upstream merges from OnlyOffice so far — December 2025 and March 2026 changes pulled into web-apps. That’s a healthy sign early on. But as Euro-Office accumulates its own changes — the theming system, the build overhaul, the licence stripping automation — merging upstream will get progressively harder. At some point, they’ll need to decide whether to track upstream closely or diverge intentionally. Both are viable strategies, but the choice will shape the project’s long-term character.</p>

<p><strong>Governance scaling.</strong> The current “who codes, decides” model works for a founding coalition of a dozen organisations. It won’t work at fifty. As the contributor base grows — and it will need to grow if the project is to deliver on its ambitions — the governance will need to formalise without becoming bureaucratic. The early signs are positive (CONTRIBUTING.md, CODEOWNERS, Code of Conduct), but this is a problem that only gets harder with success.</p>

<p><strong>WASM maturity.</strong> The browser-side rendering work via WebAssembly is potentially the most significant technical differentiator Euro-Office could offer. If the WASM path matures, it would shift rendering from the server to the client — fundamentally changing the economics of deployment and addressing Collabora’s biggest architectural weakness. The commit log shows active work here, but it’s clearly still early.</p>

<p>The commit log doesn’t resolve these questions. But it does show that real engineers are doing real work, with real money behind them, and that the work so far has been competent and well-prioritised. That’s more than most forks can show at five weeks.</p>

<p>What makes me genuinely hopeful is not just Euro-Office itself, but what it represents. For years, European digital sovereignty has been something people talked about at conferences and wrote into strategy papers, but the actual tools lagged behind the rhetoric. Now, for the first time, there’s a concrete, funded, technically credible effort to build an office suite that Europe can truly call its own — not just in governance, but in code. If Euro-Office delivers on its promise, it won’t just be a replacement for one piece of software. It will be a proof of concept that Europe can build and maintain critical digital infrastructure independently, from the document layer all the way up. That’s the real prize.</p>

<p>I’ll be revisiting this when 1.0 lands — and I’ll be hoping to deploy it on my own Nextcloud shortly after.</p>

<hr />

<p><em>Methodology: Repositories were cloned on 3 May 2026 using <code class="language-plaintext highlighter-rouge">git clone --depth</code> (30–100 commits per repo). I reviewed the commit messages, dates, and authors — not the actual source code diffs. For each commit, I categorised it by topic (licence stripping, build system, ARM64, WASM, theming, etc.), then summarised the topic clusters into the work streams described above. README files, build documentation (<code class="language-plaintext highlighter-rouge">build/</code>), and developer documentation (<code class="language-plaintext highlighter-rouge">develop/</code>) were read directly from the cloned repositories. External sources were consulted for coalition, governance, and roadmap context.</em></p>

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:repos" role="doc-endnote">
      <p>Repositories cloned: <code class="language-plaintext highlighter-rouge">Euro-Office/DocumentServer</code>, <code class="language-plaintext highlighter-rouge">Euro-Office/web-apps</code>, <code class="language-plaintext highlighter-rouge">Euro-Office/core</code>, <code class="language-plaintext highlighter-rouge">Euro-Office/eurooffice-nextcloud</code>. All available at https://github.com/Euro-Office <a href="#fnref:repos" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:tuta-countries" role="doc-endnote">
      <p>Tuta, “France ditches Microsoft for Linux to achieve digital sovereignty — and it’s not the only one!” April 2026. https://tuta.com/blog/countries-ditching-microsoft-choosing-linux-digital-sovereignty <a href="#fnref:tuta-countries" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:tuta-countries:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a> <a href="#fnref:tuta-countries:2" class="reversefootnote" role="doc-backlink">&#8617;<sup>3</sup></a> <a href="#fnref:tuta-countries:3" class="reversefootnote" role="doc-backlink">&#8617;<sup>4</sup></a> <a href="#fnref:tuta-countries:4" class="reversefootnote" role="doc-backlink">&#8617;<sup>5</sup></a> <a href="#fnref:tuta-countries:5" class="reversefootnote" role="doc-backlink">&#8617;<sup>6</sup></a></p>
    </li>
    <li id="fn:fisa" role="doc-endnote">
      <p>SoftwareSeni, “How the US CLOUD Act and FISA 702 Create Legal Exposure for EU Cloud Data,” 27 February 2026. https://www.softwareseni.com/how-the-us-cloud-act-and-fisa-702-create-legal-exposure-for-eu-cloud-data/ <a href="#fnref:fisa" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:tuta-sovereignty" role="doc-endnote">
      <p>Tuta, “What is digital sovereignty — and how Microsoft sparked the trend,” March 2026. https://tuta.com/blog/digital-sovereignty-europe <a href="#fnref:tuta-sovereignty" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:tuta-sovereignty:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:edps-m365" role="doc-endnote">
      <p>European Data Protection Supervisor, investigation into use of Microsoft 365 by the European Commission, March 2024. https://www.edps.europa.eu/system/files/2024-03/24-03-08-edps-investigation-ec-microsoft365_en.pdf <a href="#fnref:edps-m365" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:itpr" role="doc-endnote">
      <p>IT-Planungsrat, Beschluss B-2026/03-IT — Deutschland-Stack, 49. Sitzung, 18 March 2026. https://www.it-planungsrat.de/beschluss/b-2026-03-it <a href="#fnref:itpr" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:itpr-standards" role="doc-endnote">
      <p>IT-Planungsrat, Anlage Standards zum Beschluss B-2026/03-IT, 18 March 2026. https://www.it-planungsrat.de/fileadmin/beschluesse/2026/Beschluss_2026_03_Deutschland-Stack_Standards.pdf <a href="#fnref:itpr-standards" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:itpr-standards:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:eurofocus" role="doc-endnote">
      <p>Europe Focus, “The EU turns to ‘Made in Europe’ tech solutions,” April 2026. https://www.europefocus.eu/the-eu-turns-to-made-in-europe-tech-solutions/ <a href="#fnref:eurofocus" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:register" role="doc-endnote">
      <p>The Register, “Digital sovereignty isn’t just a buzzword — it’s the future,” 13 April 2026. https://www.theregister.com/2026/04/13/digital_sovereignty/ <a href="#fnref:register" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:7" role="doc-endnote">
      <p>Nextcloud, “Industry initiative launches Euro-Office as true sovereign office suite,” 27 March 2026. https://nextcloud.com/blog/press_releases/industry-initiative-launches-euro-office-as-true-sovereign-office-suite/ <a href="#fnref:7" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:7:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:9" role="doc-endnote">
      <p>heise online, “Microsoft alternative: Nextcloud and Ionos develop open-source ‘Euro-Office’,” 27 March 2026. https://www.heise.de/en/news/Microsoft-alternative-Nextcloud-and-Ionos-develop-open-source-Euro-Office-11228123.html <a href="#fnref:9" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:9:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:8" role="doc-endnote">
      <p>TechSpot, “A new OnlyOffice fork is Europe’s answer to Microsoft Office,” April 2026. https://www.techspot.com/news/111952-new-onlyoffice-fork-europe-answer-microsoft-office.html <a href="#fnref:8" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Euro-Office GitHub organisation, profile README. https://github.com/Euro-Office <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:2:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a> <a href="#fnref:2:2" class="reversefootnote" role="doc-backlink">&#8617;<sup>3</sup></a> <a href="#fnref:2:3" class="reversefootnote" role="doc-backlink">&#8617;<sup>4</sup></a></p>
    </li>
    <li id="fn:12" role="doc-endnote">
      <p>DB Tech Reviews, “Euro-Office Doesn’t Need Nextcloud — And That Changes Everything,” 8 April 2026. https://dbtechreviews.com/2026/04/08/euro-office-doesnt-need-nextcloud-and-that-changes-everything/ <a href="#fnref:12" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:6" role="doc-endnote">
      <p>Nextcloud, “Euro-Office: Building momentum,” 22 April 2026. https://nextcloud.com/blog/euro-office-building-momentum/ <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:6:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a> <a href="#fnref:6:2" class="reversefootnote" role="doc-backlink">&#8617;<sup>3</sup></a></p>
    </li>
    <li id="fn:11" role="doc-endnote">
      <p>Sovereign Cloud Architecture Initiative, “Euro-Office,” 1 April 2026. https://yeandel.co.uk/22-q2-2026-updates/euro-office.html <a href="#fnref:11" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:11:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p>Euro-Office web-apps repository (theming config and build variable documentation). https://github.com/Euro-Office/web-apps <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:5:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a> <a href="#fnref:5:2" class="reversefootnote" role="doc-backlink">&#8617;<sup>3</sup></a></p>
    </li>
    <li id="fn:1" role="doc-endnote">
      <p>Nextcloud, “Euro-Office: License compliance and what open source means,” 22 April 2026. https://nextcloud.com/blog/euro-office-license-compliance-and-what-open-source-means/ <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p>Issue #3645 on ONLYOFFICE/DocumentServer, “Euro-Office: A fully FOSS fork of ONLYOFFICE — join us on Codeberg,” 2 April 2026. https://github.com/ONLYOFFICE/DocumentServer/issues/3645 <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:oo-neowin" role="doc-endnote">
      <p>Neowin, “ONLYOFFICE suspends Nextcloud partnership over unapproved ‘Euro-Office’ fork,” 1 April 2026. https://www.neowin.net/news/onlyoffice-suspends-nextcloud-partnership-over-unapproved-euro-office-fork/ <a href="#fnref:oo-neowin" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:oo-neowin:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p>Euro-Office DocumentServer repository. https://github.com/Euro-Office/DocumentServer <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:builddir" role="doc-endnote">
      <p>Euro-Office DocumentServer build documentation. https://github.com/Euro-Office/DocumentServer/tree/main/build <a href="#fnref:builddir" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:devdir" role="doc-endnote">
      <p>Euro-Office DocumentServer develop documentation. https://github.com/Euro-Office/DocumentServer/tree/main/develop <a href="#fnref:devdir" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:devdir:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:10" role="doc-endnote">
      <p>The Document Foundation Community Blog, “Euro-Office: sovereign in name only, or in reality too?” 1 April 2026. https://blog.documentfoundation.org/blog/2026/04/01/euro-office/ <a href="#fnref:10" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Sebastian Teumert</name></author><category term="Open Source" /><category term="euro-office" /><category term="sovereignty" /><category term="data-sovereignty" /><category term="open-source" /><category term="office" /><category term="nextcloud" /><category term="gdpr" /><category term="odf" /><category term="regulation" /><category term="politics" /><category term="eu" /><category term="us" /><summary type="html"><![CDATA[I was genuinely excited when I first heard about Euro-Office. If you’re not deep in the self-hosted ecosystem, a bit of context: for years, anyone running their own cloud storage — typically via Nextcloud or similar platforms — has had two choices for browser-based document editing. Collabora Online, which is essentially LibreOffice running on a server and streaming rendered pages to your browser, is mature and deeply committed to open standards, but carries the weight of a 35-year-old codebase and puts a heavy load on the server. OnlyOffice, developed by Ascensio System SIA (a company with roots in Russia, now registered in Latvia), takes a more modern approach — JavaScript-based, lighter in the browser, with excellent Microsoft format compatibility — but has always been opaque about its development, rarely accepts outside contributions, and has made controversial decisions like disabling mobile editing in its free Community Edition. Neither option has been fully satisfying.]]></summary></entry><entry><title type="html">Quo vadis? LLMs for AI-assisted code copilots</title><link href="/blog/quo-vadis-llms-ai-code-copilot-2023" rel="alternate" type="text/html" title="Quo vadis? LLMs for AI-assisted code copilots" /><published>2023-11-05T14:09:00+00:00</published><updated>2023-11-05T14:09:00+00:00</updated><id>/blog/quo-vadis-llms-ai-code-copilot</id><content type="html" xml:base="/blog/quo-vadis-llms-ai-code-copilot-2023"><![CDATA[<p>Over the course of the decades, programming has seen major shifts in how the craft is performed. Where people wrote on punch cards which were then sewn into core memory by hand, there was not much in terms of automated assistance. By now, modern IDEs have long provided code completion and can give smart suggestions as to what a software developer might want to do. CI/CD pipelines and automated tests nowadays quickly verify the correctness of the given code (at least to a certain degree).</p>

<p>We currently see another big shift in how software is written unfolding before our eyes. AI-assisted code co-piloting is the newest variation of automation and code-completion that is aimed at making software development easier. Compared to traditional approaches, which used static analysis and the languages scoping rules together with hand-crafted templates, these tools leverage the power of Large Language Models (LLMs) which have been fine-tuned to provide code completion. A major contender in this space is <a href="https://github.com/features/copilot">GitHub Copilot</a>.</p>

<p>In this article, I wish to review a couple of research papers of the last three years to highlight the chances, but also the risks of those technologies and ask: Quo vadis? Where will the field of software development head in the near future, and what do we need to take care of so that this becomes a success story and not a gigantic money pit?</p>

<p>There are three papers in the last few years that truly stand out, and together form a somewhat concerning view on the wide-spread use of AI to write computer-assisted code. The three papers are</p>

<ul>
  <li><a href="https://arxiv.org/abs/1910.14374">Existence of Stack Overflow Vulnerabilities in Well-known Open Source Projects</a> (2019) by Md. Masudur Rahman and B M Mainul Hossain <sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">1</a></sup></li>
  <li><a href="https://arxiv.org/abs/2211.03622">Do Users Write More Insecure Code with AI Assistants?</a> (2022) by Neil Perry, Megha Srivastava, Deepak Kumar and Dan Boneh <sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">2</a></sup></li>
  <li><a href="https://arxiv.org/abs/2305.17493">The Curse of Recursion: Training on Generated Data Makes Models Forget</a> (2023) by Ilia Shumailov, Zakhar Shumaylov, Yiren Zhao, Yarin Gal, Nicolas Papernot and Ross Anderson <sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">3</a></sup></li>
</ul>

<p>Lets begin with the second paper <sup id="fnref:3:1" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">2</a></sup>, which posits the question “Do Users Write More Insecure Code with AI Assistants?”. Unfortunately, the paper can be summarized with a single word: Yes. But it also highlights some more truly concerning facts about AI and LLMs.</p>

<p>Current research on verification of LLMs has led to the notion of “trustworthy AI” and “explainable AI”. The thought was that with explanations, LLMs can become more than just black-boxes that we somehow have to trust to give us the right answers. Being neural networks (NNs), LLMs are just probabilistic models that produce <em>plausible</em> text. They have no notion of <em>knowledge</em> or <em>correctness</em> and can give hilariously wrong results that <em>sound plausible</em>. Especially with ChatGPT, there is a great danger in being overly confident in the output, because ChatGPT is trained to be <em>conversational</em> in tone, but also <em>confident</em> in what it says. Common wisdom under professionals nowadays is to only use LLMs like ChatGPT when one is able to <em>verify</em> the correctness of the output. That this is needed and warranted is highlighted by the very study quoted above. But lets dig into that a bit more, and look at why even getting <em>good explanations</em> cannot increase the confidence in the AI or make AI systems trustworthy.</p>

<p>What the study shows is that humans tend to be more critical of explanations if they <em>perceive</em> themselves as being knowledgeable of a topic, even to the point of being <em>overly</em> critic and not trusting the explanation. However, the study also shows that the less knowledgeable humans are about a topic, the more likely they are to trust any given explanation – even if that explanation is completely and utterly wrong. The study is fascinating in how they generated and presented these fake explanations and how those were received by non-experts (in this case, they used pictures of bids and their classification as well as three groups of people – professional ornithologists, hobby bird watchers and people without any background in birds). In my opinion, this leads to the very interesting possibility of an <em>explanation attack</em>, where LLMs might be trained to maliciously give wrong explanations and guide users towards actions they would otherwise not have undertaken.</p>

<p>Thus, we see that not even <em>explainable</em> AI might be enough to ensure good quality of the code or make the AI trustworthy. But lets assume for a moment that the AI is <em>trustworthy</em> in the sense that is has not been manipulated, but is actually trained to make a best effort to provide high-quality code along with explanations of this code. How does it get the training data?</p>

<p>Lets face it, most code out there in the real world isn’t of the highest quality, most is just average, and as much code below average as above average. Training a model on the real code that is out there will just give us average results. So lets identify high-quality code along with good explanations of the code and train it on that. Stack Overflow has become the <em>de-facto</em> source of information for professional software developers and hobbyists alike, with about 21 millions questions already asked and most of them answered. As of Sept. 2023, during the week it has about 6k - 7.5k questions asked <em>per day</em> and goes down to about 4k on the weekend, highlighting the fact that it is much used by professionals during their work week <sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">4</a></sup>. Suffice to say, SO is an influential source for professional software developers.</p>

<p>However, it is not free of errors. In fact, if we look at the first paper <sup id="fnref:4:1" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">1</a></sup>, we can see that there are several highly ranked questions that do have security issues. These are widely copied over into open-source libraries, and it stands to reason that this flawed code has also found entry into many closed-source / proprietary computer programs.</p>

<p>This highlights two important issues, especially together with the study quoted above: First, explanations are not enough even when they are provided, since they might come flawed sources. Even when the LLM were to provide n explanation that is sourced from SO, that code and explanation might very well be flawed as well. <strong>Automating this process likely increases the velocity with which those security flaws spread</strong> even more. It will also cement the code that is written today as the de-facto standard way of writing code in the future and significantly slow down the speed at which old, outdated practices are phased out. Although I do not like the term <a href="https://en.wikipedia.org/wiki/Cargo_cult_programming">“cargo-cult programming”</a>, the Wikipedia article for it aptly describes the problem of blindly following patterns and copying them without understanding why and where they might be appropriate, creating code that is deeply flawed in the process. We have already seen the problem prior to the advent of AI-assisted code copiloting, and there is a high likelihood that AI suggestions are all too often applied too eagerly without understanding if they are appropriate in that context.</p>

<p>This leads us to the last paper and the important question of how we get rid of those patterns, how we develop new ways to write code and how we can still drive <strong>innovation</strong> and novel paradigms to write code in when faced with a high degree of automation and large amounts of code that are written with the assistance of AI code copilots?</p>

<p>And it doesn’t look good that that front, either.</p>

<p>The last study I cited <sup id="fnref:2:1" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">3</a></sup> shows that there is what they call a “model collapse” when re-training LLMs on their own outputs, i.e. code generated by themselves as part of an code-copilot. The capabilities of LLMS diminish the more they are trained on their own outputs, making genuine human inputs to retrain them on invaluable for the future. But the problem is that text written by LLMs cannot reliably be distinguished from text written by humans. Unless there is a major theoretical breakthrough, this means that with higher and higher adoption levels of AI-assisted code-copilots, more and more inputs to these systems will likely be AI generated, unless one starts the painstaking process of curating code and text that is verifiably written by humans alone.</p>

<p>The authors write “[…] over time we start losing information about the true distribution, which first starts with tails disappearing, and over the generations learned behaviours start converging to a point estimate with very small variance. Furthermore, we show that this process is inevitable, even for cases with almost ideal conditions for long-term learning i.e. no function estimation error. […] Finally, we discuss the broader implications of model collapse. We note that access to the original data distribution is crucial: in learning where the tails of the underlying distribution matter, one needs access to real human-produced data. In other words, the use of LLMs at scale to publish content on the Internet will pollute the collection of data to train them: data about human interactions with LLMs will be increasingly valuable.”<sup id="fnref:2:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">3</a></sup></p>

<p>The details of the study do not matter much in the context of this blog article, but the above paragraphs should give rising concern as to where we are heading in terms of future LLMs.</p>

<h2 id="conclusion">Conclusion</h2>

<p>So where are we headed in the next 5-20 years? Honestly, I don’t know. At least in Europe, there is an increasing demand for regulation of software development because the economic damages of software failures and security holes skyrocket. Thus far, we as a field haven’t done a good job at pro-actively design those regulations, with much of the industry being very much against it. AI offers great increases in productivity, but also comes with additional demand on verification and quality assurance. Thus far, adoption rates far outpace the speed at which we can learn to responsibly use these technologies and mitigate their short-term and long-term impacts. There is already talk about AI regulation, driven mainly by economists and law-makers, and we computer scientists and also software developers need to make sure out voices are heard in order to ensure that the regulation we will eventually get is reasonable and sound and does increase software quality and security, and doesn’t just cost a lot of money in paperwork and cover-your-ass actions.</p>

<p>We should also be wary were software development as a whole is headed, how we still drive innovation and make sure AI assisted code-copilots are a sustainable, safe and high-quality tool hat is able to stick around for a long time. This will involve better quality assurance of those tools as well as strategies for innovation and re-training of these models to allow programming to still evolve in the future and not approach a fixed point.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:4" role="doc-endnote">
      <p><a href="https://arxiv.org/abs/1910.14374">Existence of Stack Overflow Vulnerabilities in Well-known Open Source Projects</a> (2019) by Md. Masudur Rahman and B M Mainul Hossain <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:4:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://arxiv.org/abs/2211.03622">Do Users Write More Insecure Code with AI Assistants?</a> (2022) by Neil Perry, Megha Srivastava, Deepak Kumar and Dan Boneh <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:3:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://arxiv.org/abs/2305.17493">The Curse of Recursion: Training on Generated Data Makes Models Forget</a> (2023) by Ilia Shumailov, Zakhar Shumaylov, Yiren Zhao, Yarin Gal, Nicolas Papernot and Ross Anderson <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:2:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a> <a href="#fnref:2:2" class="reversefootnote" role="doc-backlink">&#8617;<sup>3</sup></a></p>
    </li>
    <li id="fn:1" role="doc-endnote">
      <p>https://sostats.github.io/last30days/ <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Sebastian Teumert</name></author><category term="AI" /><category term="AI" /><category term="LLM" /><category term="copilot" /><category term="research" /><summary type="html"><![CDATA[Over the course of the decades, programming has seen major shifts in how the craft is performed. Where people wrote on punch cards which were then sewn into core memory by hand, there was not much in terms of automated assistance. By now, modern IDEs have long provided code completion and can give smart suggestions as to what a software developer might want to do. CI/CD pipelines and automated tests nowadays quickly verify the correctness of the given code (at least to a certain degree).]]></summary></entry><entry><title type="html">Record#with - a thought experiment</title><link href="/blog/record-with-a-thought-experiment-2020" rel="alternate" type="text/html" title="Record#with - a thought experiment" /><published>2020-06-07T14:22:00+00:00</published><updated>2020-06-07T14:22:00+00:00</updated><id>/blog/record-with-a-thought-experiment</id><content type="html" xml:base="/blog/record-with-a-thought-experiment-2020"><![CDATA[<p>Recently, there were some interesting discussions about <code class="language-plaintext highlighter-rouge">Record#copy()</code> and <code class="language-plaintext highlighter-rouge">Record#with(...)</code> on the <code class="language-plaintext highlighter-rouge">amber-spec-experts</code>
mailing list (<a href="https://mail.openjdk.java.net/pipermail/amber-spec-experts/2020-May/002217.html">1</a>, <a href="https://mail.openjdk.java.net/pipermail/amber-spec-experts/2020-May/002221.html">2</a>) which has lead me to implement both methods with a very clear &amp; typesafe way, which I’d like to 
discuss below. The code demonstrated below is available as <a href="https://gist.github.com/NetzwergX/4ebba8ea36d0663f2a540d0f71f16e49">Gist</a>.</p>

<p>What led me to start this experiment was the following quote:</p>

<blockquote>
  <p>the idea is to add a method <code class="language-plaintext highlighter-rouge">Record with(Object... componentValuePairs)</code> in <code class="language-plaintext highlighter-rouge">java.lang.Record</code>, and ask the 
compiler to verify that the even arguments (0, 2, 4, etc) are constant strings</p>

  <p>Proposed syntax:</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var otherPerson = person.with("name", "John", "age", 17);
</code></pre></div>  </div>
</blockquote>

<p>I thought this <em>had</em> to be easier and be possible in a typesafe way. So here is my suggestion:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var otherPerson = person.with(Person::name, "John").with(Person::age, 17);
</code></pre></div></div>

<p>What do we get? Type saftey. Better, easier to read syntax.</p>

<h1 id="can-we-pull-this-off">Can we pull this off?</h1>

<h2 id="yes">Yes</h2>

<p>It turns out, its actually possible to pull this off just as written there. Yes, <code class="language-plaintext highlighter-rouge">Person::name</code> is an accessor method
and doesn’t allow us to <em>set</em> anything directly - but we already know how the component of the record is called when we
look at that – and we also know the type.</p>

<p>The question is, can we get this information from the lambda? 
<a href="https://stackoverflow.com/a/35223119/1360803">Turns out we can</a>.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * c.f. https://stackoverflow.com/a/35223119/1360803
 */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="nc">SerializedLambda</span> <span class="nf">getSerializedLambda</span><span class="o">(</span><span class="nc">Serializable</span> <span class="n">lambda</span><span class="o">)</span>
		<span class="kd">throws</span> <span class="nc">NoSuchMethodException</span><span class="o">,</span> <span class="nc">SecurityException</span><span class="o">,</span>
		<span class="nc">IllegalAccessException</span><span class="o">,</span> <span class="nc">IllegalArgumentException</span><span class="o">,</span>
		<span class="nc">InvocationTargetException</span> <span class="o">{</span>
	<span class="kd">final</span> <span class="nc">Method</span> <span class="n">method</span> <span class="o">=</span> <span class="n">lambda</span><span class="o">.</span><span class="na">getClass</span><span class="o">()</span>
			<span class="o">.</span><span class="na">getDeclaredMethod</span><span class="o">(</span><span class="s">"writeReplace"</span><span class="o">);</span>
	<span class="n">method</span><span class="o">.</span><span class="na">setAccessible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
	<span class="k">return</span> <span class="o">(</span><span class="nc">SerializedLambda</span><span class="o">)</span> <span class="n">method</span><span class="o">.</span><span class="na">invoke</span><span class="o">(</span><span class="n">lambda</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>We can use this to extract everything we need:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="o">&lt;</span><span class="no">T</span><span class="o">,</span> <span class="no">F</span> <span class="kd">extends</span> <span class="nc">Serializable</span> <span class="o">&amp;</span> <span class="nc">Function</span><span class="o">&lt;</span><span class="no">R</span><span class="o">,</span> <span class="no">T</span><span class="o">&gt;&gt;</span> <span class="kt">void</span> <span class="nf">with</span><span class="o">(</span><span class="no">F</span> <span class="n">param</span><span class="o">)</span> <span class="o">{</span>
	<span class="kt">var</span> <span class="n">lambda</span> <span class="o">=</span> <span class="n">getSerializedLambda</span><span class="o">(</span><span class="n">param</span><span class="o">);</span>
	<span class="kt">var</span> <span class="n">name</span> <span class="o">=</span> <span class="n">lambda</span><span class="o">.</span><span class="na">getImplMethodName</span><span class="o">();</span>
	<span class="kt">var</span> <span class="n">signature</span> <span class="o">=</span> <span class="n">lambda</span><span class="o">.</span><span class="na">getImplMethodSignature</span><span class="o">();</span>
	<span class="c1">// get descriptor, strip () of input</span>
	<span class="kt">var</span> <span class="n">typeDescriptor</span> <span class="o">=</span> <span class="n">signature</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="n">signature</span><span class="o">.</span><span class="na">length</span><span class="o">());</span>
	<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">name</span> <span class="o">+</span> <span class="s">":"</span> <span class="o">+</span> <span class="n">typeDescriptor</span><span class="o">);</span>
	<span class="c1">// if we call this with with(Person::name), we get `name:Ljava/lang/String;`</span>
<span class="o">}</span>
</code></pre></div></div>

<p>We get the type signature and the name of the accessor method, which is the same as the field. We strip the <code class="language-plaintext highlighter-rouge">()</code> from
the method signature to get the return type.</p>

<p>Putting it all together, we get this nice method:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
<span class="kd">public</span> <span class="k">default</span> <span class="o">&lt;</span><span class="no">T</span><span class="o">,</span> <span class="no">F</span> <span class="kd">extends</span> <span class="nc">Serializable</span> <span class="o">&amp;</span> <span class="nc">Function</span><span class="o">&lt;</span><span class="no">R</span><span class="o">,</span> <span class="no">T</span><span class="o">&gt;&gt;</span> <span class="no">R</span> <span class="nf">with</span><span class="o">(</span><span class="no">F</span> <span class="n">param</span><span class="o">,</span> <span class="no">T</span> <span class="n">val</span><span class="o">)</span> <span class="o">{</span>
	<span class="k">try</span> <span class="o">{</span>
		<span class="c1">// get name &amp; type of the changing parameter</span>
		<span class="kt">var</span> <span class="n">lambda</span> <span class="o">=</span> <span class="n">getSerializedLambda</span><span class="o">(</span><span class="n">param</span><span class="o">);</span>
		<span class="kt">var</span> <span class="n">name</span> <span class="o">=</span> <span class="n">lambda</span><span class="o">.</span><span class="na">getImplMethodName</span><span class="o">();</span>
		<span class="kt">var</span> <span class="n">signature</span> <span class="o">=</span> <span class="n">lambda</span><span class="o">.</span><span class="na">getImplMethodSignature</span><span class="o">();</span>
		<span class="c1">// get descriptor, strip () of input</span>
		<span class="kt">var</span> <span class="n">typeDescriptor</span> <span class="o">=</span> <span class="n">signature</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="n">signature</span><span class="o">.</span><span class="na">length</span><span class="o">());</span>

		<span class="c1">// get record components &amp; replace the value</span>
		<span class="kt">var</span> <span class="n">components</span> <span class="o">=</span> <span class="n">getClass</span><span class="o">().</span><span class="na">getRecordComponents</span><span class="o">();</span>
		<span class="kt">var</span> <span class="n">params</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Object</span><span class="o">[</span><span class="n">components</span><span class="o">.</span><span class="na">length</span><span class="o">];</span>
		<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">components</span><span class="o">.</span><span class="na">length</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
			<span class="kt">var</span> <span class="n">component</span> <span class="o">=</span> <span class="n">components</span><span class="o">[</span><span class="n">i</span><span class="o">];</span>
			<span class="k">if</span> <span class="o">(</span><span class="n">isCompatible</span><span class="o">(</span><span class="n">component</span><span class="o">,</span> <span class="n">name</span><span class="o">,</span> <span class="n">typeDescriptor</span><span class="o">))</span>
				<span class="n">params</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">val</span><span class="o">;</span>
			<span class="k">else</span> <span class="o">{</span>
				<span class="n">params</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">component</span><span class="o">.</span><span class="na">getAccessor</span><span class="o">().</span><span class="na">invoke</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
				<span class="c1">// accessor might modify data, so circumvent accessor</span>
				<span class="c1">// but records don't expose their fields :(</span>
				<span class="c1">//params[i] = getClass().getField(component.getName()).get(this);</span>
			<span class="o">}</span>
		<span class="o">}</span>
		<span class="c1">// create new record</span>
		<span class="k">return</span> <span class="o">(</span><span class="no">R</span><span class="o">)</span> <span class="n">getClass</span><span class="o">().</span><span class="na">getConstructors</span><span class="o">()[</span><span class="mi">0</span><span class="o">].</span><span class="na">newInstance</span><span class="o">(</span><span class="n">params</span><span class="o">);</span>
	<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchMethodException</span> <span class="o">|</span> <span class="nc">SecurityException</span>
			<span class="o">|</span> <span class="nc">IllegalAccessException</span> <span class="o">|</span> <span class="nc">IllegalArgumentException</span>
			<span class="o">|</span> <span class="nc">InvocationTargetException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
		<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
	<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">InstantiationException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
		<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
	<span class="o">}</span> <span class="cm">/*catch (NoSuchFieldException e) {
		throw new RuntimeException(e);
	}*/</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The full code is available as <a href="https://gist.github.com/NetzwergX/4ebba8ea36d0663f2a540d0f71f16e49">Gist</a>. I’ve created an interface with this method as only default method, which
can be implemented by any record.</p>

<p>And it actually works as advertised:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="n">record</span> <span class="nf">Person</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">)</span> <span class="kd">implements</span> <span class="nc">CopyableRecord</span><span class="o">&lt;</span><span class="nc">Person</span><span class="o">&gt;</span> <span class="o">{}</span>

<span class="kt">var</span> <span class="n">guruJava</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Person</span><span class="o">(</span><span class="s">"Brian Goetz"</span><span class="o">);</span>
<span class="kt">var</span> <span class="n">guruCSharp</span> <span class="o">=</span> <span class="n">guruJava</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nl">Person:</span><span class="o">:</span><span class="n">name</span><span class="o">,</span> <span class="s">"Eric Lippert"</span><span class="o">);</span>
</code></pre></div></div>

<h2 id="but-with-a-few-drawbacks">But with a few drawbacks.</h2>

<p>The first and most obvious drawback: This only works with method references like <code class="language-plaintext highlighter-rouge">Person::firstName</code>. Which is fair, I
guess. This doesn’t work:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">original</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Person</span><span class="o">(</span><span class="s">"Brian"</span><span class="o">,</span> <span class="s">"Goetz"</span><span class="o">);</span>
<span class="kt">var</span> <span class="n">copy</span> <span class="o">=</span> <span class="n">original</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="n">p</span> <span class="o">-&gt;</span> <span class="n">p</span><span class="o">.</span><span class="na">firstName</span><span class="o">(),</span> <span class="s">"Eric"</span><span class="o">);</span> <span class="c1">// nope</span>
</code></pre></div></div>

<p>In fact, my current implementation silently ignores this (which is ok for a thought experiment, not so much for
production code).</p>

<p>Furthermore, the method I have presented above has a few commented-out lines.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">params</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">component</span><span class="o">.</span><span class="na">getAccessor</span><span class="o">().</span><span class="na">invoke</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="c1">// accessor might modify data, so circumvent accessor</span>
<span class="c1">// but records don't expose their fields :(</span>
<span class="c1">//params[i] = getClass().getField(component.getName()).get(this);</span>
</code></pre></div></div>

<p>These also lead to the commented-out <code class="language-plaintext highlighter-rouge">NoSuchFieldException</code> catch-block.</p>

<p>So whats the problem? Accessors can change the data. I’m not sure it would be a good or often used design feature a 
programmer would <em>want</em> to use to return data that is invalid, instead of just some wrappers around data like 
<code class="language-plaintext highlighter-rouge">Collections#unmodifieableList</code>, but it can happen.</p>

<p>Lets look at an – arguably contrived – example:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="n">record</span> <span class="nf">Doubling</span> <span class="o">(</span><span class="kt">int</span> <span class="n">n</span><span class="o">,</span> <span class="kt">int</span> <span class="n">m</span><span class="o">)</span> <span class="kd">implements</span> <span class="nc">RecordTransform</span><span class="o">&lt;</span><span class="nc">Doubling</span><span class="o">&gt;</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="kt">int</span> <span class="nf">n</span><span class="o">()</span> <span class="o">{</span> <span class="k">return</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">n</span><span class="o">;</span> <span class="o">}</span>
	<span class="kd">public</span> <span class="kt">int</span> <span class="nf">m</span><span class="o">()</span> <span class="o">{</span> <span class="k">return</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">m</span><span class="o">;</span> <span class="o">}</span>
<span class="o">}</span>

<span class="kt">var</span> <span class="n">original</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Doubling</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="mi">3</span><span class="o">);</span> <span class="c1">// Doubling[n=2, m=3]</span>
<span class="kt">var</span> <span class="n">copy</span> <span class="o">=</span> <span class="n">original</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nl">Doubling:</span><span class="o">:</span><span class="n">n</span><span class="o">,</span> <span class="mi">5</span><span class="o">);</span> <span class="c1">// Doubling[n=5, m=6]</span>
</code></pre></div></div>

<p>So yeah. By using the accessor we double the data every time we copy the record.</p>

<h2 id="is-this-really-a-problem">Is this really a problem?</h2>

<p>I’m not so sure. Lets say that we use libraries like ASM to access the underlying fields directly. We can still
trivially easy break copying:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="n">record</span> <span class="nf">Doubling</span> <span class="o">(</span><span class="kt">int</span> <span class="n">n</span><span class="o">,</span> <span class="kt">int</span> <span class="n">m</span><span class="o">)</span> <span class="kd">implements</span> <span class="nc">RecordTransform</span><span class="o">&lt;</span><span class="nc">Doubling</span><span class="o">&gt;</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nc">Doubling</span> <span class="o">{</span>
		<span class="n">n</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">n</span><span class="o">;</span>
		<span class="n">m</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">m</span><span class="o">;</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>If we copy the value of the fields, we still double them every time. And circumventing the constructor seems to be a
<em>bad</em> idea. If someone wants to alter drastically different data in the accessor or mutate it this way in their 
constructors, why net let them? Sure, copying then has side-effects that might be surprising on the first glance, but
are actually quite logical on second glance.</p>

<p>Whats actually more upsetting in my opinion is that <code class="language-plaintext highlighter-rouge">Record#toString</code> doesn’t use the accessor methods and thus
displays values you can never extract from the record. It will be interesting to see how that plays out with 
deconstruction patterns.<br />
If you implement a DoublingRecord like above, what do you expect to happen when you the following?</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">original</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Doubling</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="mi">3</span><span class="o">);</span>
<span class="n">let</span> <span class="nf">Doubling</span><span class="o">(</span><span class="kt">int</span> <span class="n">m</span><span class="o">,</span> <span class="kt">int</span> <span class="n">n</span><span class="o">)</span> <span class="o">=</span> <span class="n">original</span><span class="o">;</span>
<span class="kt">var</span> <span class="n">copy</span> <span class="o">=</span> <span class="nc">Doubling</span><span class="o">(</span><span class="n">m</span><span class="o">,</span> <span class="n">n</span><span class="o">);</span>
</code></pre></div></div>

<p>The problems you are facing with a <code class="language-plaintext highlighter-rouge">Record#with</code> or <code class="language-plaintext highlighter-rouge">Record#copy</code> method are exactly the same that emerge when talking
about deconstruction. Whatever solution is chosen for deconstruction will also be applicable for those both methods.</p>

<p><small>Personally, I’d think this is a non-issue. If someone wants to implement their records that way, let them and
let them deal with the fallout themselves.</small></p>

<p>My point is: If I’m able to pull this off, I’m sure the Java architects will find a way to implement
<code class="language-plaintext highlighter-rouge">Record#with</code> in a much better way than by using strings to look up values and completely circumventing the type system.
It can be done inside the type system, with type safety &amp; compiler support, and probably a lot more elegant than what
I’ve cobbled up here.</p>

<p><strong>Disclaimer</strong></p>

<p>This is a thought experiment. Do not use this in production. I’ve not benchmarked it, it doesn’t use
<code class="language-plaintext highlighter-rouge">MethodHandle</code>/<code class="language-plaintext highlighter-rouge">VarHandle</code> and is probably not suitable en masse.</p>]]></content><author><name>Sebastian Teumert</name></author><category term="Java" /><category term="Project Amber" /><category term="Records" /><summary type="html"><![CDATA[Recently, there were some interesting discussions about Record#copy() and Record#with(...) on the amber-spec-experts mailing list (1, 2) which has lead me to implement both methods with a very clear &amp; typesafe way, which I’d like to discuss below. The code demonstrated below is available as Gist.]]></summary></entry><entry><title type="html">Use Jekyll on Windows via the Subsystem for Linux (WSL)</title><link href="/blog/use-jekyll-on-windows-via-the-subsystem-for-linux-wsl-2020" rel="alternate" type="text/html" title="Use Jekyll on Windows via the Subsystem for Linux (WSL)" /><published>2020-05-21T19:36:00+00:00</published><updated>2020-05-21T19:36:00+00:00</updated><id>/blog/use-jekyll-on-windows-via-the-subsystem-for-linux-wsl</id><content type="html" xml:base="/blog/use-jekyll-on-windows-via-the-subsystem-for-linux-wsl-2020"><![CDATA[<p>The Windows Subsystem for Linux works surprisingly well by now – at least for simple tasks. In this blog post, I describe how to install the WSL as well as Jekyll (with GitHub Pages support) using Ubuntu as the distro of choice. Installing the WSL and a Linux distro is suprisingly easy and has only 4 steps (one is optional).</p>

<p>The official Jekyll Documentation a section on this <a href="https://jekyllrb.com/docs/installation/windows/#installation-via-bash-on-windows-10">“Jekyll on Windows”</a>, but unfortunately I found the information therein to be outdated.</p>

<ol>
  <li><strong>Activate Windows Subsystem</strong>
In order to install the subsystem, you’ll need to open a PowerShell window and type in the following:
<code class="language-plaintext highlighter-rouge">&gt; Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux</code></li>
  <li><strong>Install a distro</strong>
Visit the <a href="https://aka.ms/wslstore">Microsoft Store page for Linux Distros</a> and choose a distro. For the sake of this blog post, I’ll use Ubuntu.</li>
  <li>Run <code class="language-plaintext highlighter-rouge">sudo apt update &amp;&amp; sudo apt upgrade</code></li>
  <li><span class="badge">Optional</span> Activate <kbd>Ctrl+<b>Shift</b>+V</kbd> &amp; <kbd>Ctrl+<b>Shift</b>+C</kbd> via <code class="language-plaintext highlighter-rouge">RMB (Mouse) &gt; Properties &gt; Options (Tab) &gt; Use Ctrl+Shift+C/V as Copy/Paste</code></li>
  <li>Run <code class="language-plaintext highlighter-rouge">$ lsb_release -a</code>, which should print:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04 LTS
Release:        20.04
Codename:       focal
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="jekyll">Jekyll</h2>

<p>If you have read the aforementioned documentation page of Jekyll, you’ll have found this part:</p>

<blockquote>
  <p>Now we can install Ruby. To do this we will use a repository from BrightBox, which hosts optimized versions of Ruby for Ubuntu.</p>
</blockquote>

<p>Unfortunately, BrightBox does not support Ubuntu 20.04 LTS (Focal Fossa), which is what Windows installs when you use the MS Store:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>E: The repository 'http://ppa.launchpad.net/brightbox/ruby-ng/ubuntu focal Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details. 
</code></pre></div></div>

<p>Install <code class="language-plaintext highlighter-rouge">ruby-full</code> instead:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get install ruby-full
</code></pre></div></div>

<p>And all build essentials, so that we can build gems with native extensions:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt install build-essential patch ruby-dev zlib1g-dev liblzma-dev libsqlite3-dev nodejs
</code></pre></div></div>

<p>And finally, for the ease of handling gems, <code class="language-plaintext highlighter-rouge">ruby-bundler</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt install ruby-bundler
</code></pre></div></div>

<p>And…. that’s it. You have now a fully everything needed to get going.</p>

<h3 id="creating-your-first-site">Creating your first site</h3>

<p>Lets get the first jekyll site going. The easiest way to set up Jekyll is using the GitHub-Pages gem. It is a great choice even if not deploying on GitHub Pages.</p>

<p>First, we create the following <strong>Gemfile</strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>source 'https://rubygems.org'
gem 'github-pages', group: :jekyll_plugins
</code></pre></div></div>

<p>And than its just a matter of installing the bundle and running Jekyll:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ bundle install
$ bundle exec jekyll serve --watch
</code></pre></div></div>

<p>From time to time, you’ll want to fetch new versions of the <code class="language-plaintext highlighter-rouge">github-pages</code> gem:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ bundle update github-pages
</code></pre></div></div>]]></content><author><name>Sebastian Teumert</name></author><category term="Windows" /><category term="Linux" /><category term="Jekyll" /><summary type="html"><![CDATA[The Windows Subsystem for Linux works surprisingly well by now – at least for simple tasks. In this blog post, I describe how to install the WSL as well as Jekyll (with GitHub Pages support) using Ubuntu as the distro of choice. Installing the WSL and a Linux distro is suprisingly easy and has only 4 steps (one is optional).]]></summary></entry><entry><title type="html">A small side note on JEPs 384 and 359</title><link href="/blog/a-small-side-note-on-jep-384-and-359-2020" rel="alternate" type="text/html" title="A small side note on JEPs 384 and 359" /><published>2020-05-08T21:10:00+00:00</published><updated>2020-05-08T21:10:00+00:00</updated><id>/blog/a-small-side-note-on-jep-384-and-359</id><content type="html" xml:base="/blog/a-small-side-note-on-jep-384-and-359-2020"><![CDATA[<p>When reading about records and having read 
<a href="https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html">Pattern Matching for Java, Gavin Bierman and Brian Goetz, September 2018</a>, 
it would be easy to assume that pattern matching in <code class="language-plaintext highlighter-rouge">instanceof</code> would also include <em>deconstruction patterns</em>. 
This isn’t a preview feature in Java 14 which included records via <a href="https://openjdk.java.net/jeps/359">JEP 359</a>, but was slated for Java 15 with <a href="https://openjdk.java.net/jeps/384">JEP 384</a>. 
Unfortunately, this JEP has changed and deconstruction patterns are no longer planned for that JEP. 
Records will be re-previewed as-is.</p>]]></content><author><name>Sebastian Teumert</name></author><category term="Java" /><category term="Records" /><summary type="html"><![CDATA[When reading about records and having read Pattern Matching for Java, Gavin Bierman and Brian Goetz, September 2018, it would be easy to assume that pattern matching in instanceof would also include deconstruction patterns. This isn’t a preview feature in Java 14 which included records via JEP 359, but was slated for Java 15 with JEP 384. Unfortunately, this JEP has changed and deconstruction patterns are no longer planned for that JEP. Records will be re-previewed as-is.]]></summary></entry><entry><title type="html">Records &amp;amp; their constructors</title><link href="/blog/records-their-constructors-2020" rel="alternate" type="text/html" title="Records &amp;amp; their constructors" /><published>2020-05-08T20:57:00+00:00</published><updated>2020-05-08T20:57:00+00:00</updated><id>/blog/records-their-constructors</id><content type="html" xml:base="/blog/records-their-constructors-2020"><![CDATA[<p>A look at the constructors of records in Java 14, and how one can leverage
the formal parameter list of records to already enable libraries like Jackson to work with records (and in this
example, deserialize JSON to records).</p>

<p>Records will be re-previewed in Java 15 without any changes as part of [JEP 384] 
and are expected to become a regular feature of the language in Java 16.</p>

<h2 id="records-can-have-regular-constructors-just-like-classes">Records can have regular constructors, just like classes</h2>

<p>Records can have regular constructor. The constructor without formal parameter list, which is a new
feature in records and helps combat boilerplate by leveraging auto-initialization, but they can also have regular 
constructors with a formal parameter list, just like classes.</p>

<p>A simple record might be given as:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">record</span> <span class="nf">FooBar</span><span class="o">(</span><span class="nc">String</span> <span class="n">foo</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span> <span class="o">}</span>
</code></pre></div></div>

<p>And then we can add sanity checks – in this case just using the constructor without formal parameter list.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">record</span> <span class="nf">FooBar</span><span class="o">(</span><span class="nc">String</span> <span class="n">foo</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nc">FooBar</span> <span class="o">{</span>
		<span class="k">if</span> <span class="o">(</span><span class="n">foo</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">foo</span><span class="o">.</span><span class="na">isBlank</span><span class="o">())</span>
			<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"foo can not be null or blank"</span><span class="o">);</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Without a formal parameter list, values are assigned after the constructor has run. 
So one can initialize fields differently and <strong>doesn’t</strong> need to assign them via <code class="language-plaintext highlighter-rouge">this.x = x</code>.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">record</span> <span class="nf">FooBar</span><span class="o">(</span><span class="nc">String</span> <span class="n">foo</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nc">FooBar</span> <span class="o">{</span>
		<span class="k">if</span> <span class="o">(</span><span class="n">foo</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">foo</span><span class="o">.</span><span class="na">isBlank</span><span class="o">())</span>
			<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"foo can not be null or blank"</span><span class="o">);</span>
		<span class="k">if</span><span class="o">(</span><span class="n">bars</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
			<span class="n">bars</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">bars</code> <strong>will</strong> be assigned correctly and a call to <code class="language-plaintext highlighter-rouge">bars()</code> will return the newly created list.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="k">new</span> <span class="nc">FooBar</span><span class="o">(</span><span class="s">"FooBar"</span><span class="o">,</span> <span class="kc">null</span><span class="o">));</span>
<span class="c1">// prints FooBar[foo=FooBar, bars=[]]</span>
</code></pre></div></div>

<p>However, assigning <code class="language-plaintext highlighter-rouge">bars</code> inside the constructor to <code class="language-plaintext highlighter-rouge">this.bars</code> via <code class="language-plaintext highlighter-rouge">this.bars = bars;</code> is <em>heavily discouraged</em>, 
in fact so much so that it is a point of active discussion on the amber-spec-experts mailing list to remove access to 
fields via <code class="language-plaintext highlighter-rouge">this.x</code> in the canonical constructor altogether (both reads &amp; writes) [<a href="https://mail.openjdk.java.net/pipermail/amber-spec-experts/2020-April/002111.html">amber-spec-experts</a>].</p>

<p>However, you can also use a constructor with a formal parameter list. When doing so, auto-initialization does <em>not</em> work 
and values <em>must</em> be assigned in the constructor (since the fields are final):</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">record</span> <span class="nf">FooBar</span><span class="o">(</span><span class="nc">String</span> <span class="n">foo</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nf">FooBar</span> <span class="o">(</span><span class="nc">String</span> <span class="n">foo</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span>
		<span class="k">if</span> <span class="o">(</span><span class="n">foo</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">foo</span><span class="o">.</span><span class="na">isBlank</span><span class="o">())</span>
			<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"foo can not be null or blank"</span><span class="o">);</span>
		<span class="k">if</span><span class="o">(</span><span class="n">bars</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
			<span class="n">bars</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
		<span class="k">this</span><span class="o">.</span><span class="na">foo</span> <span class="o">=</span> <span class="n">foo</span><span class="o">;</span>
		<span class="k">this</span><span class="o">.</span><span class="na">bars</span> <span class="o">=</span> <span class="n">bars</span><span class="o">;</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Why would you ever want to do that? Because you can put annotations on them. Currently, libraries like Jackson do not 
support records, but work to make this happen is underway [3]. Using formal parameter lists for the constructor lets us 
put annotations on them and get around that limitation:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">record</span> <span class="nf">FooBar</span><span class="o">(</span><span class="nc">String</span> <span class="n">foo</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nf">FooBar</span><span class="o">(</span>
			<span class="nd">@JsonProperty</span> <span class="nc">String</span> <span class="n">foo</span><span class="o">,</span> 
			<span class="nd">@JsonProperty</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span>			
		<span class="k">if</span> <span class="o">(</span><span class="n">foo</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">foo</span><span class="o">.</span><span class="na">isBlank</span><span class="o">())</span>
			<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"foo can not be null or blank"</span><span class="o">);</span>
		<span class="k">if</span><span class="o">(</span><span class="n">bars</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
			<span class="n">bars</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
		<span class="k">this</span><span class="o">.</span><span class="na">foo</span> <span class="o">=</span> <span class="n">foo</span><span class="o">;</span>
		<span class="k">this</span><span class="o">.</span><span class="na">bars</span> <span class="o">=</span> <span class="n">bars</span><span class="o">;</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Yes, this actually works right now, in Java 14, with Jackson 2.11.0.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="n">record</span> <span class="nf">FooBar</span><span class="o">(</span><span class="nc">String</span> <span class="n">foo</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nf">FooBar</span><span class="o">(</span><span class="nd">@JsonProperty</span><span class="o">(</span><span class="s">"foo"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">foo</span><span class="o">,</span>
		 <span class="nd">@JsonProperty</span><span class="o">(</span><span class="s">"bars"</span><span class="o">)</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">bars</span><span class="o">)</span> <span class="o">{</span>
		<span class="k">if</span> <span class="o">(</span><span class="n">foo</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">foo</span><span class="o">.</span><span class="na">isBlank</span><span class="o">())</span>
			<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"foo can not be null or blank"</span><span class="o">);</span>
		<span class="k">if</span> <span class="o">(</span><span class="n">bars</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
			<span class="n">bars</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
		<span class="k">this</span><span class="o">.</span><span class="na">foo</span> <span class="o">=</span> <span class="n">foo</span><span class="o">;</span>
		<span class="k">this</span><span class="o">.</span><span class="na">bars</span> <span class="o">=</span> <span class="n">bars</span><span class="o">;</span>
	<span class="o">}</span>

	<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">JsonProcessingException</span> <span class="o">{</span>
		<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="k">new</span> <span class="nc">ObjectMapper</span><span class="o">()</span>
			<span class="o">.</span><span class="na">readValue</span><span class="o">(</span><span class="s">"{\"foo\" : \"foo\", \"bars\": []}"</span><span class="o">,</span> <span class="nc">FooBar</span><span class="o">.</span><span class="na">class</span><span class="o">));</span>
		<span class="c1">// prints out FooBar[foo=foo, bars=[]]</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>]]></content><author><name>Sebastian Teumert</name></author><category term="Java" /><category term="Records" /><summary type="html"><![CDATA[A look at the constructors of records in Java 14, and how one can leverage the formal parameter list of records to already enable libraries like Jackson to work with records (and in this example, deserialize JSON to records).]]></summary></entry><entry><title type="html">On records &amp;amp; (im-) mutability</title><link href="/blog/on-records-im-mutability-and-lesser-known-features-2020" rel="alternate" type="text/html" title="On records &amp;amp; (im-) mutability" /><published>2020-05-08T19:24:00+00:00</published><updated>2020-05-08T19:24:00+00:00</updated><id>/blog/on-records-im-mutability-and-lesser-known-features</id><content type="html" xml:base="/blog/on-records-im-mutability-and-lesser-known-features-2020"><![CDATA[<p>Records are sometimes described as immutable, which is unfortunate. Looking at the JEP, we see them being called 
“shallowly-immutable”. That is an important distinction.
A record can still be changed in a multitude of ways, and this article sheds some light on the strategies one
can employ to ensure records actually are immutable.</p>

<p>Records will be re-previewed in Java 15 without any changes as part of <a href="https://openjdk.java.net/jeps/384">JEP 384</a> 
and are expected to become a regular feature of the language in Java 16.</p>

<p>Lets start with a simple example and how it can be shown to be not immutable:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="n">record</span> <span class="nf">NaiveRecord</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Date</span><span class="o">&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="o">{</span> <span class="o">}</span>
</code></pre></div></div>

<p>We can show that this record is mutable by simply adding to or removing from the list as returned by <code class="language-plaintext highlighter-rouge">values()</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">naive</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">NaiveRecord</span><span class="o">(</span><span class="s">"naive"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;());</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">naive</span><span class="o">);</span>
<span class="c1">//prints NaiveRecord[name=naive, values=[]]</span>
<span class="n">naive</span><span class="o">.</span><span class="na">values</span><span class="o">().</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">Date</span><span class="o">(</span><span class="mi">99</span><span class="o">,</span> <span class="mo">01</span><span class="o">,</span> <span class="mo">01</span><span class="o">));</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">naive</span><span class="o">);</span>
<span class="c1">// prints NaiveRecord[name=naive, values=[Mon Feb 01 00:00:00 CET 1999]]</span>
</code></pre></div></div>

<p>How can we do it better? We can adress the above problem by making the list immutable,
leveraging the canonical constructor without using a formal paremeter list:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="n">record</span> <span class="nf">BetterRecord</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Date</span><span class="o">&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nc">BetterRecord</span> <span class="o">{</span>
		<span class="n">values</span> <span class="o">=</span> <span class="nc">Collections</span><span class="o">.</span><span class="na">unmodifiableList</span><span class="o">(</span><span class="n">values</span><span class="o">);</span>
	<span class="o">}</span>
<span class="o">};</span>
</code></pre></div></div>
<p>Now, changes to the record via <code class="language-plaintext highlighter-rouge">record.values().add/remove()</code> aren’t possible anymore, 
as they’d throw an <code class="language-plaintext highlighter-rouge">UnsupportedOperationException</code>. 
Unfortunately, changes to the record are still possible by writing to the underlying list directly. 
If that has escaped or be given away, the record can still experience changes in state (and thus, <code class="language-plaintext highlighter-rouge">hashCode()</code>).</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">original</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;</span><span class="nc">Date</span><span class="o">&gt;();</span>
<span class="n">original</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">Date</span><span class="o">(</span><span class="mi">99</span><span class="o">,</span> <span class="mo">01</span><span class="o">,</span> <span class="mo">01</span><span class="o">));</span>
<span class="kt">var</span> <span class="n">better</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BetterRecord</span><span class="o">(</span><span class="s">"better"</span><span class="o">,</span> <span class="n">original</span><span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"%s hash=%s"</span><span class="o">.</span><span class="na">formatted</span><span class="o">(</span><span class="n">better</span><span class="o">,</span> <span class="n">better</span><span class="o">.</span><span class="na">hashCode</span><span class="o">()));</span>
<span class="c1">// BetterRecord[name=better, values=[Mon Feb 01 00:00:00 CET 1999]] hash=-1516124796</span>
<span class="n">original</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">Date</span><span class="o">(</span><span class="mi">102</span><span class="o">,</span> <span class="mo">01</span><span class="o">,</span> <span class="mo">01</span><span class="o">));</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"%s hash=%s"</span><span class="o">.</span><span class="na">formatted</span><span class="o">(</span><span class="n">better</span><span class="o">,</span> <span class="n">better</span><span class="o">.</span><span class="na">hashCode</span><span class="o">()));</span>
<span class="c1">// BetterRecord[name=better, values=[Mon Feb 01 00:00:00 CET 1999, Fri Feb 01 00:00:00 CET 2002]] hash=1357225607</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"-----"</span><span class="o">);</span>
</code></pre></div></div>

<p>The solution to that particular problem is to defensively copy the whole list, and then wrapping it into an unmodifiable one.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="n">record</span> <span class="nf">EvenBetterRecord</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Date</span><span class="o">&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nc">EvenBetterRecord</span> <span class="o">{</span> 
		<span class="n">values</span> <span class="o">=</span> <span class="nc">Collections</span><span class="o">.</span><span class="na">unmodifiableList</span><span class="o">(</span><span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;(</span><span class="n">values</span><span class="o">));</span>
	<span class="o">}</span>
<span class="o">};</span>
</code></pre></div></div>

<p>But still, this record remains vulnerable if the data type stored in the list is mutable, as is the case for <code class="language-plaintext highlighter-rouge">java.util.Date</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">original</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;</span><span class="nc">Date</span><span class="o">&gt;();</span>
<span class="kt">var</span> <span class="n">someDay</span>  <span class="o">=</span> <span class="k">new</span> <span class="nc">Date</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span> <span class="mo">01</span><span class="o">,</span> <span class="mo">01</span><span class="o">);</span>
<span class="n">original</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">someDay</span><span class="o">);</span>
<span class="kt">var</span> <span class="n">evenBetter</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">EvenBetterRecord</span><span class="o">(</span><span class="s">"even better"</span><span class="o">,</span> <span class="n">original</span><span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"%s hash=%s"</span><span class="o">.</span><span class="na">formatted</span><span class="o">(</span><span class="n">evenBetter</span><span class="o">,</span> <span class="n">evenBetter</span><span class="o">.</span><span class="na">hashCode</span><span class="o">()));</span>
<span class="c1">// EvenBetterRecord[name=even better, values=[Tue Feb 01 00:00:00 CET 2000]] hash=-1168472954</span>

<span class="n">someDay</span><span class="o">.</span><span class="na">setYear</span><span class="o">(</span><span class="mi">99</span><span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"%s hash=%s"</span><span class="o">.</span><span class="na">formatted</span><span class="o">(</span><span class="n">evenBetter</span><span class="o">,</span> <span class="n">evenBetter</span><span class="o">.</span><span class="na">hashCode</span><span class="o">()));</span>
<span class="c1">// EvenBetterRecord[name=even better, values=[Mon Feb 01 00:00:00 CET 1999]] hash=1655265406</span>
</code></pre></div></div>

<p>We can address this by also creating a deep copy of each element of the list.
This is where having a copy constructor comes in very handy. Unfortunately, <code class="language-plaintext highlighter-rouge">java.util.Date</code> doesn’t have one.
But it <em>does</em> implement <code class="language-plaintext highlighter-rouge">Cloneable</code> &amp; has a <code class="language-plaintext highlighter-rouge">public clone()</code> method.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="n">record</span> <span class="nf">ImmutableRecord</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Date</span><span class="o">&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="nc">ImmutableRecord</span> <span class="o">{</span>
		<span class="n">values</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="na">stream</span><span class="o">()</span>
				<span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="nl">Date:</span><span class="o">:</span><span class="n">clone</span><span class="o">)</span>
				<span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="nc">Date</span><span class="o">.</span><span class="na">class</span><span class="o">::</span><span class="n">cast</span><span class="o">)</span>
				<span class="o">.</span><span class="na">collect</span><span class="o">(</span><span class="nc">Collectors</span><span class="o">.</span><span class="na">toUnmodifiableList</span><span class="o">());</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Here we take the values, clone them, cast them back from <code class="language-plaintext highlighter-rouge">Object</code> to <code class="language-plaintext highlighter-rouge">Date</code> (as <code class="language-plaintext highlighter-rouge">Date#clone</code> returns <code class="language-plaintext highlighter-rouge">Object</code>)
and then collect them all into an unmodifiable list.</p>

<p>This list is not modifiable by any of the tricks shown so far.
We can of course still do shenanigans involving <code class="language-plaintext highlighter-rouge">Unsafe</code> or serialization, but this is the kind of record I’d consider 
<em>reasonably immutable</em>. If you are not using <code class="language-plaintext highlighter-rouge">java.util.Date</code>, you might need to make sure that you are actually doing 
a deep copy of the object, as a shallow copy might have leaked references through which it can be manipulated, too.</p>

<p>Note that only nesting records is no defense again mutation, either. 
If the nested record is mutable, e.g. by having an improperly treated collection, the holding record becomes mutable, too.</p>

<h2 id="recap">Recap</h2>

<p>Records are not immutable, they are only “shallowly-immutable”. We can break immutability in three ways:</p>

<ul>
  <li>Adding to or removing from the list returned by <code class="language-plaintext highlighter-rouge">values()</code><br />
  (addressed by wrapping it into an unmodifiable list)</li>
  <li>Adding or removing from the original list if we still have a reference to it<br />
  (addressed by copying the list)</li>
  <li>Mutating an element in the list mutates the record<br />
  (addressed by deep copying the elements of the list)</li>
</ul>

<p>In fact, we can easily devise unit-tests for all three of these properties.
The following gist contains a JUnit 5 test case, with unit tests called</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">canNotChangeThroughGetter</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">canNotChangeThroughOriginalList</code> and</li>
  <li><code class="language-plaintext highlighter-rouge">canNotChangeThroughOriginalObject</code>.</li>
</ul>

<p>In order to execute each of these tests with each record, I have added a common interface <code class="language-plaintext highlighter-rouge">RecordWithList</code> to all four 
of these records and execute the tests with each type of record.
Not all records pass all tests, which was expected in this case.</p>

<details class="github-gist" data-url="https://gist.github.com/NetzwergX/e0e09f3a10f40bdae7fac643193b8d0e">
<summary>Show Gist</summary>
<script src="https://gist.github.com/e0e09f3a10f40bdae7fac643193b8d0e.js"> </script>
</details>

<h1 id="conclusion">Conclusion</h1>

<p>Using the canonical constructor without formal parameter list can be quite powerful. 
Using <code class="language-plaintext highlighter-rouge">this.x</code> inside such a constructor is not needed and actively discouraged to the point 
that the Java architects are considering disallowing such access altogether.</p>

<p>Using a formal parameter list on the constructor allows programmers to place annotations there. 
With such a constructor, some libraries, most notably Jackson, can be made to work with constructors easily.</p>

<p>Records are only “shallowly-immutable”. If one wants to leverage the beneficial properties of immutable types, 
great care has to be taken to ensure that the record actually is immutable, and not only appears that way at first glance.</p>]]></content><author><name>Sebastian Teumert</name></author><category term="Java" /><category term="Records" /><summary type="html"><![CDATA[Records are sometimes described as immutable, which is unfortunate. Looking at the JEP, we see them being called “shallowly-immutable”. That is an important distinction. A record can still be changed in a multitude of ways, and this article sheds some light on the strategies one can employ to ensure records actually are immutable.]]></summary></entry><entry><title type="html">Failure Modes</title><link href="/blog/failure-modes-2020" rel="alternate" type="text/html" title="Failure Modes" /><published>2020-05-07T00:00:00+00:00</published><updated>2020-05-07T00:00:00+00:00</updated><id>/blog/failure-modes</id><content type="html" xml:base="/blog/failure-modes-2020"><![CDATA[<p>Programs often have to deal with less then ideal conditions – intermittent internet connections, hardware dropping in 
and out, user input not being reliable, files being corrupted, and many, many more scenarios in which failure is not 
only a possibility, but to a certain has to be expected and worked with without fatally crashing the application,
but instead gracefully resuming and informing the user of the problems and allowing them to fix them.<br />
In this article, I’ll talk about the following three ways to handle failure modes.</p>

<h1 id="failure-modes">Failure modes</h1>

<ol>
  <li>Return <code class="language-plaintext highlighter-rouge">true</code>, <code class="language-plaintext highlighter-rouge">false</code>, <code class="language-plaintext highlighter-rouge">NULL</code> or another <em>magic</em> value</li>
  <li>Use <code class="language-plaintext highlighter-rouge">void</code>, throw a (checked) exception</li>
  <li>Return an intermediate result object</li>
</ol>

<p>Each of these modes is discussed below, with examples of their usage, strengths and weaknesses.</p>

<h1 id="return-true-false-or-null">Return <code class="language-plaintext highlighter-rouge">true</code>, <code class="language-plaintext highlighter-rouge">false</code> or <code class="language-plaintext highlighter-rouge">NULL</code></h1>

<p>This is used in some older, mostly C-style APIs. Today, we can for example find it quite often in the 
PHP standard library, leading to code like this:</p>

<pre><code class="language-PHP">if ($data = xyz_parse($data) === FALSE)
	$error = xyz_last_error();
</code></pre>

<p>Obviously this only works in languages like PHP because there is no static typing and in C due to being able to cast 
values this way. In Java, the only way to signal failure would be to return <code class="language-plaintext highlighter-rouge">null</code> or another magic value 
(via the NULL-Object pattern).</p>

<p>The downsides to this approach are (not exhaustive):</p>

<ul>
  <li>It is not clear from the method signature what the magic values are</li>
  <li>Without a-priory knowledge about the magic values, checking for them and interpreting them correctly is impossible</li>
  <li><em>No compiler support</em>, forcing the caller to correctly handle all scenarios by themselves, making errors easy</li>
</ul>

<p>In multi-threaded contexts, this approach is even worse. In between parsing and retrieving the error, 
another thread might parse something, overwriting the stored errors.
Synchronizing such access is easily forgotten or a performance nightmare.</p>

<p>Therefore, this approach has largely fallen out of favor, especially in programming languages that offer useful alternatives.</p>

<p>We can sometimes see a similar approach being used in Java where no return value is expected and instead a boolean
is returned to indicate failure and success, e.g. in <code class="language-plaintext highlighter-rouge">Collection#add</code>. The disadvatange is that we do not get any
information about the kind of failure and have no way to query what went wrong.</p>

<p>And in case of <code class="language-plaintext highlighter-rouge">Collections.unmodifiable[Collection|List|Set|Map]</code>, we get a runtime exception (<code class="language-plaintext highlighter-rouge">UnsupportedOperationException)</code>, 
which by necessity is unchecked. This defeats all the help the compiler could give us and makes unmodifiable collections
prone to let exceptions bubble up the stack without being handled at the proper level.</p>

<h1 id="throw-checked-exceptions">Throw (checked) exceptions</h1>

<p>Checked exceptions are a more elegant way to signal potential failure modes and forcing the caller to handle them. 
Since <em>failure is to be expected</em> for certain operations, checked exceptions an be leverage to enforce error handling
by the caller. Java for example uses checked exceptions when dealing with sockets.
The basic assumption is that a call should succeed, but certain operations are known to be unreliable.
Socket connections are among them. So the caller gets forced to handle the failure.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">try</span> <span class="o">{</span>
	<span class="n">socket</span><span class="o">.</span><span class="na">open</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
	<span class="c1">// deal with the failure, e.g. display error message</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="return-result-object">Return result object</h1>

<p>Another way to handle expected failure is to return an immediate result object that holds information about 
the operation. In modern Java, <code class="language-plaintext highlighter-rouge">Optional&lt;E&gt;</code> could also be used to signal values that might or might not be present 
(e.g. a valid parsing result).</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ValidationResult</span> <span class="n">result</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="na">validate</span><span class="o">(</span><span class="n">rawData</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">result</span><span class="o">.</span><span class="na">isValid</span><span class="o">())</span> <span class="o">{</span>
	<span class="kt">var</span> <span class="n">data</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="na">getData</span><span class="o">();</span>
	<span class="c1">// process data</span>
<span class="o">}</span>
<span class="k">else</span> <span class="o">{</span>
	<span class="kt">var</span> <span class="n">error</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="na">getValidationError</span><span class="o">();</span>
	<span class="c1">// optional error handling</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Nice, clean logic for the caller. In Java, <code class="language-plaintext highlighter-rouge">ValidationResult#getData</code> could return <code class="language-plaintext highlighter-rouge">Optional&lt;BusinessData&gt;</code> to 
communicate to the caller that the data might or might not be present and to ensure compiler support for missing values.</p>

<h2 id="leveraging-sealed-classes-and-interfaces-algebraic-types">Leveraging sealed classes and interfaces (algebraic types)</h2>

<p>With [JEP 360] <a href="https://mail.openjdk.java.net/pipermail/amber-dev/2020-April/005784.html">considered for Java 15</a>,
we might get yet another way to create intermediate result objects that sits somewhere in between checked exceptions
and a result object - algebraic types! These are formed with <a href="https://cr.openjdk.java.net/~briangoetz/amber/datum.html">Sealed Types</a> and <a href="https://openjdk.java.net/jeps/359">Records</a>.</p>

<p>Suppose we create a type <code class="language-plaintext highlighter-rouge">Result&lt;S, E&gt; = Success&lt;S&gt; | Error&lt;E&gt;</code>, which we could do In Java 15 with</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sealed</span> <span class="kd">interface</span> <span class="nc">Result</span><span class="o">&lt;</span><span class="no">S</span><span class="o">,</span><span class="no">E</span><span class="o">&gt;</span> <span class="n">permits</span> <span class="nc">Success</span><span class="o">&lt;</span><span class="no">S</span><span class="o">,</span> <span class="no">E</span><span class="o">&gt;,</span> <span class="nc">Error</span><span class="o">&lt;</span><span class="no">S</span><span class="o">,</span> <span class="no">E</span><span class="o">&gt;</span> <span class="o">{</span>
	<span class="n">record</span> <span class="nc">Success</span><span class="o">&lt;</span><span class="no">S</span><span class="o">,</span> <span class="no">E</span><span class="o">&gt;</span> <span class="o">(</span><span class="no">S</span> <span class="n">result</span><span class="o">)</span> <span class="kd">implements</span> <span class="nc">Result</span><span class="o">&lt;</span><span class="no">S</span><span class="o">,</span> <span class="no">E</span><span class="o">&gt;</span> <span class="o">{}</span>
	<span class="n">record</span> <span class="nc">Error</span><span class="o">&lt;</span><span class="no">S</span><span class="o">,</span> <span class="no">E</span><span class="o">&gt;</span> <span class="o">(</span><span class="no">E</span> <span class="n">error</span><span class="o">)</span> <span class="kd">implements</span> <span class="nc">Result</span><span class="o">&lt;</span><span class="no">S</span><span class="o">,</span> <span class="no">E</span><span class="o">&gt;</span> <span class="o">{}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Unfortunately, we can not specify a “don’t care” generic wildcard, so a bit repetition is needed there. But now, instead of
indicating to a caller the possibility of errorneos execution via <code class="language-plaintext highlighter-rouge">throws</code>, we can indicate this via the result type:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Parser</span> <span class="o">{</span>
	
	<span class="kd">public</span> <span class="nc">Result</span><span class="o">&lt;</span><span class="nc">Data</span><span class="o">,</span> <span class="nc">InvalidFormatException</span><span class="o">&gt;</span> <span class="nf">parse</span><span class="o">(</span><span class="nc">String</span> <span class="n">raw</span><span class="o">)</span> <span class="o">{</span>
		<span class="c1">// [...]</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>A caller is then forced to examine the type, either via <code class="language-plaintext highlighter-rouge">instanceof</code> (<a href="https://openjdk.java.net/jeps/305">JEP 305</a>) or leveraging <code class="language-plaintext highlighter-rouge">switch</code> expressions (<a href="https://openjdk.java.net/jeps/325">JEP 325</a>),
potentially even leveraging pattern-matching with deconstruction patterns inside of any of those (<a href="https://openjdk.java.net/jeps/8213076">JEP Draft</a>, <a href="https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html">Pattern Matching</a>).</p>

<p>An example call could look like this:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">switch</span><span class="o">(</span><span class="n">parser</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="n">input</span><span class="o">))</span> <span class="o">{</span>
	<span class="k">case</span> <span class="nf">Result</span><span class="o">(</span><span class="nc">Data</span> <span class="n">data</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="n">process</span><span class="o">(</span><span class="n">data</span><span class="o">);</span>
	<span class="k">case</span> <span class="nf">Error</span><span class="o">(</span><span class="nc">InvalidFormatException</span> <span class="n">e</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="n">displayError</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>We might even use a more general exception and switch more fine-grained on the exception type 
(potentially forgoing exhaustiveness checks and necessitating a <code class="language-plaintext highlighter-rouge">default</code> clause).</p>

<h1 id="conclusion">Conclusion</h1>

<p>Failure modes can be handled in different ways depending on wether failure is expected or unexpected. Shown here are
four ways of handling them, and which one to choose depends on the nature of the problem and the context
in which it might occur.</p>

<p>There is a (sometimes) heated debate going on when to use (checked) exceptions and when to use other approaches.
A statement that I found very reasonable wrt. exceptions is the following:</p>

<blockquote>
  <p>Checked exceptions are for environment problems. Unchecked exceptions are programming errors.<br />
— Elliotte Rusty Harold, <em>Exceptions: I’m Telling You For The Last Time</em></p>
</blockquote>]]></content><author><name>Sebastian Teumert</name></author><category term="Java" /><category term="exception-handling" /><summary type="html"><![CDATA[Programs often have to deal with less then ideal conditions – intermittent internet connections, hardware dropping in and out, user input not being reliable, files being corrupted, and many, many more scenarios in which failure is not only a possibility, but to a certain has to be expected and worked with without fatally crashing the application, but instead gracefully resuming and informing the user of the problems and allowing them to fix them. In this article, I’ll talk about the following three ways to handle failure modes.]]></summary></entry><entry><title type="html">Java 8 Lambda Cheat Sheet</title><link href="/blog/java-8-lambda-cheat-sheet-2020" rel="alternate" type="text/html" title="Java 8 Lambda Cheat Sheet" /><published>2020-05-06T00:00:00+00:00</published><updated>2020-05-06T00:00:00+00:00</updated><id>/blog/java-8-lambda-cheat-sheet</id><content type="html" xml:base="/blog/java-8-lambda-cheat-sheet-2020"><![CDATA[<p class="no-print">Even though Java 8 is just a little over six years old and brought a tremendous revolution to Java, 
adoption of lambdas and functional approaches to programming problems is still an ongoing process.<br />
I have introduced numerous people to functional-style programming &amp; lambdas,
and at one point came up with the idea of a small “cheat sheet” only one or two DIN A4 pages in size that you could have 
in hand when thinking about functional stuff. This is by no means meant to be a comprehensive introduction, 
but a small reference document, and has been received very well, so I thought I’d share it here.</p>

<table>
  <thead>
    <tr>
      <th>Interface<br />&amp; Method</th>
      <th>Type</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html"><code class="language-plaintext highlighter-rouge">Supplier&lt;E&gt;</code></a> <br /> <code class="language-plaintext highlighter-rouge">E get()</code></td>
      <td><code class="language-plaintext highlighter-rouge">() -&gt; E</code></td>
      <td><code class="language-plaintext highlighter-rouge">Supplier&lt;List&gt; factory = ArrayList::new;</code><br /><code class="language-plaintext highlighter-rouge">stream.collect(Collectors.toList(factory));</code></td>
    </tr>
    <tr>
      <td><a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html"><code class="language-plaintext highlighter-rouge">Consumer&lt;E&gt;</code></a> <br /><code class="language-plaintext highlighter-rouge">void accept(E e)</code></td>
      <td><code class="language-plaintext highlighter-rouge">E -&gt; ()</code></td>
      <td><code class="language-plaintext highlighter-rouge">list.foreach(e -&gt; e.frobnicate())</code></td>
    </tr>
    <tr>
      <td><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html"><code class="language-plaintext highlighter-rouge">Runnable</code></a> <br /> <code class="language-plaintext highlighter-rouge">void run()</code></td>
      <td><code class="language-plaintext highlighter-rouge">() -&gt; ()</code></td>
      <td><code class="language-plaintext highlighter-rouge">new Thread(() -&gt; System.sleep(10000)).run();</code></td>
    </tr>
    <tr>
      <td><a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html"><code class="language-plaintext highlighter-rouge">Function&lt;T,R&gt;</code></a><br /><code class="language-plaintext highlighter-rouge">R apply(T t)</code></td>
      <td><code class="language-plaintext highlighter-rouge">T -&gt; R</code></td>
      <td><code class="language-plaintext highlighter-rouge">stream.map(t -&gt; new R(t));</code></td>
    </tr>
    <tr>
      <td><a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/BiFunction.html"><code class="language-plaintext highlighter-rouge">BiFunction&lt;T,U,R&gt;</code></a><br /><code class="language-plaintext highlighter-rouge">R apply(T t, U u)</code></td>
      <td><code class="language-plaintext highlighter-rouge">(T, U) -&gt; R</code></td>
      <td><code class="language-plaintext highlighter-rouge">stream.reduce(start, accumulator, merge</code>)</td>
    </tr>
    <tr>
      <td><a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html"><code class="language-plaintext highlighter-rouge">Predicate&lt;E&gt;</code></a> <br /><code class="language-plaintext highlighter-rouge">boolean test(E e)</code></td>
      <td><code class="language-plaintext highlighter-rouge">E -&gt; boolean</code></td>
      <td><code class="language-plaintext highlighter-rouge">Function&lt;E, Boolean&gt;</code> but with primitive <code class="language-plaintext highlighter-rouge">boolean</code></td>
    </tr>
  </tbody>
</table>

<h1 id="when-to-use">When to use</h1>

<table>
  <thead>
    <tr>
      <th>Use</th>
      <th>When</th>
      <th>Related concept</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Supplier&lt;E&gt;</code></td>
      <td>If it takes nothing</td>
      <td>Factory</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Consumer&lt;E&gt;</code></td>
      <td>If it returns nothing</td>
      <td>Listener, Callback</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Runnable</code></td>
      <td>If it does neither</td>
      <td>Task</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Function&lt;F, T&gt;</code></td>
      <td>If it does both</td>
      <td>Callback</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">BiFunction&lt;T, U , R&gt;</code></td>
      <td>If it takes two and returns one</td>
      <td> </td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Predicate&lt;E&gt;</code></td>
      <td>To check semantic properties</td>
      <td>Condition</td>
    </tr>
  </tbody>
</table>

<h1 id="mapreduceimportant-stream-operations">MapReduce<br /><small>Important stream operations</small></h1>

<p><em>As always, <code class="language-plaintext highlighter-rouge">A = B</code> is permissible!</em></p>

<table>
  <thead>
    <tr>
      <th>Operation</th>
      <th>Type</th>
      <th>Input</th>
      <th>Output</th>
      <th>See also</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">map</code></td>
      <td><code class="language-plaintext highlighter-rouge">A -&gt; B</code></td>
      <td><code class="language-plaintext highlighter-rouge">Stream&lt;A&gt;</code></td>
      <td><code class="language-plaintext highlighter-rouge">Stream&lt;B&gt;</code></td>
      <td><code class="language-plaintext highlighter-rouge">flatMap</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">filter</code></td>
      <td><code class="language-plaintext highlighter-rouge">A -&gt; bool</code></td>
      <td><code class="language-plaintext highlighter-rouge">Stream&lt;A&gt;</code></td>
      <td><code class="language-plaintext highlighter-rouge">Stream&lt;A&gt;</code></td>
      <td><code class="language-plaintext highlighter-rouge">takeWhile</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">reduce</code></td>
      <td><code class="language-plaintext highlighter-rouge">(B, ((B, A) -&gt; B), ((B, B) -&gt; B)) -&gt; B</code></td>
      <td><code class="language-plaintext highlighter-rouge">Stream&lt;A&gt;</code></td>
      <td><code class="language-plaintext highlighter-rouge">B</code></td>
      <td><code class="language-plaintext highlighter-rouge">collect</code> is <code class="language-plaintext highlighter-rouge">reduce</code></td>
    </tr>
  </tbody>
</table>

<h1 id="when-to-use-1">When to use</h1>

<table>
  <thead>
    <tr>
      <th>Use</th>
      <th>When</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">map</code></td>
      <td>transforming one Stream into another Stream</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">filter</code></td>
      <td>excluding elements from one stream based on a condition (predicate)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">reduce</code></td>
      <td>making the stream “smaller” (reducing it), e.g. <br /> - collecting <em>multiple</em> elements into <em>one</em> list<br />- taking a sum, maximum or minimum<br />- or otherwise reducing multiple elements to one element</td>
    </tr>
  </tbody>
</table>]]></content><author><name>Sebastian Teumert</name></author><category term="Java" /><category term="lambda" /><category term="functional-programming" /><category term="cheat-sheet" /><summary type="html"><![CDATA[Even though Java 8 is just a little over six years old and brought a tremendous revolution to Java, adoption of lambdas and functional approaches to programming problems is still an ongoing process. I have introduced numerous people to functional-style programming &amp; lambdas, and at one point came up with the idea of a small “cheat sheet” only one or two DIN A4 pages in size that you could have in hand when thinking about functional stuff. This is by no means meant to be a comprehensive introduction, but a small reference document, and has been received very well, so I thought I’d share it here.]]></summary></entry><entry><title type="html">How To: Use language variables</title><link href="/blog/How-To-use-language-variables-2013" rel="alternate" type="text/html" title="How To: Use language variables" /><published>2013-06-09T00:00:00+00:00</published><updated>2013-06-09T00:00:00+00:00</updated><id>/blog/How-To-use-language-variables</id><content type="html" xml:base="/blog/How-To-use-language-variables-2013"><![CDATA[<p>WCF 2.0 comes with built-in internationalization (i18n) or, as some call
it, multi-language support. I18n within WCF 2.0 is realied using so called
<em>language variables</em>. Those variables can be filled with values in multiple
languages and even allow adminitrators to translate their whole board to
another language themselves. But how do plugin developers use language variables
correctly?<br />
<a href="/2013-06-08-how-to-create-wcf-plugins.html">In the last article</a>, 
where I wrote about creating a simple WCF 2.0 pugin, I presented a template in
which the term “Hello, World!” was hard coded into the template in english. 
This is not only strongly discouraged, but is also dangerous in terms of 
encoding and escaping. Languages variables ansure the proper ecspaing of HTML 
entities and much more, therefore one should always use language variables over
hard coded text.</p>

<h4 id="modifiying-the-template">Modifiying the template</h4>

<p>In templates, we can use the <code class="language-plaintext highlighter-rouge">{lang}...{/lang}</code> template tag to render the 
contents of a language variable. if the variable is not found, the name of the 
variable is put out instead. So, a modified version of the template from
the last article would look like this:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{include file='documentHeader'}

<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;title&gt;</span>{lang}wcf.page.helloworld.title{/lang} - {PAGE_TITLE|language}<span class="nt">&lt;/title&gt;</span>

    {include file='headInclude' sandbox=false}
<span class="nt">&lt;/head&gt;</span>

<span class="nt">&lt;body</span> <span class="na">id=</span><span class="s">"tpl{$templateName|ucfirst}"</span><span class="nt">&gt;</span>

{include file='header'}

<span class="nt">&lt;header</span> <span class="na">class=</span><span class="s">"boxHeadline"</span><span class="nt">&gt;</span>    
    <span class="nt">&lt;h1&gt;</span>{lang}wcf.page.helloworld.title{/lang}<span class="nt">&lt;/h1&gt;</span>  
<span class="nt">&lt;/header&gt;</span>

{include file='userNotice'}

{lang}wcf.page.helloworld.info{/lang}

{include file='footer'}

<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p>Here we use two language variables – <code class="language-plaintext highlighter-rouge">wcf.page.helloworld.title</code> for the
page title, which is also used in the heading, and <code class="language-plaintext highlighter-rouge">wcf.page.helloworld.info</code>
which will hold the text in the blue information box. You might notice that I
have removed the whole <code class="language-plaintext highlighter-rouge">&lt;p class='info'&gt;...&lt;/p&gt;</code> box altogether. This is right –
you can use HTML and even template scripting inside language variables.</p>

<p>By now, the page will look like this:</p>

<p><img src="/assets/images/Hello_World_Page_LVars.png" alt="Screenshots of HelloWorld-Page" title="Hello, World! using language variables" /></p>

<h4 id="deploying-language-variables">Deploying language variables</h4>

<p>In order to define values for our language variables, we will use the <strong>Language-
PIP</strong>, which is XML-based. Therefore, we create a new folder named <code class="language-plaintext highlighter-rouge">lang/</code> in
our plugin, and place two files there, namely <code class="language-plaintext highlighter-rouge">de.xml</code> and <code class="language-plaintext highlighter-rouge">en.xml</code>.</p>

<p>The <code class="language-plaintext highlighter-rouge">lang/en.xml</code> file will look like this:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="nt">&lt;language</span> <span class="na">xmlns=</span><span class="s">"http://www.woltlab.com"</span> <span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="na">xsi:schemaLocation=</span><span class="s">"http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/language.xsd"</span> <span class="na">languagecode=</span><span class="s">"en"</span> <span class="na">languagename=</span><span class="s">"English"</span> <span class="na">countrycode=</span><span class="s">"en"</span><span class="nt">&gt;</span>
	<span class="nt">&lt;category</span> <span class="na">name=</span><span class="s">"wcf.page"</span><span class="nt">&gt;</span>
		<span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">"wcf.page.helloworld.title"</span><span class="nt">&gt;</span><span class="cp">&lt;![CDATA[Hello, World!]]&gt;</span><span class="nt">&lt;/item&gt;</span>
		<span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">"wcf.page.helloworld.info"</span><span class="nt">&gt;</span><span class="cp">&lt;![CDATA[&lt;p class="info"&gt;my first page!&lt;/p&gt;]]&gt;</span><span class="nt">&lt;/item&gt;</span>		
	<span class="nt">&lt;/category&gt;</span>
<span class="nt">&lt;/language&gt;</span>
</code></pre></div></div>

<p>Like in the <code class="language-plaintext highlighter-rouge">package.xml</code> file, we again declare the used sheme, which in this
case is the scheme for language files. Moreover, we declare for which language
this file is used - in this case english.</p>

<p>by now you will most probably have notices the <code class="language-plaintext highlighter-rouge">&lt;categories&gt;</code> block. Language
variables withing WCF are separated into categories. The name of a language
variable alsways has to be prefixed with it’s category. It is most important
always to use the correct category, as unexpected things can happen if you use 
the wrong language category (this was cause for much trouble for early WCf 1.x
plugins). Unfortunately, as of now there is no documentation about the
existing language categories available. Therefore, you will need to take a look
into the WCF database youself.</p>

<p>In this case, <code class="language-plaintext highlighter-rouge">wcf.page</code> is the correct category.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;instruction type="language"&gt;language/*.xml&lt;/instruction&gt;
</code></pre></div></div>]]></content><author><name>Sebastian Teumert</name></author><category term="Woltlab" /><category term="wcf2" /><category term="wcf" /><category term="how to" /><category term="tutorial" /><category term="language" /><category term="plugin" /><summary type="html"><![CDATA[WCF 2.0 comes with built-in internationalization (i18n) or, as some call it, multi-language support. I18n within WCF 2.0 is realied using so called language variables. Those variables can be filled with values in multiple languages and even allow adminitrators to translate their whole board to another language themselves. But how do plugin developers use language variables correctly? In the last article, where I wrote about creating a simple WCF 2.0 pugin, I presented a template in which the term “Hello, World!” was hard coded into the template in english. This is not only strongly discouraged, but is also dangerous in terms of encoding and escaping. Languages variables ansure the proper ecspaing of HTML entities and much more, therefore one should always use language variables over hard coded text.]]></summary></entry></feed>