<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Grant Riordan</title>
    <description>The latest articles on DEV Community by Grant Riordan (@grantdotdev).</description>
    <link>https://dev.to/grantdotdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F434380%2F4f092a26-2eda-4d8b-8a10-2f71109596ac.png</url>
      <title>DEV Community: Grant Riordan</title>
      <link>https://dev.to/grantdotdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grantdotdev"/>
    <language>en</language>
    <item>
      <title>Stop Writing Raw Python - Let C Handle It</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Sat, 04 Apr 2026 05:07:24 +0000</pubDate>
      <link>https://dev.to/grantdotdev/stop-writing-raw-python-let-c-handle-it-432c</link>
      <guid>https://dev.to/grantdotdev/stop-writing-raw-python-let-c-handle-it-432c</guid>
      <description>&lt;ul&gt;
&lt;li&gt;April 2026 · 6 min read*
&lt;em&gt;A .NET developer's guide to Python performance — and why the rules are different&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I've spent most of my career in .NET. C#, the CLR, JIT compilation — these are things I know deeply. I'm proficient in TypeScript and JavaScript for full-stack and mobile work. Python, though, has always been at arm's length. I never really needed to cross over into that world. &lt;/p&gt;

&lt;p&gt;That changed recently. And the first real thing it taught me was something I hadn't expected: &lt;strong&gt;don't write your own raw code if you can help it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's strange advice if you're coming from C#. In .NET, hand-crafted code and library code run through the same JIT compiler. Performance is often comparable, so you usually optimise based on other considerations — readability, semantics, maintainability. Python, it turns out, works very differently. Understanding why changes how you write it.&lt;/p&gt;

&lt;p&gt;The fundamental difference isn’t syntax — it’s where computation happens. In C#, you trust the JIT to make your code fast. In Python, your job is to keep work out of the Python layer as much as possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Python Actually Runs
&lt;/h2&gt;

&lt;p&gt;The version of Python most people use is &lt;strong&gt;CPython&lt;/strong&gt; — the reference implementation, written in C. When you run a &lt;code&gt;.py&lt;/code&gt; file, CPython compiles it to bytecode and then interprets that bytecode at runtime. Crucially, it does not use JIT compilation like C# does.&lt;/p&gt;

&lt;p&gt;C# runs on the .NET Common Language Runtime, which uses &lt;strong&gt;Just-In-Time (JIT) compilation&lt;/strong&gt;. Your C# source gets compiled to Intermediate Language (IL), and when you run the program the CLR compiles that IL to native machine code, optimised at runtime. After the initial warm-up, it executes at hardware speed.&lt;/p&gt;

&lt;p&gt;CPython is interpreting Python bytecode one instruction at a time. The .NET CLR is handing the CPU something close to its native language.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth noting:&lt;/strong&gt; Python 3.11+ introduced an &lt;em&gt;adaptive interpreter&lt;/em&gt; with specialised bytecode — certain hot code paths get micro-optimised at runtime. It's a meaningful improvement, but CPython still lacks a general-purpose JIT. The gap with C# remains significant for CPU-bound work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the root of why Python's &lt;strong&gt;raw&lt;/strong&gt; execution speed is generally slower than C# for CPU-intensive tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  The C-Backed Library Trick
&lt;/h2&gt;

&lt;p&gt;Here's where Python gets clever. Many of its built-in functions and popular libraries — &lt;code&gt;sum()&lt;/code&gt;, &lt;code&gt;sorted()&lt;/code&gt;, itertools (a lazy iterator toolkit), the entirety of NumPy — are &lt;strong&gt;not written in Python&lt;/strong&gt;. They're implemented in C, compiled to native machine code, and called from Python. When you use them, you're escaping the interpreter overhead for the heavy work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Slow: a plain Python loop
&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="c1"&gt;# Fast: drops into C for the iteration
&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A very simple example, but the point holds at scale. Both do the same thing. But the second hands off to a C function that runs without the interpreter touching each iteration. For large lists, the difference is measurable. &lt;/p&gt;

&lt;p&gt;The loop isn’t the problem — the Python interpreter touching every iteration is. The fix isn’t to avoid loops specifically, it’s to push computation down into C-backed code wherever possible.&lt;/p&gt;

&lt;p&gt;In C#, this asymmetry largely doesn't exist. A hand-rolled loop and &lt;code&gt;Enumerable.Sum()&lt;/code&gt; from LINQ go through the same JIT pipeline. That said, LINQ isn't entirely free — it can introduce allocations, delegate overhead, and less predictable inlining. A &lt;code&gt;for&lt;/code&gt; loop over an array or &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; is often faster in hot paths. But this is an optimisation consideration, not a fundamental runtime difference the way it is in Python.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vectorisation: The Real Unlock
&lt;/h2&gt;

&lt;p&gt;The "use library functions" advice only scratches the surface. The deeper insight is &lt;strong&gt;vectorisation&lt;/strong&gt; — and it's where the real performance leap happens. The loop example illustrates the principle, but vectorisation is where it gets truly powerful. Not just “C code instead of Python code”, but entire operations that never touch the Python layer at all.&lt;/p&gt;

&lt;p&gt;Libraries like NumPy don't just run in C. They operate on &lt;em&gt;entire arrays at once&lt;/em&gt;, using CPU-level Single Instruction Multiple Data (SIMD) instructions, avoiding Python-level loops entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# This doesn't loop in Python — it's a single C-level vector operation
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare that to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Each iteration is a Python instruction — slow
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though both produce the same output, the NumPy version isn't just "faster C code" — it's a fundamentally different execution model. The Python interpreter barely participates. This is the insight that explains why Python dominates data science and scientific computing despite being a slow language at its core.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Does JavaScript Sit?
&lt;/h2&gt;

&lt;p&gt;Coming from .NET, you might assume JavaScript is similarly slow — a scripting language, interpreted, running in a browser. Historically that was fair. Modern JavaScript engines have largely changed the picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V8&lt;/strong&gt; (powering Chrome and Node.js) uses aggressive JIT compilation with multiple optimisation tiers. JavaScript code that runs frequently gets compiled to native machine code, similar in principle to the .NET CLR. TypeScript compiles to plain JavaScript before anything runs, so at execution time it is identical to JS — no performance difference there.&lt;/p&gt;

&lt;p&gt;It's worth noting that JS JIT and C# JIT behave differently in practice. V8 uses &lt;em&gt;speculative optimisation&lt;/em&gt; — it makes assumptions about your code and optimises aggressively, but can &lt;em&gt;deoptimise&lt;/em&gt; if those assumptions are violated. C#'s CLR is more predictable. Both are fast; JS just requires more care to keep on the happy path.&lt;/p&gt;

&lt;p&gt;The practical upshot: the "use library functions or your code will be slow" advice matters much less in JavaScript and TypeScript. A hand-written &lt;code&gt;for&lt;/code&gt; loop in modern JS is not dramatically slower than an equivalent library call, because both go through the same JIT compiler.&lt;/p&gt;

&lt;p&gt;Where JS does lag is in areas Python has addressed with C-backed scientific libraries. NumPy, Pandas, and similar tools have &lt;strong&gt;no real equivalent in the JavaScript ecosystem&lt;/strong&gt; — or at least, nothing as mature or widely adopted. TensorFlow.js and WebAssembly-based libraries exist, but the gap is significant. If you need serious numerical computing, Python + NumPy will outperform vanilla JS even accounting for Python's slower interpreter, because the actual number crunching never touches the Python layer at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Execution Model&lt;/th&gt;
&lt;th&gt;Raw Loop Speed&lt;/th&gt;
&lt;th&gt;"Use Libraries" Advice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C#&lt;/td&gt;
&lt;td&gt;JIT → native machine code (CLR)&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;For ergonomics, not speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Interpreted bytecode (CPython)&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Critical for performance&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;JIT → native machine code (V8)&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;For ergonomics, not speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;Compiles to JS → same as JS&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Same as JS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Simplified for general application code. Performance is context-dependent. PyPy — a Python implementation with JIT compilation — can significantly close the gap with C# for CPU-bound workloads.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What This Changes About How I Write Python
&lt;/h2&gt;

&lt;p&gt;Knowing this shapes a few concrete habits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reach for built-ins first.&lt;/strong&gt; &lt;code&gt;sum()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;sorted()&lt;/code&gt;, &lt;code&gt;Counter&lt;/code&gt;, list comprehensions — these exist not just for readability, but because they hand off work to C.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NumPy before hand-rolled loops.&lt;/strong&gt; Any numerical work over arrays belongs in NumPy. Not because it's cleaner (it is), but because it vectorises the operation and keeps it out of the Python interpreter entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't be surprised by slow loops.&lt;/strong&gt; When Python feels slow in a tight loop, that's not a bug in your code — it's the nature of the interpreter. The solution is usually to restructure so the interpreter handles coordination while optimised C code handles the heavy lifting.&lt;/p&gt;

