ProgrammingPro #96: Rust 1.86 Trait Upcasting, GitHub Copilot Security Campaigns, Python Shell Commands, and Dangerous C++ Behaviors
Upgrade Your Mind for Half the Price: Two bestselling tech books. Now 50% off. For a limited time.
Get the Paperback for $57.99 $25.33!
Get the Paperback for $54.99 $25.33!
Welcome to a brand new issue of ProgrammingPro.
In today’s Expert Insight, we bring you an excerpt from the recently published book, C++ Memory Management, which discuses three major categories of dangerous behavior in C++—ill-formed code with no required diagnostics, undefined behavior that compilers may optimize around unpredictably, and implementation-defined behavior that risks portability.
News Highlights: Sonatype flags 18,000 open source malware packages in Q1, most targeting data theft; GitHub rolls out security campaigns with Copilot autofix to reduce security debt; Rust 1.86 adds trait upcasting; and Kotlin, Swift, and Ruby drop from Tiobe’s top 20.
My top 5 picks from today’s learning resources:
The C# Reinforcement Learning Revolution - Breaking Free from Python's Grip🧠
Shadow Table Strategy for Seamless Service Extractions and Data Migrations🫥
Beyond Chatbots: Architecting Domain-Specific Generative AI for Operational Decision-Making🧭
But there’s more, so dive right in.
Stay Awesome!
Divya Anne Selvaraj
Editor-in-Chief
🗞️News and Analysis🔎
Sonatype warns of 18,000 open source malware packages in Q1 2025: Over half of these were designed to exfiltrate sensitive data, signaling a sharp rise in sophisticated software supply chain threats.
GitHub introduces security campaigns to help developers reduce security debt: The new feature will help teams by coordinating fixes across repos with prioritized tasks, templates, and Copilot-assisted autofixes.
Rust language adds trait upcasting: Rust 1.86 introduces long-awaited trait upcasting, allowing trait objects to be upcast to supertrait objects, alongside new APIs, mutable indexing enhancements, and compiler safety improvements.
Kotlin, Swift, and Ruby losing popularity – Tiobe index: The three languages have fallen out of Tiobe’s top 20 programming languages, signaling declining popularity due to platform-specific use and competition from more versatile languages like Python.
EngFlow Makes C++ Builds 21x Faster and Software a Lot Safer: EngFlow has launched the public beta of CMake RE and acquired tipi.build to deliver significantly faster and safer C/C++ builds through remote execution, caching, and modern dependency management tools.
Django 5.2 release touts automatic model importing: The version also introduces support for composite primary keys and easier BoundField overrides, while ending support for earlier 5.x versions.
April 4, 2025: AI updates from the past week: Updates include Claude for Education’s guided learning features, Amazon's new site and SDK for Nova models, and Solo.io’s MCP Gateway for managing AI agent tool sprawl.
🎓Tutorials and Learning Resources💡
Python
🎓Running External Commands in Python (Shell or Otherwise): Explains how to use
subprocess.run()
in Python to execute system commands safely and efficiently.
For more Python resources, go to PythonPro
C# and .NET
💡The C# Reinforcement Learning Revolution - Breaking Free from Python's Grip: Challenges Python’s dominance in reinforcement learning by presenting RLMatrix, a C# framework offering superior debugging, type safety, performance, and production integration for real-world applications.
💼How we ended up rewriting NuGet Restore in .NET 9: Delves into Microsoft's rewrite of NuGet Restore to fix major performance bottlenecks caused by a legacy recursive graph resolution algorithm that failed at scale.
🎓Migrate C# apps from the in-process model to the isolated worker model: Provides a detailed migration guide for moving C# Azure Functions apps from the in-process model to the isolated worker model before support ends in November 2026.
C++ and C
💡C++26: variadic friends: Introduces a new feature coming in C++26 through proposal P2893R3, which will enable you to grant friendship to a pack of types in templates, simplifying patterns like the passkey idiom and CRTP.
🎓STL Demystified: A Practical Guide to C++ Standard Template Library (STL): An example-rich guide covering STL's core components—containers, iterators, algorithms, and function objects—along with detailed demonstrations.
💡Writing C for curl: Covers curl’s coding guidelines and safety practices for writing secure, maintainable C code, including testing, memory management, code style, error handling, and the use of custom helper functions.
Java
🎓Choosing the Right Implementation Between ArrayList and LinkedList: Analyzes algorithm complexity, read/insert performance, iteration cost, and memory usage to help choose the right implementation.
💡JDK 24 Security Enhancements: Compiles the most important security enhancements in the latest Java release including quantum-resistant cryptography with ML-KEM (key encapsulation) and ML-DSA (digital signatures).
💡10 Java-based tools and frameworks for generative AI: Covers tools including Spring AI, LangChain4j, Deeplearning4J, and Jllama among others for tasks like LLM orchestration and vector database integration.
JavaScript and TypeScript
💡On JavaScript's Weirdness: Highlights surprising behaviors with
eval
, loop scoping, falsy values likedocument.all
, inconsistent string iteration due to Unicode, sparse arrays that break array methods, and more.🎓Learning Clojure as a Javascript developer: Compares JavaScript patterns with Clojure idioms using real examples, especially around building strings, destructuring, and using threading macros (
->>
).🎓Use the Gemini API with OpenAI fallback in Typescript: Demonstrates how to implement a fallback strategy between Gemini and OpenAI APIs in TypeScript using the OpenAI TS/JS library.
Go
💡Cutting 70% of Infra Costs with Go: A benchmark between Go, NextJS, Java and GraalVM: Benchmarks REST APIs built with Go (Gin, Chi), Java (Spring Boot, Micronaut, Quarkus), Kotlin, and Node (NestJS), revealing Go (Chi) as the most performant.
💡Common Go Patterns for Performance: Outlines 15 performance patterns across memory, concurrency, I/O, and compiler tuning, covering techniques like object pooling, preallocation, zero-copy, worker pools, atomic ops, and more.
Rust
💡Adaptive Lossless Floating Point (ALP) Rust is faster than C++: A Rust ALP compression implementation achieves 20–50% higher throughput than its C++ counterpart by leveraging Rust’s well-defined float-to-int casting semantics.
🎓Pitfalls of Safe Rust: Explores issues like unchecked arithmetic, unsafe type casting, unbounded inputs, path manipulation quirks, improper use of
unwrap
, and misuse of serialization or default values and more.
Swift
🗞️Swift 6.1 Released: The version introduces concurrency enhancements, trailing comma support across more syntax, package traits for configurable APIs, and productivity-focused diagnostics.
🎓SwiftUI Alert Guide + Code Examples: Explains how to present alerts in SwiftUI using view modifiers, including basic alerts, alerts with custom actions, and data-driven alerts using objects or errors.
PHP
🎓An opinionated HTML Serializer for PHP 8.4: Introduces a serializer built using PHP 8.4’s new
Dom\HTMLDocument
class to produce neatly indented, human-readable HTML output.🎓A cookieless, cache-friendly image proxy in Laravel (inspired by Cloudflare): Outlines how to build a cookieless, cache-friendly image proxy in Laravel, mimicking Cloudflare’s image resizing service.
SQL
🎓Building AI apps? You need sync: Using ElectricSQL, demonstrates how syncing state through a database solves UX and reliability challenges in handling key collaboration needs such as resumability and multi-device support.
💡When parameterization fails: SQL injection in Nim's db_postgres module using parameterized queries: Reveals how Nim's
db_postgres
module can be vulnerable to SQL injection whenstandard_conforming_strings
is disabled, due to flawed manual escaping in its parameterization logic.
Ruby
🎓Setting up Zed with Ruby LSP: Details steps for setup, diagnostics, and troubleshooting, while addressing feature gaps compared to VS Code.
🎓Ruby makes advanced CLI options easy: Explains how Ruby’s built-in
OptionParser
makes building flexible, user-friendly CLI tools easy—without relying on external gems—by showcasing advanced usage.
Kotlin
🗞️Introducing Kotlin-bench: Introduces a benchmark designed to evaluate LLMs on 100 real-world Kotlin and Android development tasks using GitHub issue-PR pairs and unit test validation.
🗞️Bringing Fuzz Testing to Kotlin with kotlinx.fuzz: Introduces a Kotlin-native fuzz testing framework built on Jazzer, enabling developers to uncover edge cases and hidden bugs by generating randomized input for target functions.
🌟Advanced Concepts🚀
Shadow Table Strategy for Seamless Service Extractions and Data Migrations: Introduces a zero-downtime data migration method that maintains a synchronized copy of production data using triggers or CDC, enabling seamless database migrations, microservice extractions, and schema refactoring.
Beyond Chatbots: Architecting Domain-Specific Generative AI for Operational Decision-Making: Argues that LLMs fall short for real-time, domain-specific business decisions and introduces domain-specific generative models as a better alternative.
Architectural Experimentation in Practice: Frequently Asked Questions: Clarifies when to use experiments, how to structure them for actionable outcomes, and how they differ from unstructured exploration.
The single-writer Database Architecture: Explains how Bugsink uses a single-writer database architecture built on SQLite’s concurrency model to ensure stable, consistent, and simple event processing.
JetBrains Terminal: A New Architecture: Introduces JetBrains’ reworked terminal architecture which restores full shell compatibility by returning to a standards-compliant core (JediTerm) while using the IDE’s editor.
🧠Expert Insight📚
Here’s an excerpt from “Chapter 2: Things to Be Careful With" in the book, C++ Memory Management, by Patrice Roy, published in March 2025.
Different kinds of evil
Before delving into some actual practices that require care, it’s interesting to look at the main categories of risks we could run into if our code does not respect the rules of the language. With each such category comes a form of unpleasantness we should strive to avoid.
Ill-formed, no diagnostic required
Some constructs in C++ are said to be Ill-Formed, No Diagnostic Required (IFNDR). Indeed, you will find quite a few occurrences in the standard of “if […], the program is ill-formed, with no diagnostic required.” When something is IFNDR, it means your program is broken. Bad things could happen, but the compiler is not required to tell you about them (indeed, sometimes, the compiler does not have sufficient information to diagnose the problematic situation).
One Definition Rule (ODR) violations, to which we will return in the The ODR section later in this chapter, fall under IFNDR. However, there are other such cases, such as having a global object that has different alignment requirements (through alignas
) in different translation units (different source files, essentially), or having a constructor that delegates to itself either directly or indirectly. Here is an example:
class X {
public:
// #0 delegates to #1 which delegates to #0 which...
X(float x) : X{ static_cast<int>(x) } { // #0
}
X(int n) : X{ n + 0.5f } { // #1
}
};
int main() {}
Note that your compiler might give a diagnostic; it’s just not required to do so. It’s not that compilers are lazy – they might even be unable to provide a diagnostic in some cases! So, be careful not to write code that leads to IFNDR situations.
Undefined behavior
We mentioned Undefined Behavior (UB) in Chapter 1. UB is often seen as a source of headaches and pain for C++ programmers but it refers to any behavior for which the C++ standard imposes no requirement. In practice, this means that if you write code that contains UB, you have no idea what’s going to happen at runtime (at least if you’re aiming for somewhat portable code). Canonical examples of UB include dereferencing a null pointer or an uninitialized pointer: do that and you’ll be in serious trouble.
To compilers, UB is not supposed to happen (code that respects the rules of the language does not contain UB, after all). For that reason, compilers “optimize around” code that contains UB, to sometimes surprising effect: they might begin removing tests and branches, optimizing loops away, and so on.
The effects of UB tend to be local. For instance, in the following example, there is a test that ensures that p
is not null before using *p
in one case, but there is at least one access to *p
that is unchecked. This code is broken (the unchecked access to *p
is UB), so the compiler is allowed to rewrite it in such a way that all tests to verify that p
is not null are effectively removed. After all, the damage would be done if p
were nullptr
, so the compiler is entitled to assume that the programmer passed a non-null pointer to the function!
int g(int);
int f(int *p) {
if(p != nullptr)
return g(*p); // Ok, we know p is not null
return *p; // oops, if p == nullptr this is UB
}
The whole body of f()
could legitimately be rewritten by your compiler as return g(*p)
in this case, with the return *p
statement being turned into unreachable code.
The potential for UB hides in various places in the language, including signed integer overflow, accessing an array out of bounds, data races, and so on. There are ongoing efforts to reduce the number of potential UB cases (there’s even a study group, SG12, dedicated to this effort), but UB will likely remain part of the language for the foreseeable future, and we need to be aware of it.
Implementation-defined behavior
Some parts of the standard fall under the umbrella of implementation-defined behavior, or behavior that you can count on with a specific platform. This is behavior that your platform of choice is supposed to document, but that is not guaranteed to be portable to other platforms.
Implementation-defined behavior occurs in many situations and includes such things as implementation-defined limits: the maximum number of nested parentheses; the maximum number of case labels in a switch statement; the actual size of an object; the maximum number of recursive calls in a constexpr
function; the number of bits in a byte; and so on. Other well-known cases of implementation-defined behavior include the number of bytes in an int
object or whether the char
type is a signed or an unsigned integral type.
Implementation-defined behavior is not really a source of evil, but it can be problematic if one strives for portable code but depends on some non-portable assumptions. It is sometimes useful to spell one’s assumptions in code through static_assert
when the assumption can be validated at compile-time or some similar, potentially runtime mechanisms in order to realize—before it’s too late—that these assumptions are broken for a given target platform.
For example:
int main() {
// our code supposes int is four bytes wide, a non-
// portable assumption
static_assert(sizeof(int)==4);
// only compiles if condition is true...
}
Unless you are convinced that your code will never need to be ported to another platform, strive to rely as little as possible on implementation-defined behavior, and if you do, make sure that you validate (through static_assert
if possible, at runtime if there’s no other choice) and document this situation. It might help you avoid some nasty surprises in the future...
C++ Memory Management was published in March 2025. Packt library subscribers can continue reading the entire book for free or you can buy the book here!
Get the eBook for $33.99 $29.99
🛠️Useful Tools⚒️
MonkeysPaw: A Ruby web framework that generates entire web pages from natural language prompts, using LLMs to interpret and fulfill developer "wishes."
markitdown: A Python tool that converts various file types to Markdown for LLMs, preserving structure for accurate analysis and supporting plugins, format-specific dependencies, and LLM integration.
mcp-go: A Go library that implements the Model Context Protocol, enabling LLM applications to interact with external tools and data through simple, high-level server and tool definitions.
That’s all for today.
We have an entire range of newsletters with focused content for tech pros. Subscribe to the ones you find the most useful here.
If your company is interested in reaching an audience of developers, software engineers, and tech decision makers, you may want to advertise with us.
If you have any suggestions or feedback, or would like us to find you a learning resource on a particular subject, just leave a comment below!