Exploring DATAS

.NET 8 introduced a new garbage collection feature: Dynamic Adaptation To Application Sizes or DATAS. The inner workings of it are detailed in this post.

This feature tunes the GC to adjust the number of heaps and execute compacting garbage collections more often to have a smaller overall heap size. The result should be a heap size that more closely resembles the actual amount of memory that the application uses.

This feature is great for memory constrained environments or with uneven loads, where memory may be reclaimed between the loads.

In this post I will enable DATAS on my test server application and test client side application to observe the differences in the memory utilization.

Find out more


Implementing ISpanFormattable

I have recently realized that implementing the ISpanFormattable interface enables a type to participate in string interpolation feature of C# in a more efficient way. This realization made me curious how much more efficient it is to implement the corresponding public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = default) method to the standard ToString(). In this blog post I use .NET8 and C# 12.

Implementing ISpanFormattable is not automatically justified for all types, but ones that participate in frequent serialization, such as string interpolation. One can search the types that implement this interface, and it contains most of the primitive and value types (int, Guid, DateTime, etc).

Fortunately I just have one such type on hand that lends itself for the investigation. In a previous blog post, I iterated through a couple of different implementation of FractionalDouble type.

While understanding the details of the FractionalDouble format is less relevant for this post, here is a quick summary:

Find out more


Lookups with Switch Expressions

In a recent PR I have optimized parsing known header values, such CacheControlHeaderValue or MediaTypeHeaderValue.

The original code used a Dictionary<> to look up a Func<string, T?> parsing method, with a string input and a generic type T return type. In this blog post I will summarize the pros and cons of different alternatives that were considered as part of the optimization.

FrozenDictionary

This dictionary contains known Func<string, T?> parsers. These known parsers do not change at runtime. Using a FrozenDictionary would bring performance benefits for the lookup operations. However, freezing the dictionary itself takes time at runtime, because when freezing the new dictionary builds an efficient lookup. This is usually worth the trade-off as freezing only needs to happen once during the lifetime of the application. However, in this case all the contents of this dictionary are known at compile time.

Find out more


Stable and Unstable Sorting for Structs in .NET

Sorting items of a collection is a common task that .NET developers perform. A collection is a data structure that stores multiple values, such as an array, a list, a dictionary, etc.

One common way to sort items of a collection in .NET 8 (and previous .NET versions) is by using LINQ’s OrderBy extension method. LINQ stands for Language Integrated Query, and it is a set of features that allow you to query and manipulate data in various ways. For example, you can use OrderBy to sort a list of numbers:

// Create a list of numbers
List<int> numbers = [3, 1, 2];

// Sort the list using OrderBy
var sorted = numbers.OrderBy(x => x);

Another way to sort items of a collection is by using Array.Sort method. This method works on arrays, which are fixed-size collections of values. For example, you can use Array.Sort to sort an array of numbers in ascending order:

Find out more


Choosing Package Dependencies

Applications today are built upon well-tested, reusable packages. These packages solve the most common aspects of software development, such as logging, authentication, handling HTTP requests, serialization etc.

It is a regular task for a development team to decide which dependency to take on. New features will be built-up these dependencies. A new dependency is an additional responsibility for team: updating and replacing the package without breaking the features built on it. Updating non-breaking or patch releases is a straightforward task, however replacing a library or updating it with breaking changes can be extremely costly. I have come across teams stuck with no longer maintained libraries for years, before the team managed to completely get rid of it. Any security vulnerabilities during this period pose a risk. Therefore, the decision for picking the right library has a huge weight.

I very often observe teams deciding application dependencies based on the packages' popularity. I think this is a fraud way of picking libraries. In this post I summarize the questions that I prefer to ask when I have to introduce a new dependency in an application. I expand on my questions in the space of .NET, C# and NuGet packages. I know some of the languages are vastly different to the NuGet package ecosystem, for example npm is has more and tiny packages. Developers of such ecosystems might take my concerns with a grain of salt and apply that best works for them.

NuGet Packages

Find out more