&lt;p&gt;For a .NET developer, this is a genuine mental shift. In C#, you trust the JIT to make most sensible code fast. In Python, you trust the libraries to provide fast tools — and your job is to wire them together well.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;Python's slowness in raw execution isn't a flaw so much as a design trade-off. The language prioritises readability and developer speed, and it compensates for interpreter overhead by sitting on top of an enormous library of high-performance C code. Once you understand that, a lot of Python idioms that might seem arbitrary start to make perfect sense.&lt;/p&gt;

&lt;p&gt;Sometimes you genuinely can’t offload to a library — custom logic, complex conditionals, things NumPy can’t express cleanly. In those cases, accept the performance tradeoff, or reach for generators to manage memory overhead, or PyPy if raw speed is required. &lt;/p&gt;

&lt;p&gt;Coming from C# and JavaScript, the biggest adjustment isn’t syntax or semantics. It’s accepting that Python’s performance model is fundamentally different — and that working with it, rather than against it, means trusting the libraries over your own raw code. In C# the JIT has your back. In Python, the libraries do.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written with a .NET background, a Python curiosity, and one too many slow &lt;code&gt;for&lt;/code&gt; loops.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have thoughts? Leave a comment or find me on &lt;a href="https://x.com/grantdotdev" rel="noopener noreferrer"&gt;X/Twitter&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>discuss</category>
      <category>learning</category>
      <category>development</category>
    </item>
    <item>
      <title>Stop Writing Python — Let C Do It</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Fri, 03 Apr 2026 21:20:20 +0000</pubDate>
      <link>https://dev.to/grantdotdev/why-python-told-me-to-stop-writing-my-own-code-4fbb</link>
      <guid>https://dev.to/grantdotdev/why-python-told-me-to-stop-writing-my-own-code-4fbb</guid>
      <description>&lt;ul&gt;
&lt;li&gt;April 2026 · 6 min read*
&lt;em&gt;A .NET developer's guide to Python performance — and why the rules are different&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I've spent most of my career in .NET. C#, the CLR, JIT compilation — these are things I know deeply. I'm proficient in TypeScript and JavaScript for full-stack and mobile work. Python, though, has always been at arm's length. I never really needed to cross over into that world. &lt;/p&gt;

&lt;p&gt;That changed recently. And the first real thing it taught me was something I hadn't expected: &lt;strong&gt;don't write your own raw code if you can help it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's strange advice if you're coming from C#. In .NET, hand-crafted code and library code run through the same JIT compiler. Performance is often comparable, so you usually optimise based on other considerations — readability, semantics, maintainability. Python, it turns out, works very differently. Understanding why changes how you write it.&lt;/p&gt;

&lt;p&gt;The fundamental difference isn’t syntax — it’s where computation happens. In C#, you trust the JIT to make your code fast. In Python, your job is to keep work out of the Python layer as much as possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Python Actually Runs
&lt;/h2&gt;

&lt;p&gt;The version of Python most people use is &lt;strong&gt;CPython&lt;/strong&gt; — the reference implementation, written in C. When you run a &lt;code&gt;.py&lt;/code&gt; file, CPython compiles it to bytecode and then interprets that bytecode at runtime. Crucially, it does not use JIT compilation like C# does.&lt;/p&gt;

&lt;p&gt;C# runs on the .NET Common Language Runtime, which uses &lt;strong&gt;Just-In-Time (JIT) compilation&lt;/strong&gt;. Your C# source gets compiled to Intermediate Language (IL), and when you run the program the CLR compiles that IL to native machine code, optimised at runtime. After the initial warm-up, it executes at hardware speed.&lt;/p&gt;

&lt;p&gt;CPython is interpreting Python bytecode one instruction at a time. The .NET CLR is handing the CPU something close to its native language.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth noting:&lt;/strong&gt; Python 3.11+ introduced an &lt;em&gt;adaptive interpreter&lt;/em&gt; with specialised bytecode — certain hot code paths get micro-optimised at runtime. It's a meaningful improvement, but CPython still lacks a general-purpose JIT. The gap with C# remains significant for CPU-bound work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the root of why Python's &lt;strong&gt;raw&lt;/strong&gt; execution speed is generally slower than C# for CPU-intensive tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  The C-Backed Library Trick
&lt;/h2&gt;

&lt;p&gt;Here's where Python gets clever. Many of its built-in functions and popular libraries — &lt;code&gt;sum()&lt;/code&gt;, &lt;code&gt;sorted()&lt;/code&gt;, itertools (a lazy iterator toolkit), the entirety of NumPy — are &lt;strong&gt;not written in Python&lt;/strong&gt;. They're implemented in C, compiled to native machine code, and called from Python. When you use them, you're escaping the interpreter overhead for the heavy work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Slow: a plain Python loop
&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="c1"&gt;# Fast: drops into C for the iteration
&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A very simple example, but the point holds at scale. Both do the same thing. But the second hands off to a C function that runs without the interpreter touching each iteration. For large lists, the difference is measurable. &lt;/p&gt;

&lt;p&gt;The loop isn’t the problem — the Python interpreter touching every iteration is. The fix isn’t to avoid loops specifically, it’s to push computation down into C-backed code wherever possible.&lt;/p&gt;

&lt;p&gt;In C#, this asymmetry largely doesn't exist. A hand-rolled loop and &lt;code&gt;Enumerable.Sum()&lt;/code&gt; from LINQ go through the same JIT pipeline. That said, LINQ isn't entirely free — it can introduce allocations, delegate overhead, and less predictable inlining. A &lt;code&gt;for&lt;/code&gt; loop over an array or &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; is often faster in hot paths. But this is an optimisation consideration, not a fundamental runtime difference the way it is in Python.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vectorisation: The Real Unlock
&lt;/h2&gt;

&lt;p&gt;The "use library functions" advice only scratches the surface. The deeper insight is &lt;strong&gt;vectorisation&lt;/strong&gt; — and it's where the real performance leap happens. The loop example illustrates the principle, but vectorisation is where it gets truly powerful. Not just “C code instead of Python code”, but entire operations that never touch the Python layer at all.&lt;/p&gt;

&lt;p&gt;Libraries like NumPy don't just run in C. They operate on &lt;em&gt;entire arrays at once&lt;/em&gt;, using CPU-level Single Instruction Multiple Data (SIMD) instructions, avoiding Python-level loops entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# This doesn't loop in Python — it's a single C-level vector operation
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare that to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Each iteration is a Python instruction — slow
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though both produce the same output, the NumPy version isn't just "faster C code" — it's a fundamentally different execution model. The Python interpreter barely participates. This is the insight that explains why Python dominates data science and scientific computing despite being a slow language at its core.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Does JavaScript Sit?
&lt;/h2&gt;

&lt;p&gt;Coming from .NET, you might assume JavaScript is similarly slow — a scripting language, interpreted, running in a browser. Historically that was fair. Modern JavaScript engines have largely changed the picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V8&lt;/strong&gt; (powering Chrome and Node.js) uses aggressive JIT compilation with multiple optimisation tiers. JavaScript code that runs frequently gets compiled to native machine code, similar in principle to the .NET CLR. TypeScript compiles to plain JavaScript before anything runs, so at execution time it is identical to JS — no performance difference there.&lt;/p&gt;

&lt;p&gt;It's worth noting that JS JIT and C# JIT behave differently in practice. V8 uses &lt;em&gt;speculative optimisation&lt;/em&gt; — it makes assumptions about your code and optimises aggressively, but can &lt;em&gt;deoptimise&lt;/em&gt; if those assumptions are violated. C#'s CLR is more predictable. Both are fast; JS just requires more care to keep on the happy path.&lt;/p&gt;

&lt;p&gt;The practical upshot: the "use library functions or your code will be slow" advice matters much less in JavaScript and TypeScript. A hand-written &lt;code&gt;for&lt;/code&gt; loop in modern JS is not dramatically slower than an equivalent library call, because both go through the same JIT compiler.&lt;/p&gt;

&lt;p&gt;Where JS does lag is in areas Python has addressed with C-backed scientific libraries. NumPy, Pandas, and similar tools have &lt;strong&gt;no real equivalent in the JavaScript ecosystem&lt;/strong&gt; — or at least, nothing as mature or widely adopted. TensorFlow.js and WebAssembly-based libraries exist, but the gap is significant. If you need serious numerical computing, Python + NumPy will outperform vanilla JS even accounting for Python's slower interpreter, because the actual number crunching never touches the Python layer at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Execution Model&lt;/th&gt;
&lt;th&gt;Raw Loop Speed&lt;/th&gt;
&lt;th&gt;"Use Libraries" Advice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C#&lt;/td&gt;
&lt;td&gt;JIT → native machine code (CLR)&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;For ergonomics, not speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Interpreted bytecode (CPython)&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Critical for performance&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;JIT → native machine code (V8)&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;For ergonomics, not speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;Compiles to JS → same as JS&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Same as JS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Simplified for general application code. Performance is context-dependent. PyPy — a Python implementation with JIT compilation — can significantly close the gap with C# for CPU-bound workloads.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What This Changes About How I Write Python
&lt;/h2&gt;

&lt;p&gt;Knowing this shapes a few concrete habits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reach for built-ins first.&lt;/strong&gt; &lt;code&gt;sum()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;sorted()&lt;/code&gt;, &lt;code&gt;Counter&lt;/code&gt;, list comprehensions — these exist not just for readability, but because they hand off work to C.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NumPy before hand-rolled loops.&lt;/strong&gt; Any numerical work over arrays belongs in NumPy. Not because it's cleaner (it is), but because it vectorises the operation and keeps it out of the Python interpreter entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't be surprised by slow loops.&lt;/strong&gt; When Python feels slow in a tight loop, that's not a bug in your code — it's the nature of the interpreter. The solution is usually to restructure so the interpreter handles coordination while optimised C code handles the heavy lifting.&lt;/p&gt;

&lt;p&gt;For a .NET developer, this is a genuine mental shift. In C#, you trust the JIT to make most sensible code fast. In Python, you trust the libraries to provide fast tools — and your job is to wire them together well.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;Python's slowness in raw execution isn't a flaw so much as a design trade-off. The language prioritises readability and developer speed, and it compensates for interpreter overhead by sitting on top of an enormous library of high-performance C code. Once you understand that, a lot of Python idioms that might seem arbitrary start to make perfect sense.&lt;/p&gt;

&lt;p&gt;Sometimes you genuinely can’t offload to a library — custom logic, complex conditionals, things NumPy can’t express cleanly. In those cases, accept the performance tradeoff, or reach for generators to manage memory overhead, or PyPy if raw speed is required. &lt;/p&gt;

&lt;p&gt;Coming from C# and JavaScript, the biggest adjustment isn’t syntax or semantics. It’s accepting that Python’s performance model is fundamentally different — and that working with it, rather than against it, means trusting the libraries over your own raw code. In C# the JIT has your back. In Python, the libraries do.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written with a .NET background, a Python curiosity, and one too many slow &lt;code&gt;for&lt;/code&gt; loops.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have thoughts? Leave a comment or find me on &lt;a href="https://x.com/grantdotdev" rel="noopener noreferrer"&gt;X/Twitter&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>discuss</category>
      <category>development</category>
    </item>
    <item>
      <title>AI Can Not Be Left Unsupervised</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Thu, 26 Mar 2026 23:42:34 +0000</pubDate>
      <link>https://dev.to/grantdotdev/ai-can-not-be-left-unsupervised-5ad</link>
      <guid>https://dev.to/grantdotdev/ai-can-not-be-left-unsupervised-5ad</guid>
      <description>&lt;p&gt;"AI is dangerous" — is a phrase you may hear a lot, and I have to agree. But, the most dangerous words in tech right now aren't "&lt;em&gt;AI is dangerous&lt;/em&gt;", they're "&lt;em&gt;it'll probably be fine&lt;/em&gt;". In a society where the use of AI has become the norm, people have become almost complacent around the dangers of it.&lt;/p&gt;

&lt;p&gt;This week I read an article on Dev.to &lt;a href="https://dev.to/harsh2644/agentic-ai-is-the-most-overhyped-thing-in-tech-and-i-have-proof-1785"&gt;here&lt;/a&gt;, telling a story where an employee had "trusted AI to organize my backlog." Two hours later, they returned to a development team's worst nightmare.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The agent had silently deleted 47 tickets it labelled as duplicates — they weren't. It had reassigned half my team's tasks to people who had left the company months ago. It created 23 new tickets for features nobody had requested. And it marked three critical bugs as resolved, because it found similar-sounding issues elsewhere in the system."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A prime example of when AI is left to its own devices — no warning, no follow-up prompts. It was asked to organise a backlog, and so it did, in the only way it knew how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Damaging Cases
&lt;/h2&gt;

&lt;p&gt;This isn't an isolated incident. Amazon's own AI coding tool, Kiro, was handed a minor fix to a customer-facing system. Rather than patch it, the agent autonomously decided to delete and rebuild the entire environment from scratch. The resulting outage lasted 13 hours. Amazon's response? "Coincidence that AI was involved." That denial tells you everything. &lt;/p&gt;

&lt;p&gt;In a similar case, an AI coding assistant from &lt;strong&gt;Replit&lt;/strong&gt; went rogue and wiped the production database of startup &lt;strong&gt;SaaStr&lt;/strong&gt; entirely — its founder took to social media to warn others after the assistant modified production code despite explicit instructions not to.&lt;/p&gt;

&lt;p&gt;Could your business afford that kind of downtime?&lt;/p&gt;

&lt;p&gt;It isn't just agentic AI operating behind the scenes. Customer-facing AI is failing in equally public and embarrassing ways. DPD's AI chatbot, after a routine system update, began swearing at a customer, insulted itself, and wrote a poem about how terrible the company was, all because a frustrated user simply asked it to. The incident went viral. &lt;/p&gt;

&lt;p&gt;Perhaps the most alarming example of AI complacency comes from a Chevrolet dealership, whose chatbot agreed to sell a 2024 Chevy Tahoe for &lt;strong&gt;$1&lt;/strong&gt; and declared it a legally binding offer after a user simply manipulated it with a clever prompt. The dealer pulled the bot, but the damage to their brand was already done.&lt;/p&gt;

&lt;p&gt;In August 2025, security researchers used a single 400-character prompt to manipulate Lenovo's customer service chatbot into revealing sensitive company data including live session cookies from real support agents. Not a sophisticated hack. Just a simple prompt.&lt;/p&gt;

&lt;p&gt;Outside of customer service, the professional world is sleepwalking into its own risks. A lawyer was caught citing entirely non-existent legal cases in a New York federal court filing he had used ChatGPT to conduct legal research, and &lt;strong&gt;simply trusted the output&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;With the rapid adoption of AI across industries, has the world become complacent, siding with productivity over pragmatism? More often than not, users are blindly allowing AI to complete work for them, review sensitive documents outside the bounds of a secure environment, and make decisions without a single human checkpoint. &lt;/p&gt;

&lt;p&gt;I know many developers who simply click "Accept" when prompted to approve terminal commands. I've spoken to professionals within my network who say "AI has evolved, it can be trusted." That ignorance and naivety is precisely what leads to the scenarios above.&lt;/p&gt;

&lt;p&gt;The companies and individuals that will thrive in an AI-driven world aren't the ones adopting it the fastest. They're the ones adopting it the most responsibly. &lt;/p&gt;

&lt;h2&gt;
  
  
  Final Note
&lt;/h2&gt;

&lt;p&gt;Before you click "Accept" on that next AI suggestion, ask yourself honestly: do you actually know what you're agreeing to? Don't simply outsource your thinking to something that doesn't think - it predicts. &lt;/p&gt;

&lt;p&gt;AI isn't the danger. We are.&lt;/p&gt;

&lt;p&gt;I’d love to hear your thoughts - comment below or drop me a follow on &lt;a href="https://x.com/grantdotdev" rel="noopener noreferrer"&gt;X/Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
    </item>
    <item>
      <title>Using Python To Merge Array of Ranges</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Tue, 30 Dec 2025 22:16:48 +0000</pubDate>
      <link>https://dev.to/grantdotdev/using-python-to-merge-array-of-ranges-2hic</link>
      <guid>https://dev.to/grantdotdev/using-python-to-merge-array-of-ranges-2hic</guid>
      <description>&lt;p&gt;So I was doing an Advent of Code 2025 challenge the other day, and had an issue where I needed to count all the unique numbers between multiple ranges. It reminded me of some code I'd written previously for a booking system.&lt;/p&gt;

&lt;p&gt;The problem was that the ranges overlapped in many cases. Now, looping over all the numbers and using a &lt;code&gt;set()&lt;/code&gt; was not feasible, nor performant as the ranges could be in the millions. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Naïve Approach
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;unique_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ranges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;unique_values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a range of say &lt;code&gt;1-100_000_000_000&lt;/code&gt; you'd create 1 billion numbers in memory, that's huge! You're also materialising data that doesn't need to exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution - Merge First, Count Later
&lt;/h2&gt;

&lt;p&gt;Instead of creating every number in memory (expensive), we merge overlapping ranges into fewer, larger ranges, then calculate the count mathematically.&lt;/p&gt;

&lt;p&gt;Lets look at a smaller range for the purpose of this tutorial:&lt;/p&gt;

&lt;p&gt;Let's say we have the following ranges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;some of them overlap or touch each other. &lt;br&gt;
&lt;code&gt;10-14&lt;/code&gt; and &lt;code&gt;12-18&lt;/code&gt; overlap (they share 12, 13, 14)&lt;/p&gt;

&lt;p&gt;If merged, they become one range: 10-18. Without merging, you'd count numbers twice or waste memory storing every individual number.&lt;/p&gt;
&lt;h2&gt;
  
  
  How To Merge Overlapping Ranges
&lt;/h2&gt;
&lt;h3&gt;
  
  
  First Thing - Let's Get The Ranges Sorted
&lt;/h3&gt;

&lt;p&gt;Sorting the arrays by their start position makes the merging a lot easier - we read from left-to-right on the number line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sorted_ranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fresh_ranges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Before: [(3,5), (10,14), (16,20), (12,18)]
# After:  [(3,5), (10,14), (12,18), (16,20)]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How does this help though? When you encounter a new range, you only need to check if it overlaps with the last merged range. There's no need to check all previous ranges. If ranges are sorted, overlaps always happen with the most recent range, saving time and effort checking other ranges.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Sorted number line view:
   3---5      10----14
              12------18
                  16----20

&lt;span class="c"&gt;# You can see overlaps flow left-to-right!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Second - Merge the overlapping ranges
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sorted_ranges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Overlaps or touches - merge!
&lt;/span&gt;        &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Doesn't overlap - add as new range
&lt;/span&gt;        &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why &lt;code&gt;merged and start &amp;lt;= merged[-1][1] + 1&lt;/code&gt;?&lt;br&gt;
This condition checks two things:&lt;/p&gt;

&lt;p&gt;merged → Is there at least one range already merged?&lt;/p&gt;

&lt;p&gt;First iteration: merged = [] → False, so add first range&lt;/p&gt;

&lt;p&gt;Later: merged = [(3,5)] → True, check overlap&lt;br&gt;
start &amp;lt;= merged[-1][1] + 1 → Does current range touch/overlap the last merged range?&lt;/p&gt;
&lt;h4&gt;
  
  
  Lets take a look at some examples:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Case 1: Adjacent (touching)
&lt;/span&gt;&lt;span class="n"&gt;Last&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# ends at 14
&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# starts at 15
&lt;/span&gt;&lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;YES&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt; &lt;span class="n"&gt;They&lt;/span&gt; &lt;span class="n"&gt;touch&lt;/span&gt;

&lt;span class="c1"&gt;# Case 2: Gap between ranges
&lt;/span&gt;&lt;span class="n"&gt;Last&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# ends at 5
&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# starts at 10
&lt;/span&gt;&lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;NO&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt; &lt;span class="n"&gt;Gap&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Why + 1?&lt;/p&gt;

&lt;p&gt;Ranges for example like (5,10) and (11,15) are adjacent. They shouldn't stay separate (gap at position 10.5). The &lt;code&gt;+ 1&lt;/code&gt; is about merging adjacent ranges that touch, not just overlapping ones.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Range A: &lt;span class="o"&gt;(&lt;/span&gt;5, 9&lt;span class="o"&gt;)&lt;/span&gt;   →  5, 6, 7, 8, 9
Range B: &lt;span class="o"&gt;(&lt;/span&gt;10, 15&lt;span class="o"&gt;)&lt;/span&gt; →  10, 11, 12, 13, 14, 15

Number line:
5--6--7--8--9--10--11--12--13--14--15
&lt;span class="o"&gt;[======&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;======][========&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;========]&lt;/span&gt;
              ↑
          They TOUCH at position 9→10

Without +1:
Check: 10 &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; 9? → NO ❌
Result: Keep separate &lt;span class="o"&gt;[(&lt;/span&gt;5,9&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="o"&gt;(&lt;/span&gt;10,15&lt;span class="o"&gt;)]&lt;/span&gt;
This is WRONG - there is no gap! They should be one range: &lt;span class="o"&gt;(&lt;/span&gt;5,15&lt;span class="o"&gt;)&lt;/span&gt;

With +1:
Check: 10 &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; 9+1? → 10 &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; 10? → YES ✅
Result: Merge to &lt;span class="o"&gt;(&lt;/span&gt;5, 15&lt;span class="o"&gt;)&lt;/span&gt;
This is CORRECT!

&lt;span class="c"&gt;# Actual Gap&lt;/span&gt;
Range A: &lt;span class="o"&gt;(&lt;/span&gt;5, 9&lt;span class="o"&gt;)&lt;/span&gt;   →  5, 6, 7, 8, 9
Range B: &lt;span class="o"&gt;(&lt;/span&gt;11, 15&lt;span class="o"&gt;)&lt;/span&gt; →  11, 12, 13, 14, 15

Number line:
5--6--7--8--9--&lt;span class="o"&gt;(&lt;/span&gt;10&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nt"&gt;--11--12--13--14--15&lt;/span&gt;
&lt;span class="o"&gt;[======&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;======]&lt;/span&gt;  GAP  &lt;span class="o"&gt;[=======&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=======]&lt;/span&gt;
              ↑      ↑
          Ends at 9  Starts at 11
          10 is missing!

With +1:
Check: 11 &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; 9+1? → 11 &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; 10? → NO ✅
Result: Keep separate &lt;span class="o"&gt;[(&lt;/span&gt;5,9&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="o"&gt;(&lt;/span&gt;11,15&lt;span class="o"&gt;)]&lt;/span&gt;
This is CORRECT - there&lt;span class="s1"&gt;'s a gap at position 10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply, sum each range to get the total number of items within the ranges.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;total_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total_count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final Code:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# Sort ranges by start position
&lt;/span&gt;    &lt;span class="n"&gt;sorted_ranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fresh_ranges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Merge overlapping ranges
&lt;/span&gt;    &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sorted_ranges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Overlapping or adjacent - merge with last range
&lt;/span&gt;            &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# No overlap - add new range
&lt;/span&gt;            &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# Calculate total count from merged ranges
&lt;/span&gt;    &lt;span class="n"&gt;total_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total_count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real Life Usages:
&lt;/h2&gt;

&lt;p&gt;There are many scenarios in real life where you may need to handle multiple ranges needing merged, or to be counted;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;h3&gt;
  
  
  Appointment Booking Systems:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Meeting A: 9:00 AM - 10:30 AM
Meeting B: 10:15 AM - 11:00 AM  
Meeting C: 2:00 PM - 3:30 PM
Meeting D: 3:30 PM - 5:00 PM

Sorted: &lt;span class="o"&gt;[(&lt;/span&gt;9:00, 10:30&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="o"&gt;(&lt;/span&gt;10:15, 11:00&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="o"&gt;(&lt;/span&gt;2:00, 3:30&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="o"&gt;(&lt;/span&gt;3:30, 5:00&lt;span class="o"&gt;)]&lt;/span&gt;

Merged: &lt;span class="o"&gt;[(&lt;/span&gt;9:00, 11:00&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="o"&gt;(&lt;/span&gt;2:00, 5:00&lt;span class="o"&gt;)]&lt;/span&gt;
         ↑               ↑
   Meetings A+B overlap  Meetings C+D &lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;adjacent&lt;span class="o"&gt;)&lt;/span&gt;

Free &lt;span class="nb"&gt;times&lt;/span&gt;: Before 9:00, 11:00-2:00, After 5:00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;When is the room actually free?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  IP Address Blocking
&lt;/h3&gt;

&lt;p&gt;Block: 192.168.1.0 - 192.168.1.50&lt;br&gt;
Block: 192.168.1.45 - 192.168.1.100&lt;br&gt;
Block: 192.168.1.200 - 192.168.1.255&lt;/p&gt;

&lt;p&gt;Without merging, check 3 rules for every connection.&lt;br&gt;
With merging - &lt;br&gt;
[(192.168.1.0, 192.168.1.100), (192.168.1.200, 192.168.1.255)]&lt;/p&gt;

&lt;p&gt;Only 2 rules to check = Faster firewall!&lt;/p&gt;
&lt;h3&gt;
  
  
  Maintenance Downtime
&lt;/h3&gt;

&lt;p&gt;Server or Machine scheduled for maintenance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Maintenance A: Hour 0-5
Maintenance B: Hour 4-8
Maintenance C: Hour 20-24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Merged downtime: [(0, 8), (20, 24)]&lt;br&gt;
Total downtime: 8 + 4 = 12 hours (not 17 if counted individually)&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters in All Cases:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Avoid double-counting overlapping periods&lt;/li&gt;
&lt;li&gt;Optimise checks - fewer ranges to search&lt;/li&gt;
&lt;li&gt;Find gaps - available time slots&lt;/li&gt;
&lt;li&gt;Accurate reporting - real busy vs. free time&lt;/li&gt;
&lt;li&gt;Performance - checking fewer merged ranges vs. many overlapping ones&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The above pattern / method is used by multiple companies around the globe, handling calendar invites, database indexing, network traffic analysis and much more. &lt;/p&gt;

&lt;p&gt;Go ahead, use the above code to increase your applications performance. &lt;/p&gt;

&lt;p&gt;If you want to chat, or reach out don't hesitate to comment below, or  drop me a follow on &lt;a href="https://x.com/grantdotdev" rel="noopener noreferrer"&gt;x/twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Spread Operator and Chaining in JS/TS</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Tue, 30 Sep 2025 13:39:09 +0000</pubDate>
      <link>https://dev.to/grantdotdev/spread-operator-and-chaining-in-jsts-1227</link>
      <guid>https://dev.to/grantdotdev/spread-operator-and-chaining-in-jsts-1227</guid>
      <description>&lt;p&gt;Hey, so I’m sometimes asked how the spread operator works in JS especially when working with chained statements. &lt;/p&gt;

&lt;p&gt;Some confuse the &lt;code&gt;...&lt;/code&gt; (spread) operator as applying to the first element of the chain, spreading the variable before applying chained functions.&lt;/p&gt;

&lt;p&gt;This isn’t correct; it applies to the result of the chain.&lt;/p&gt;

&lt;p&gt;Take this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getLongestWordLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some may think it spreads the &lt;code&gt;sentence&lt;/code&gt; variable first then applies the other chained functions, which you would be right in thinking would throw an error. &lt;/p&gt;

&lt;p&gt;However, due to the way that JS works the &lt;code&gt;.&lt;/code&gt; operator is seen as what's called a primary expression, meaning it takes *&lt;em&gt;precedence *&lt;/em&gt; over every other operator. &lt;/p&gt;

&lt;p&gt;This would be the same as if you wrote your code like this, wrapping your statement in brackets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getLongestWordLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But fortunately for us these extra brackets aren't needed due to the &lt;code&gt;.&lt;/code&gt; expression precedence. &lt;/p&gt;

&lt;p&gt;So in fact what the code is doing is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Replace all &lt;code&gt;.&lt;/code&gt; in a string.&lt;/li&gt;
&lt;li&gt;Split the result on spaces.&lt;/li&gt;
&lt;li&gt;Return the length of each word.&lt;/li&gt;
&lt;li&gt;Spread the lengths array to Math.max()&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Code is read left to right, treating the chain as a single variable / element - so no need to wrap our statement in extra brackets. &lt;/p&gt;

&lt;p&gt;Hope this helps 😁 - did you know this?&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>learning</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>C# LeetCode 268: Missing Number - (Easy)</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Thu, 25 Sep 2025 20:46:18 +0000</pubDate>
      <link>https://dev.to/grantdotdev/c-leetcode-268-missing-number-easy-2ogc</link>
      <guid>https://dev.to/grantdotdev/c-leetcode-268-missing-number-easy-2ogc</guid>
      <description>&lt;p&gt;LeetCode 268: Missing Number&lt;/p&gt;

&lt;p&gt;This problem gives you an array of distinct numbers ranging from 0 to n, with one number missing. Your task is to find that missing number.&lt;br&gt;
At first, I misread the instructions — I assumed the highest number would be the array's maximum value, not realizing that n is both the length of the array and the upper bound of the range [0, n]. That realisation changed everything for me.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;To solve this, we can use a well-known mathematical formula known as Gauss's formula. It calculates the sum of the first n natural numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Sum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works because you can pair numbers in the sequence so that each pair adds up to the same value, take the numbers between 1 and 100:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;1 + 100 &lt;span class="o"&gt;=&lt;/span&gt; 101  
2 + 99  &lt;span class="o"&gt;=&lt;/span&gt; 101  
3 + 98  &lt;span class="o"&gt;=&lt;/span&gt; 101  
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;n&lt;/code&gt; is multiplied by the number of possible pairings (&lt;code&gt;n&lt;/code&gt; + 1). Then as we're doing pairings we need to half this number.&lt;/p&gt;

&lt;p&gt;So, if the array had no missing number, its sum would match this formula. But since one number is missing, the actual sum of the array will be less than the expected sum.&lt;/p&gt;

&lt;p&gt;Thus, the missing number is simply:&lt;br&gt;
&lt;code&gt;Missing = Expected Sum - Actual Sum&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;MissingNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;expectedSum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;actualSum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;actualSum&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;expectedSum&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;actualSum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Walkthrough
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
var numbers &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;0, 3, 1]&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;# sum of all numbers&lt;/span&gt;
0 + 3 + 1 &lt;span class="o"&gt;=&lt;/span&gt; 4

&lt;span class="c"&gt;## all numbers added up using Gauss&lt;/span&gt;
&lt;span class="c"&gt;# 0 -&amp;gt; 3&lt;/span&gt;
n &lt;span class="o"&gt;=&lt;/span&gt; 3
3 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;3 + 1&lt;span class="o"&gt;)&lt;/span&gt; / 2 &lt;span class="o"&gt;=&lt;/span&gt; 6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we can then subtract 6 (Gauss sum) - 4 (actual sum) = 2&lt;/p&gt;

&lt;p&gt;So the missing number would be 2.&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>csharp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode 8: String to Integer (atoi) - Medium</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Sun, 21 Sep 2025 20:58:52 +0000</pubDate>
      <link>https://dev.to/grantdotdev/leetcode-8-string-to-integer-atoi-medium-33om</link>
      <guid>https://dev.to/grantdotdev/leetcode-8-string-to-integer-atoi-medium-33om</guid>
      <description>&lt;p&gt;Mastering LeetCode 8: String to Integer (atoi) &lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple and Efficient Solution
&lt;/h2&gt;

&lt;p&gt;LeetCode's String to Integer (atoi) is a classic medium-difficulty coding problem that challenges you to convert a string representation of a number into an actual integer. While it sounds straightforward, the problem comes with a few twists: you need to handle leading whitespace, account for positive or negative signs, and ensure the result stays within the 32-bit signed integer range. &lt;/p&gt;

&lt;p&gt;In this post, I'll walk you through a highly efficient solution that achieves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0ms runtime (beating 100% of submissions)&lt;/li&gt;
&lt;li&gt;41.85MB of memory (better than 50% of submissions) &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding the Problem
&lt;/h2&gt;

&lt;p&gt;The goal is to take a string, such as "   -42", "4193 with words", or "+123", and convert it into an integer, like -42, 4193, or 123. Here are the key requirements&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ignore leading whitespace: Skip any spaces at the start of the string.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handle signs: Recognise + or - to determine if the number is positive or negative.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stop at invalid characters: If you encounter a non-digit (other than the initial sign), stop processing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Respect 32-bit integer bounds: If the result exceeds the 32-bit signed integer range (-2^31 to 2^31 - 1), return the appropriate boundary value (-2^31 or 2^31 - 1).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Default to 0: If the string is empty or contains no valid digits, return 0.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Approach: Simple and Fast
&lt;/h2&gt;

&lt;p&gt;I designed a solution that prioritises efficiency by working directly with the string's characters and using indexing to avoid unnecessary operations. Here's the step-by-step approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Check for Empty Input: If the string is null or empty, return 0.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skip Whitespace: Loop through the string to bypass leading spaces, avoiding methods like .Trim() to reduce overhead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handle the Sign: Assume the number is positive by default (sign = 1). If a &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; is found, update the sign variable and move to the next character.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build the Number: Process each digit character, converting it to its numeric value and building the result incrementally. Stop if a non-digit is encountered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check Bounds: As the number is built, ensure it stays within the 32-bit integer limits, clamping to &lt;code&gt;int.MaxValue&lt;/code&gt; or &lt;code&gt;int.MinValue&lt;/code&gt; if necessary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apply the Sign: Multiply the result by the sign to get the correct positive or negative value.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is clean, avoids heavy string operations, and handles all edge cases efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;MyAtoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Handle null or empty string&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Skip leading whitespace&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Return 0 if only whitespace&lt;/span&gt;

        &lt;span class="c1"&gt;// Check for sign&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Default to positive&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'+'&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Set sign based on + or -&lt;/span&gt;
            &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Process digits&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDigit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Convert character to digit (e.g., '5' -&amp;gt; 5)&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Check for overflow before adding digit&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxValue&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sign&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxValue&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Build number: multiply by 10 and add new digit&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Apply sign to get final positive or negative result&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;Whitespace Handling: The &lt;code&gt;while (idx &amp;lt; end &amp;amp;&amp;amp; s[idx] == ' ')&lt;/code&gt; loop skips leading spaces. If the string contains only whitespace, we return 0.&lt;/p&gt;

&lt;p&gt;Sign Detection: We default to &lt;code&gt;sign = 1&lt;/code&gt; (positive). If a &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; is found, we set sign to 1 or -1 and advance the index (so the index will be at the first character).&lt;/p&gt;

&lt;p&gt;Number Building: For each digit, we convert the character to its numeric value (e.g., '5' - '0' = 5). We build the number by multiplying the current result by 10 and adding the new digit (e.g., for "123", we do 0*10 + 1 = 1, 1*10 + 2 = 12, 12*10 + 3 = 123).&lt;/p&gt;

&lt;p&gt;Overflow Check: Before adding a digit, we check if result * 10 + digit would exceed int.MaxValue. If so, we return int.MaxValue or int.MinValue based on the sign.&lt;/p&gt;

&lt;p&gt;Final Sign Application: Multiplying result by sign ensures the correct positive or negative output (e.g., 123 * -1 = -123).&lt;/p&gt;

&lt;p&gt;Hope this has helped, as always give me a follow, or drop me a line on &lt;a href="https://x.com/grantdotdev" rel="noopener noreferrer"&gt;twitter/x&lt;/a&gt;&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>csharp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode 206: Reverse Linked List - (Easy)</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Tue, 16 Sep 2025 13:37:28 +0000</pubDate>
      <link>https://dev.to/grantdotdev/leetcode-206-reverse-linked-list-easy-2l6h</link>
      <guid>https://dev.to/grantdotdev/leetcode-206-reverse-linked-list-easy-2l6h</guid>
      <description>&lt;p&gt;Given the head of a singly linked list, reverse the list, and return the reversed list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fte99qnkzslnq1axiixa0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fte99qnkzslnq1axiixa0.png" alt="example of reversal" width="542" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach &amp;amp; Solution
&lt;/h2&gt;

&lt;p&gt;We reverse a linked list by keeping track of two pointers: &lt;code&gt;prev&lt;/code&gt; (the previous node) and &lt;code&gt;curr&lt;/code&gt; (the current node). At each step, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Save the next node so we don’t lose track of the list.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reverse the current node’s pointer to point to prev.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move &lt;code&gt;prev&lt;/code&gt; forward to &lt;code&gt;curr&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move &lt;code&gt;curr&lt;/code&gt; forward to the saved next node.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We continue until &lt;code&gt;curr&lt;/code&gt; is null, meaning we’ve processed all nodes. At that point, prev will be the new head of the reversed list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;ListNode ReverseList(ListNode head)&lt;br&gt;
{&lt;br&gt;
    ListNode prev = null;&lt;br&gt;
    ListNode curr = head;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while (curr != null)
{
    ListNode nextNode = curr.next;
    curr.next = prev;
    prev = curr;
    curr = nextNode;
}

return prev; // new head
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>leetcode</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Extension Members: My New Favourite Feature in C# 14</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Fri, 12 Sep 2025 18:49:31 +0000</pubDate>
      <link>https://dev.to/grantdotdev/extension-members-my-new-favourite-feature-in-c-14-23f1</link>
      <guid>https://dev.to/grantdotdev/extension-members-my-new-favourite-feature-in-c-14-23f1</guid>
      <description>&lt;p&gt;The release candidate of .Net10 was released on the 9th September [2025], which comes with C# 14, and with that comes one of my favourite features, &lt;strong&gt;Extension Members&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concept
&lt;/h2&gt;

&lt;p&gt;The new &lt;code&gt;extension&lt;/code&gt; keyword defines an extension scope; a block where you declare which type your extension methods apply to. All methods inside that scope automatically extend the specified type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before and After
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Current Implementation
&lt;/h3&gt;

&lt;p&gt;So up until C# 14 you would declare an extension method like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToTitleCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
         &lt;span class="n"&gt;CultureInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentCulture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToTitleCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can be cumbersome, and to some junior developers it may not be obvious that the method is an extension method. You would have to know that &lt;code&gt;static + this = extension&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The New Way
&lt;/h3&gt;

&lt;p&gt;Firstly you declare your extensions scope using the new &lt;code&gt;extension&lt;/code&gt; keyword:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// extension methods go here&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This replaces the &lt;code&gt;(this string text)&lt;/code&gt; syntax, now all methods within this block apply to this type. The new syntax makes declaring all your extensions for this type much cleaner and tidier.&lt;/p&gt;

&lt;p&gt;Let's add some basic extensions to show you the concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nf"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToTitleCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;CultureInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentCulture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToTitleCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsPalindrome&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SequenceEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Reverse&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The examples above show just how easy it is to now declare multiple extension methods on the same type, because we can just use the scoped variable &lt;code&gt;text&lt;/code&gt; , rather than having to redefine it each time with &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shorter Method Declarations:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DateTimeExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsWeekend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DayOfWeek&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;DayOfWeek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Saturday&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;DayOfWeek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sunday&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//after&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DateTimeExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsWeekend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DayOfWeek&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;DayOfWeek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Saturday&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;DayOfWeek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sunday&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsBusinessHours&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hour&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsWeekend&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Extensions Can Easily Be Grouped
&lt;/h2&gt;

&lt;p&gt;Before C# 14, you might see a single Helpers class like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Extensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// for DateTime&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsWeekend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// for collections&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;HasDuplicates&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// for strings&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToTitleCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// and so on...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem with this approach:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard to maintain&lt;/strong&gt;– Over time, these Helpers classes can balloon to 500–1,000+ lines of mixed methods, making it difficult for developers to find what they need. – One file can contain extensions for multiple unrelated types.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before C# 14&lt;/th&gt;
&lt;th&gt;After C# 14&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Helpers.cs (mixed types)&lt;/td&gt;
&lt;td&gt;Extensions.cs (type-scoped)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;- DateTime extensions&lt;/td&gt;
&lt;td&gt;- extension(DateTime date) { … }&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;- IEnumerable extensions&lt;/td&gt;
&lt;td&gt;- extension(IEnumerable items) { … }&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;- string extensions&lt;/td&gt;
&lt;td&gt;- extension(string text) { … }&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;- Random other methods&lt;/td&gt;
&lt;td&gt;… neatly grouped per type&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let's take a look how the code may look with the new groupings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Extensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsWeekend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsBankHoliday&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;FormatIsoDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;HasDuplicates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToTitleCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means:&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Natural grouping by type *&lt;/em&gt;– all string extensions must sit inside the extension(string) scope, all DateTime ones inside extension(DateTime).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prevents mixing unrelated stuff&lt;/strong&gt;– you literally cannot write a &lt;code&gt;string&lt;/code&gt; extension in the &lt;code&gt;DateTime&lt;/code&gt; scope. The compiler enforces it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cleaner discoverability&lt;/strong&gt;– IDEs and developers now know exactly where to look. If you collapse your editor, you’ll see one &lt;code&gt;extension(string)&lt;/code&gt; block, one &lt;code&gt;extension(DateTime)&lt;/code&gt; block, instead of a 500+ line god like class of random extensions.&lt;/p&gt;

&lt;p&gt;Before, people dumped everything into Helpers.cs.&lt;/p&gt;

&lt;p&gt;Now, even if your team of developers decides to keep a single file called Extensions.cs, the syntax itself enforces organisation by type, so it’s much less likely to create a “misc soup” of extensions scattered around the file.&lt;/p&gt;

&lt;h2&gt;
  
  
  We Now Have Extension Properties !
&lt;/h2&gt;

&lt;p&gt;New in C#14 we no longer just have to have extension methods, we can now utilise &lt;em&gt;extension properties&lt;/em&gt;. Meaning without huge refactors, or updating multiple places you can easily add Extension properties, to compute results.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsNullOrEmpty&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have a &lt;code&gt;IsNullOrEmpty&lt;/code&gt; property which will be attached to every IEnumerable type within your code base.&lt;/p&gt;

&lt;p&gt;So you can do things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Grant Green"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Roger Red"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bianca Blue"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Before (method style)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No names found!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// After C# 14 (property style)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No names found!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think you'll agree using a property instead of a method makes the code read like it's part of the type itself. It's cleaner, easier to read, and removes the mental overhead of remembering parentheses for simple checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;C# 14’s extension members are a small language change with a big impact!&lt;/p&gt;

&lt;p&gt;They enforce better organisation by type, reducing the mess of “miscellaneous helpers” spread across static classes.&lt;/p&gt;

&lt;p&gt;Extension properties make your APIs feel more natural, allowing boolean checks and computed values to read like first-class members of the type.&lt;/p&gt;

&lt;p&gt;Overall, your code becomes cleaner, more discoverable, and easier for teams to maintain.&lt;/p&gt;

&lt;p&gt;While the compiler doesn’t stop you from scattering extensions across multiple classes, using a consistent type-scoped approach helps keep your codebase tidy and readable.&lt;/p&gt;

&lt;p&gt;In short: if you frequently write helper methods or utilities, C# 14 extension members are worth adopting — they make your codebase feel more structured and your extensions feel like they belong.&lt;/p&gt;

&lt;p&gt;Which types do you most often extend in your projects? I’d love to hear your thoughts in the comments or drop me a follow on &lt;a href="https://x.com/grantdotdev" rel="noopener noreferrer"&gt;twitter/x&lt;/a&gt; to hear when I post more articles like this on DevTo and FreeCodeCamp.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>tutorial</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>C# LeetCode 1792: Maximum Average Pass Ratio - (Medium)</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Thu, 04 Sep 2025 18:14:59 +0000</pubDate>
      <link>https://dev.to/grantdotdev/c-leetcode-1792-maximum-average-pass-ratio-medium-199d</link>
      <guid>https://dev.to/grantdotdev/c-leetcode-1792-maximum-average-pass-ratio-medium-199d</guid>
      <description>&lt;p&gt;&lt;strong&gt;LeetCode 1792: Maximum Average Pass Ratio - (Medium Difficulty)&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intuition
&lt;/h2&gt;

&lt;p&gt;Needed a way to determine which class would yield the best return on adding the extra students.&lt;/p&gt;

&lt;p&gt;Best way to track this in my mind would be tracking a Priority, so a &lt;code&gt;PriorityQueue&lt;/code&gt; would be ideal for this scenario. A &lt;code&gt;PriorityQueue&lt;/code&gt; lets us always select the class with the current highest gain efficiently in O(log n) time per operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Populate the queue with initial values and the gain in pass ratio from adding one student to each class.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For each student, take the class with the highest gain from adding one more passing student.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loop over the priority queue adding up all the ratios and divide by number of classes to get the average ratio.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let's say you have two classes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Pass&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;th&gt;Initial Gain from 1 Student&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0.1667&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;0.0667&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;First assignment:&lt;/p&gt;

&lt;p&gt;Class A has higher gain → gets 1 student → now A = [2,3]&lt;/p&gt;

&lt;p&gt;Next round:&lt;/p&gt;

&lt;p&gt;New gain for A:&lt;br&gt;
(3/4) - (2/3) = 0.75 - 0.6667 = 0.0833&lt;/p&gt;

&lt;p&gt;Class B still has gain:&lt;br&gt;
(4/6) - (3/5) = 0.6667 - 0.6 = 0.0667&lt;/p&gt;

&lt;p&gt;→ A still has higher gain (0.0833 vs 0.0667), so gets another student.&lt;/p&gt;

&lt;p&gt;Now A = [3,4]&lt;/p&gt;

&lt;p&gt;Third round:&lt;/p&gt;

&lt;p&gt;Gain for A now:&lt;br&gt;
(4/5) - (3/4) = 0.8 - 0.75 = 0.05&lt;/p&gt;

&lt;p&gt;Class B gain is still 0.0667&lt;/p&gt;

&lt;p&gt;✅ Now B has higher gain — it gets the next student.&lt;/p&gt;

&lt;p&gt;When solving this problem, you might wonder:&lt;/p&gt;

&lt;p&gt;“Aren’t we already adding one extra student when we calculate the initial gain? Then adding more? Isn’t that overcounting?”&lt;/p&gt;

&lt;p&gt;The answer is no — and here’s why.&lt;/p&gt;

&lt;p&gt;The iniital gain is just a prediction. When we calculate the gain for a class:&lt;/p&gt;

&lt;p&gt;Gain(pass, total) = Ratio(pass + 1, total + 1) - Ratio(pass, total)&lt;/p&gt;

&lt;p&gt;We're not actually adding a student.&lt;br&gt;
We're just asking a "what if" question:&lt;/p&gt;

&lt;p&gt;“If I gave one extra passing student to this class, how much would its pass ratio improve?”&lt;/p&gt;

&lt;p&gt;This helps us prioritize which class would benefit the most if it were chosen next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;MaxAverageRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;extraStudents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pq&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;PriorityQueue&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
            &lt;span class="n"&gt;Comparer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CompareTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Populate the queue with initial values&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enqueue&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Gain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Distribute extra students&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;extraStudents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dequeue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
            &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
            &lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enqueue&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Gain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// After distribution, calculate final average&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dequeue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;CalculateRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;CalculateRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;Gain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CalculateRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CalculateRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>csharp</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>leetcode</category>
    </item>
    <item>
      <title>LeetCode 168: Excel Sheet Column Title (Easy)</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Sat, 30 Aug 2025 17:00:11 +0000</pubDate>
      <link>https://dev.to/grantdotdev/leetcode-168-excel-sheet-column-title-easy-3mbc</link>
      <guid>https://dev.to/grantdotdev/leetcode-168-excel-sheet-column-title-easy-3mbc</guid>
      <description>&lt;h1&gt;
  
  
  Approach
&lt;/h1&gt;

&lt;p&gt;This problem is essentially a &lt;strong&gt;base-26 conversion&lt;/strong&gt;, where the "digits" are the 26 letters of the alphabet (&lt;code&gt;A–Z&lt;/code&gt;).  &lt;/p&gt;

&lt;p&gt;Like any base conversion, we process the &lt;strong&gt;least significant digit first&lt;/strong&gt; — meaning we figure out the &lt;em&gt;last letter&lt;/em&gt; of the result before the first.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use the modulo operator (&lt;code&gt;% 26&lt;/code&gt;) to find the remainder, which tells us the current character.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Insert each character at the &lt;strong&gt;front&lt;/strong&gt; of the string (or reverse later), since we’re building the result from right → left. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After each step, divide &lt;code&gt;columnNumber&lt;/code&gt; by 26 to move on to the next "digit."  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Important: decrement &lt;code&gt;columnNumber&lt;/code&gt; at the start of each loop (&lt;code&gt;columnNumber--&lt;/code&gt;) because Excel columns are &lt;strong&gt;1-based&lt;/strong&gt;, while our alphabet mapping is &lt;strong&gt;0-based&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Example Flow (columnNumber = 28)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Iteration 1&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: 28
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;columnNumber--&lt;/code&gt; → 27
&lt;/li&gt;
&lt;li&gt;Remainder: &lt;code&gt;27 % 26 = 1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Character: &lt;code&gt;'A' + 1 = 'B'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Result: &lt;code&gt;"B"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Update columnNumber: &lt;code&gt;27 / 26 = 1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Iteration 2&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;columnNumber--&lt;/code&gt; → 0
&lt;/li&gt;
&lt;li&gt;Remainder: &lt;code&gt;0 % 26 = 0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Character: &lt;code&gt;'A' + 0 = 'A'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Result: &lt;code&gt;"AB"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Update columnNumber: &lt;code&gt;0 / 26 = 0&lt;/code&gt; → stop
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Final result = &lt;code&gt;"AB"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can verify manually:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;27 = 1 full cycle (&lt;code&gt;A → Z&lt;/code&gt;) + 2 more columns (&lt;code&gt;AA, AB&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
csharp
public class Solution {
    public string ConvertToTitle(int columnNumber) {
        var result = new StringBuilder();

        while (columnNumber &amp;gt; 0) {
            columnNumber--; // shift into 0-based
            int remainder = columnNumber % 26;
            result.Insert(0, (char)('A' + remainder));
            columnNumber /= 26;
        }

        return result.ToString();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>csharp</category>
      <category>leetcode</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stop Throwing Exceptions: The ServiceResult&lt;T&gt; Pattern for Clean API</title>
      <dc:creator>Grant Riordan</dc:creator>
      <pubDate>Fri, 29 Aug 2025 13:56:37 +0000</pubDate>
      <link>https://dev.to/grantdotdev/stop-throwing-exceptions-the-serviceresult-pattern-for-clean-api-5fj1</link>
      <guid>https://dev.to/grantdotdev/stop-throwing-exceptions-the-serviceresult-pattern-for-clean-api-5fj1</guid>
      <description>&lt;p&gt;Error handling in APIs can get pretty messy, right?&lt;/p&gt;

&lt;p&gt;Whether it's throwing exceptions for "expected" situations like “User not found,” or dealing with ambiguous null values, traditional error handling approaches often leave us with more questions than answers. But don't worry—there's a better way!&lt;/p&gt;

&lt;p&gt;Imagine you're a waiter taking orders: if a customer orders a dish that’s not available, you don’t throw a tantrum  or drop everything in the kitchen (throw Exception). Instead, you let them know it’s not available and suggest something else. Same idea applies to your API!&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through how the Discriminated Union pattern (using a ServiceResult type) can simplify your error handling, making your code more predictable and easy to maintain.&lt;/p&gt;

&lt;p&gt;In simple terms, a &lt;strong&gt;Discriminated Union&lt;/strong&gt; is a way to define a type that can be one of several distinct types, each with its own properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why Traditional Error Handling Doesn’t Cut It&lt;/li&gt;
&lt;li&gt;The ServiceResult Pattern&lt;/li&gt;
&lt;li&gt;Usage Example&lt;/li&gt;
&lt;li&gt;Benefits of This Approach&lt;/li&gt;
&lt;li&gt;Real-World Error Handling&lt;/li&gt;
&lt;li&gt;Separation of Concerns&lt;/li&gt;
&lt;li&gt;Flow of Code Example&lt;/li&gt;
&lt;li&gt;Caveats and Considerations&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why Traditional Error Handling Doesn’t Cut It
&lt;/h2&gt;

&lt;p&gt;When building APIs or services, one of the first design decisions you’ll face is how to represent the outcome of an operation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Exceptions aren’t always exceptional (e.g. “User not found” is normal, not an error).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nulls are ambiguous (is it missing, or did something go wrong?).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wrapping results in a &lt;code&gt;ServiceResult&amp;lt;T&amp;gt;&lt;/code&gt; gives clarity: every call is either a success or a failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ServiceResult Pattern
&lt;/h2&gt;

&lt;p&gt;At its core, every service call has two possible outcomes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It succeeds, giving you the entity / object you wanted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It fails, giving you structured error details.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In functional programming, this is often called a &lt;strong&gt;Discriminated Union&lt;/strong&gt; (a type with a fixed set of possibilities). You may be more familiar with union types if using for example Typescript.&lt;br&gt;
In C# these don't exist, however, we can express this cleanly with &lt;code&gt;records&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Is is my interpretation is below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TEntity&lt;/span&gt; &lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ErrorType&lt;/span&gt; &lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;FromSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TEntity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;FromFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ErrorType&lt;/span&gt; &lt;span class="n"&gt;errorType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errorType&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is the implementation of the ErrorType enum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ErrorType&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Validation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Conflict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Unexpected&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Here’s what’s happening:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Success&lt;/strong&gt; → wraps the entity so you know the operation worked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Failure&lt;/strong&gt; → captures one or more error messages and an error type (NotFound, Conflict, etc.).&lt;/p&gt;

&lt;p&gt;Instead of manually creating new instances of &lt;code&gt;Success&lt;/code&gt; or &lt;code&gt;Failure&lt;/code&gt;, the factory methods &lt;code&gt;FromSuccess&lt;/code&gt; and &lt;code&gt;FromFailure&lt;/code&gt; let you do it with one simple line of code. It's like a shortcut to avoid any mistakes or extra boilerplate.&lt;/p&gt;

&lt;p&gt;This gives you a predictable, strongly-typed contract. Whenever you call a service, you must deal with either Success or Failure. &lt;/p&gt;

&lt;p&gt;Here is an example of how ServiceResult and ErrorTypes could be used:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Case&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;th&gt;Why it’s useful&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Entity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Normal outcome, strongly typed result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Errors[]&lt;/code&gt;, &lt;code&gt;ErrorType&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Clear reason for failure, caller knows what broke&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation Failure&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Errors[]&lt;/code&gt;, &lt;code&gt;Validation&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Communicates bad input without exceptions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not Found&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Errors[]&lt;/code&gt;, &lt;code&gt;NotFound&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Expresses absence cleanly (instead of null/404)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conflict&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Errors[]&lt;/code&gt;, &lt;code&gt;Conflict&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Useful for concurrency/duplicate key scenarios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database/Server&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Errors[]&lt;/code&gt;, &lt;code&gt;Database&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Lets you bubble up infra issues in a controlled way&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unexpected Exception&lt;/td&gt;
&lt;td&gt;(thrown, not returned)&lt;/td&gt;
&lt;td&gt;Reserved for truly exceptional conditions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If the operation fails, you get one or more error messages and an ErrorType enum.&lt;/p&gt;

&lt;p&gt;This gives the caller enough context to decide what to do next — maybe return a 404, maybe log an error, maybe retry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage Example
&lt;/h2&gt;

&lt;p&gt;Now that we’ve got our ServiceResult type, let’s see what it looks like in practice.&lt;/p&gt;

&lt;p&gt;Imagine you’re building a movie service, and you need to update a movie. Instead of throwing an exception when the movie isn’t found, you return a Failure result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Service layer - MovieService.UpdateAsync()&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;UpdateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UpdateMovieRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;movie&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;movie&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Movie not found"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotFound&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to notice here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No exceptions&lt;/strong&gt; for expected outcomes (Movie not found is normal, not exceptional).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistent shape:&lt;/strong&gt; every exit path returns a ServiceResult.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexible:&lt;/strong&gt; you can add richer error context over time (Validation, Conflict, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then in your API handler (controller/endpoint), you can use pattern matching to decide what to return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;movieService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UpdateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;MapErrorTypeToStatusCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unexpected result type"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the controller stays thin — no exception handling logic, no try/catch bloat — just clear translation of service outcomes into HTTP responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of This Approach
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Predictable&lt;/strong&gt;: Callers must handle both success and failure, making bugs less likely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expressive&lt;/strong&gt;: You can return multiple errors, not just a single exception message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performant&lt;/strong&gt;: You avoid throwing/catching exceptions for normal control flow.&lt;/p&gt;

&lt;p&gt;Modern C#: Uses records and pattern matching — concise, readable, and type-safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Error Handling
&lt;/h2&gt;

&lt;p&gt;So far we’ve only looked at simple success/failure outcomes, but real-world services often hit database or infrastructure errors. Traditionally, you’d wrap service logic in try/catch and bubble exceptions up to the controller — which makes your API code messy and inconsistent.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;ServiceResult&amp;lt;TEntity&amp;gt;&lt;/code&gt;, we can catch exceptions inside the service and still return a clean, predictable result.&lt;/p&gt;

&lt;p&gt;Here’s an example for deleting a movie:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;DeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;movieResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;movieResult&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbUpdateException&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Database error while deleting movie {MovieId}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;$"Failed to delete movie: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what’s happening here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected errors&lt;/strong&gt; (movie not found) are modeled as failures with ErrorType.NotFound.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unexpected errors&lt;/strong&gt; (like DbUpdateException) are caught and translated into &lt;code&gt;ErrorType.Database&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The calling code doesn’t need to care whether it was a validation error, missing data, or a DB issue — it just sees Failure and can respond appropriately.&lt;/p&gt;

&lt;p&gt;Here’s what the API handler looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DeleteMovieRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;movieService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;failedResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;failedResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;AddError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ErrorsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;MapErrorTypeToStatusCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failedResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Deleted movie with ID: {MovieId}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OkAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DeleteMovieResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No try/catch in the controller, no exception mapping logic scattered around.&lt;br&gt;
All failure handling is centralized in the service, while the API handler simply translates ErrorType → HTTP status code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Separation of Concerns:
&lt;/h2&gt;

&lt;p&gt;Encourages separation of concerns as services don’t need to know about HTTP or status codes.&lt;/p&gt;

&lt;p&gt;Endpoints/controllers can translate ServiceResult.Failure → 400/404/500 as appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ServiceResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorType&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Validation&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotFound&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ErrorType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conflict&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;409&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ErrorsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a much cleaner alternative than handling multiple custom exception types in your API handler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flow of Code Example:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;                   +----------------------+
                   |   Service Call       |
                   +----------------------+
                            |
                            v
             +------------------------------+
             |  Was the operation a success?|
             +------------------------------+
              /                        &lt;span class="err"&gt;\&lt;/span&gt;
             /                          &lt;span class="err"&gt;\&lt;/span&gt;
            v                            v
+-------------------+         +--------------------------+
|   Success         |         |   Failure                |
|-------------------|         |--------------------------|
|   Return Entity   |         |   Error Type (e.g.       |
|   (TEntity)       |         |   Validation, NotFound,  |
+-------------------+         |   Conflict, Database,    |
                              |   Unexpected)            |
                              +--------------------------+
                                       |
                                       v
                           +--------------------------+
                           | Return Error Details     |
                           | (Errors[], ErrorType)    |
                           +--------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caveats and Considerations
&lt;/h2&gt;

&lt;p&gt;While the ServiceResult pattern is straightforward and provides clarity, it's important to be mindful of the context in which it's applied. In smaller applications with very simple error handling needs, this pattern might feel like overkill, but as your system grows and complexity increases, the benefits far outweigh the initial overhead. &lt;/p&gt;

&lt;p&gt;One potential challenge is ensuring that your &lt;code&gt;ErrorType&lt;/code&gt; enum is comprehensive enough to cover all potential failure scenarios. If you miss a common error type, the pattern might lose some of its expressiveness. However, with proper design and planning, this pattern keeps error handling clean, maintainable, and easy to extend as your app evolves. Ultimately, it encourages good separation of concerns and helps avoid clutter in your API handlers.&lt;/p&gt;

&lt;p&gt;The key takeaway is that it offers a solid, scalable foundation for error handling, and once in place, it keeps your codebase more predictable and robust in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;For expected outcomes (like a user not found or bad input), use &lt;code&gt;ServiceResult&amp;lt;T&amp;gt;&lt;/code&gt; to return a structured Failure result. This is part of your normal control flow.&lt;/p&gt;

&lt;p&gt;For truly exceptional, unexpected issues (like a database connection failure), let exceptions be thrown. This prevents messy try/catch blocks in your service and API layers.&lt;/p&gt;

&lt;p&gt;Centralise logic; by catching infrastructure exceptions (like &lt;code&gt;DbUpdateException&lt;/code&gt;) inside your service and converting them to a &lt;code&gt;ServiceResult.Failure&lt;/code&gt;, you keep your API handlers clean and focused on translating outcomes into HTTP responses."&lt;/p&gt;

&lt;p&gt;What do you think of this pattern? Do you use a similar approach, or do you prefer a different method for handling API errors? Share your thoughts in the comments!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>csharp</category>
      <category>api</category>
    </item>
  </channel>
</rss>
