Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's new in .NET 8 Preview 1 #8133

Closed
3 tasks
leecow opened this issue Jan 24, 2023 · 26 comments
Closed
3 tasks

What's new in .NET 8 Preview 1 #8133

leecow opened this issue Jan 24, 2023 · 26 comments

Comments

@leecow
Copy link
Member

leecow commented Jan 24, 2023

What's new in .NET 8 Preview 1

This issue is for teams to highlight work for the community that will release in .NET 8 Preview 1

To add content, use a new conversation entry. The entry should include the team name and feature title as the first line shown in the template below.

Required

## Team Name: Feature title

[link to the tracking issue or epic item for the work]

Tell the story of the feature and anything the community should pay particular attention 
to be successful in using the feature.

Optional

Below are three additional items to consider. These will help the .NET 8 blog team and the community throughout the release.

  • Link to documentation.
    • Where can we send people to learn more about the feature?
  • Link to where you'd like people to provide feedback for this feature.
    • Where can people best comment on the direction of this feature?
  • Whether you would like assistance from the .NET 8 writers to craft a story for this feature.

Index of .NET 8 releases

Preview 1: #8133
Preview 2: #8134
Preview 3: #8135
Preview 4: #8234
Preview 5: https://github.com/dotnet/core/issues
Preview 6: https://github.com/dotnet/core/issues
Preview 7: https://github.com/dotnet/core/issues
RC 1: https://github.com/dotnet/core/issues
RC 2: https://github.com/dotnet/core/issues

@jkotas
Copy link
Member

jkotas commented Jan 24, 2023

NativeAOT support for macOS x64 and arm64. Thank Filip Navara for contributing it.

@jkotas
Copy link
Member

jkotas commented Jan 24, 2023

NativeAOT binary size improvements, in particular on Linux. Size of native AOT compiled HelloWorld on Linux x64 improved from xxx MB in .NET 7 to yyy MB in .NET 8 Preview 1 (fill in actual numbers based on where we land after the cutoff). cc @MichalStrehovsky

@bartonjs
Copy link
Member

BCL: Utility methods for working with randomness

dotnet/runtime#73864

Both System.Random and System.Security.Cryptography.RandomNumberGenerator have gained utility methods for randomly choosing items from the input set ("with replacement"), called GetItems, and for randomizing the order of a span, called Shuffle.

Shuffle is useful in reducing training bias in Machine Learning (so the first thing isn't always training, and the last thing always test):

YourType[] trainingData = LoadTrainingData();
Random.Shared.Shuffle(trainingData);

IDataView sourceData = mlContext.Data.LoadFromEnumerable(trainingData);

DataOperationsCatalog.TrainTestData split = mlContext.Data.TrainTestSplit(sourceData);
model = chain.Fit(split.TrainSet);

IDataView predictions = model.Transform(split.TestSet);
...

Shall we play a game? How about Simon?

private static ReadOnlySpan<Button> s_allButtons = new[]
{
    Button.Red,
    Button.Green,
    Button.Blue,
    Button.Yellow,
};

...

Button[] thisRound = Random.Shared.GetItems(s_allButtons, 31);
// rest of game goes here ...

@MichalStrehovsky
Copy link
Member

MichalStrehovsky commented Feb 3, 2023

CLR AppModel team: NativeAOT size improvements

dotnet/runtime#79003

Option to publish as Native AOT was first introduced in .NET 7. In .NET 8, we're refining some of the fundamentals such as size. Publishing app with Native AOT creates a fully self-contained version of you app that doesn't need a runtime - everything is included in a single file. We worked on making this single file smaller. Linux builds are now up to 50% smaller.

Here's the sizes of a Hello World app with Native AOT that includes the entire .NET runtime:

.NET 7 .NET 8 Preview 1
Linux x64 (with -p:StripSymbols=true) 3.76 MB 1.84 MB
Windows x64 2.85 MB 1.77 MB

On Linux, we've also removed the dependency on libstdc++: simple apps will be able to run on from scratch Alpine Linux containers with no additional dependencies. We'd like to thank Adeel Mujahid (am11 on GitHub) for contributing it in dotnet/runtime#76705.

@jkotas
Copy link
Member

jkotas commented Feb 3, 2023

we've also removed the dependency on libstdc++: simple apps will be able to run on from scratch Alpine Linux containers with no additional dependencies.

The removal of libstdc++ dependency is unrelated to experiments with "from scratch" Linux containers. I would avoid mentioning "from scratch" containers here. If we want to talk about "from scratch" Linux containers in preview blog posts, we need do put in place testing and documentation first.

@eiriktsarpalis
Copy link
Member

eiriktsarpalis commented Feb 6, 2023

System.Text.Json Improvements

We're continuing to improve System.Text.Json, particularly with respect to performance and reliability enhancements of the source generator when used in conjunction with ASP.NET core in NativeAOT applications. Here's a list of new features that were shipped in Preview 1:

Missing member handling dotnet/runtime#79945

It is now possible to configure object deserialization behavior, whenever the underlying JSON payload includes properties that cannot be mapped to members of the deserialized POCO type. This can controlled by setting a JsonUnmappedMemberHandling value, either as an annotation on the POCO type itself, globally on JsonSerializerOptions or programmatically by customizing the JsonTypeInfo contract for the relevant types:

JsonSerializer.Deserialize<MyPoco>("""{"Id" : 42, "AnotherId" : -1 }"""); 
// JsonException : The JSON property 'AnotherId' could not be mapped to any .NET member contained in type 'MyPoco'.

[JsonUnmappedMemberHandling(JsonUnmappedMemberHandling.Disallow)]
public class MyPoco
{
     public int Id { get; set; }
}

Source generator support for required and init properties dotnet/runtime#79828

The source generator now supports serializing types with required and init properties, as is currently supported in reflection-based serialization.

Interface hierarchy support dotnet/runtime#78788

System.Text.Json now supports serializing properties from interface hierarchies:

IDerived value = new Derived { Base = 0, Derived =1 };
JsonSerializer.Serialize(value); // {"Base":0,"Derived":1}

public interface IBase
{
    public int Base { get; set; }
}

public interface IDerived : IBase
{
    public int Derived { get; set; }
}

public class Derived : IDerived
{
    public int Base { get; set; }
    public int Derived { get; set; }
}

Snake Case and Kebab Case dotnet/runtime#69613

The library now ships with naming policies for snake_case and kebab-case property name conversions. The can be used similarly to the existing camelCase naming policy:

var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
JsonSerializer.Serialize(new { PropertyName = "value" }, options); // { "property_name" : "value" }

The following naming policies are now available:

namespace System.Text.Json;

public class JsonNamingPolicy
{
    public static JsonNamingPolicy CamelCase { get; }
    public static JsonNamingPolicy KebabCaseLower { get; }
    public static JsonNamingPolicy KebabCaseUpper { get; }
    public static JsonNamingPolicy SnakeCaseLower { get; }
    public static JsonNamingPolicy SnakeCaseUpper { get; }
}

Credit to @YohDeadfall for contributing the implementation.

Add JsonSerializer.MakeReadOnly() and IsReadOnly APIs dotnet/runtime#74431

The JsonSerializerOptions class has always been using freezable semantics, so far however freezing could only be done imlpicitly by passing the instance to one of the JsonSerializer methods. The addition of the new APIs makes it possible for users to explicitly control when their JsonSerializerOptions instance should be frozen:

public class MySerializer
{
    private JsonSerializerOptions Options { get; }

    public MySerializer()
    {
          Options = new JsonSerializerOptions(JsonSerializerDefaults.Web) { Converters = { new MyCustomConverter() } };
          Options.MakeReadOnly(); // Make read-only before exposing the property.
    }
}

@lambdageek
Copy link
Member

Mono: .NET Hot Reload supports adding instance fields, properties and events

dotnet/runtime#63643

.NET on mobile and WebAssembly now supports adding instance fields, properties and events to existing classes when using Hot Reload. This also enables other C# and Razor language features that use instance fields under the hood, such as certain types of C# lambdas and some uses of Razor's @bind directive.

@lambdageek
Copy link
Member

WebAssembly: experimental "Webcil" a new container format for .NET assemblies

dotnet/runtime#80807

In some environments, firewalls and anti-virus tools prevent .NET WebAssembly applications from functioning correctly because .NET .dll files are prevented from being downloaded onto users' machines, or they're quarantined by the AV software when discovered in a browser's cache directory.

As a potential workaround, the wasm-experimental workload now supports a new .webcil file format that can be used to serve .NET assemblies.

Quick start guide:

  1. Install the wasm-experimental workload: dotnet install wasm-experimental
  2. Create a new app: dotnet new wasmbrowser
  3. Add the WasmEnableWebcil property to the .csproj file:
       <PropertyGroup>
          <WasmEnableWebcil>true</WasmEnableWebcil>
       </PropertyGroup>
  4. Run the app and verify in the browsers DevTools that .webcil files are being downloaded, not .dll.

Note: Webcil is not supported in Blazor WebAssembly apps in this preview. It will be enabled in a later preview

If you find that your AV or firewall still flags .webcil files as malicious, please file an issue

@thaystg
Copy link
Member

thaystg commented Feb 6, 2023

Mono: Debugging .NET WebAssembly App supports loading symbols from symbol server as configured in Visual Studio

dotnet/runtime#79284

When debugging .NET WebAssembly apps, the debugger will now download symbol data from symbol file locations that are configured in visual studio preferences (see screenshot, below). This will improve the debugging experience for applications that use NuGet packages.
image

@JulieLeeMSFT
Copy link
Member

JulieLeeMSFT commented Feb 8, 2023

CodeGen

Community PRs (Many thanks to JIT community contributors!)

Cloud Native

  • PR#79709 removed helper calls for non-gc static fields, and PR#80969 optimized static fields of gc types.
  • PR#80831 devirtualizes casts to interfaces with single implementations.

Arm64

Arm64 performance improvement work is ongoing as planned in Issue#77010.

AVX-512

.NET 8 will support the AVX-512 ISA extensions as planned in Issue#77034.

General SIMD improvements

  • PR#77562 implemented additional intrinsics for newly approved APIs on Vector64/128/256/512<T> and Vector<T> defined in Issue#76593.
  • PR#79720 implemented Vector2/3/4 and Vector<T> using HWIntrinsics.
  • PR#77947 vectorized String.Equals for OrdinalIgnoreCase.

PGO

Fundamental PGO improvements are in progress as planned in Issue#74873.

  • A new JIT tier is introduced to instrument only hot Tier0 and R2R code. This means you no longer need to disable ReadyToRun and sacrifice startup time to have Full PGO level of performance benefits: PR#70941
  • PR#80481 enabled edge based profiles for all scenarios.
  • Building pred list has moved to very early stage of JIT: PR#80625, PR#80856, PR#81288, PR#81246, PR#81196, PR#81000, and PR#80891.

Loop Optimizations

  • PR#75140 supports delegate GDV guards in loop cloning.
  • PR#80353 extended loop unrolling optimization

General Optimizations

  • @SingleAccretion enabled promotion of multi-reg Long variables on 32 bit unblocking field enregistration in PR#76263.
  • PR#77103 implemented a new tail merging optimization as proposed in Issue#8795.
  • PR#81055 ensures that Span<T>.Length and ROSpan<T>.Length are recognized as “never negative”.
  • PR#79346 added an early liveness pass that allows the JIT to remove a lot of unnecessary struct copies when passing struct arguments.
  • PR#77874 removed unnecessary zero/sign-extending instructions for some simple operations involving small integer types.
  • String literals, typeof(), static fields are moved to Non-GC Heap via PR#49576, PR#75573, and PR#76112.
    • It allowed JIT to omit GC write barriers in certain cases PR#76135.
    • typeof(..) no longer needs a helper call in most cases, e.g.:
      Type GetMyType() => typeof(string);
      ; Method MyType():System.Type:this
      -      4883EC28             sub      rsp, 40
      -      48B918083857FC7F0000 mov      rcx, 0x7FFC57380818
      -      E80DE8AB5F           call     CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
      -      90                   nop      
      -      4883C428             add      rsp, 40
      +      48B8B800000364020000 mov      rax, 0x264030000B8 ; 'System.String'
             C3                   ret      
      -; Total bytes of code: 25
      +; Total bytes of code: 11
  • A batch of improvements for static and static readonly fields PR#77102, PR#77593, PR#77354, PR#77737, PR#78593, PR#78736 and PR#78783
  • A good example of what JIT is now capable of folding in .NET 8 is the expression shown in PR#81005.

JIT Throughput Improvements

  • PR#80265 converted JitHashTable iteration to range-based for to improve throughput by 0.22%.

@tannergooding
Copy link
Member

.NET Libraries - System.Numerics and System.Runtime.Intrinsics

We reimplemented Vector256<T> to internally be 2x Vector128<T> ops where possible: dotnet/runtime#76221. This allows partial acceleration of some functions when Vector128.IsHardwareAccelerated == true but Vector256.IsHardwareAccelerated == false, such as on Arm64.

Added the initial managed implementation of Vector512<T>: dotnet/runtime#76642. Much like the previous work item, this is implemented interanlly as 2x Vector256<T> ops (and therefore indirectly as 4x Vector128 ops). This allows partial acceleration of some functions even when Vector512.IsHardwareAccelerated == false. -- NOTE: There is no direct acceleration for Vector512 yet, even when the underlying hardware supports it. Such functionality should be enabled in a future preview.

Rewrote Matrix3x2 and Matrix4x4 to better take advantage of hardware acceleration: dotnet/runtime#80091. This resulted in up to 48x perf improvements for some benchmarks. 6-10x improvements were more common. -- NOTE: Improvements to Quaternion and Plane will be coming in Preview 2

Hardware Intrinsics are now annotated with the ConstExpected attribute: dotnet/runtime#80192. This ensures that users are aware when the underlying hardware expects a constant and therefore when a non-constant value may unexpectedly hurt performance.

Added the Lerp API to IFloatingPointIeee754<TSelf> and therefore to float (System.Single), double (System.Double), and System.Half: dotnet/runtime#81186. This allows efficiently and correctly performing a linear interpolation between two values.

@richlander
Copy link
Member

richlander commented Feb 14, 2023

.NET 8 container images are using Debian 12 (Bookworm)

Every two years, there is both a new Debian and .NET LTS released. Fortunately, the Debian release always ships first, often at the mid-point of the year, while .NET ships closer to the end. This is important because (A) Debian is the default Linux distro in our container images, and (B) we don't change the Debian version in those images for a major release once it is generally available. To ensure that we're preparing everyone for the transition to a new Debian release, we try to adopt it with Preview 1. We did that with .NET 6 Preview 1 and Debian 11 (Bullseye) and we're doing it again with .NET 8 and Debian 12 (Bookworm).

If you pull one of our 8.0 images, you are using Debian 12.

Note that Debian Bookworm includes OpenSSL 3. That doesn't matter for most users since .NET can use both OpenSSL 1.x and 3.x without issue.

@richlander
Copy link
Member

richlander commented Feb 14, 2023

.NET 8 container images are non-root-capable

Container base images are almost always configured to run with the root user and many users keep that configuration in production. That's not always the best approach. For the most part, people do this because they are not aware of other options or because it is a pain to configure every single application to have a different user. Compounding that, container images do not come -- for the most part -- with an user that is appropriate (other than root) for container workloads.

There is a better way. Starting with .NET 8, all container images that we publish will be non-root capable. That means you'll only need to add a one-liner at the end of your Dockerfiles or a similar instruction in your Kubernetes manifests, in order to run as non-root.

This is the one-liner you'll be able to use to configure containers as non-root (for Dockerfiles):

USER app

You can also launch container images with -u app as you can see in the following example.

image

In this example, root-requiring commands are blocked. The presence of the non-root app user is demonstrated.

As part of this change, we changed the default port from port 80 to 8080. This is a breaking change. It was necessary in order to enable the non-root scenario, since port 80 is a privileged port.

We also added a new environment variable to make it easier to change ports: ASPNETCORE_HTTP_PORTS. It accepts a list of ports, which is simpler than the format required by ASPNETCORE_URLS.

That means that you will need to adopt the following pattern to launch container .NET 8 ASP.NET Core images, even .NET 8 images are run as root:

docker run --rm -it -p 8080:8080 aspnetapp

You can change the port back to port 80 by using the environment variable, either the existing or new one:

docker run --rm -it -p 8080:80 -e ASPNETCORE_HTTP_PORTS=80 aspnetapp

If you change the port back to port 80, you cannot run as non-root. Those choices are mutually exclusive.

We will publish a deeper-dive blog post on non-root-capable container images soon.

@richlander
Copy link
Member

.NET 8 container tagging change

.NET 8 preview container images will be exposed with 8.0-preview not 8.0. They will transition to 8.0 with the Release Candidate releases. The goal of this approach is to more clearly describe preview releases as such. Previously, preview releases used stable tags, like 7.0 starting with Preview 1. Those tags are more convenient to use, but might be confusing to some users.

This change was made based on a community request.

For example, to pull the .NET 8 Preview SDK, the following tag will be needed:

docker run --rm -it mcr.microsoft.com/dotnet/sdk:8.0-preview

As stated, we will start publishing images with the 8.0 tag with RC1. The 8.0-preview tag will not be published with the final GA release.

@richlander
Copy link
Member

richlander commented Feb 15, 2023

dotnet publish and dotnet pack produce Release assets by default

Publish and pack verbs are intended to produce production assets, which means that they should produce Release assets. In .NET 8, they will do that by default. People have been asking that for some time. Sorry that it took so long!

This feature is controlled by the PublishRelease and PackRelease boolean properties. They default to true.

It is easiest to demonstrate the feature, with dotnet publish:

/app# dotnet new console
/app# dotnet build
  app -> /app/bin/Debug/net8.0/app.dll
/app# dotnet publish
  app -> /app/bin/Release/net8.0/app.dll
  app -> /app/bin/Release/net8.0/publish/
/app# dotnet publish -p:PublishRelease=false
  app -> /app/bin/Debug/net8.0/app.dll
  app -> /app/bin/Debug/net8.0/publish/

Note that PublishRelease and PackRelease also exist in .NET 7 starting with the 7.0.200 SDK. They are opt-in in .NET 7 and must be set to true to provide the same behavior.

See the breaking change docs:

@JeremyLikness
Copy link
Member

CLR AppModel team: NativeAOT size improvements

dotnet/runtime#79003

Option to publish as Native AOT was first introduced in .NET 7. In .NET 8, we're refining some of the fundamentals such as size. Publishing app with Native AOT creates a fully self-contained version of you app that doesn't need a runtime - everything is included in a single file. We worked on making this single file smaller. Linux builds are now up to 50% smaller.

Here's the sizes of a Hello World app with Native AOT that includes the entire .NET runtime:

.NET 7 .NET 8 Preview 1
Linux x64 (with -p:StripSymbols=true) 3.76 MB 1.84 MB
Windows x64 2.85 MB 1.77 MB
On Linux, we've also removed the dependency on libstdc++: simple apps will be able to run on from scratch Alpine Linux containers with no additional dependencies. We'd like to thank Adeel Mujahid (am11 on GitHub) for contributing it in dotnet/runtime#76705.

@MichalStrehovsky thanks for providing this!

@mmitche
Copy link
Member

mmitche commented Feb 15, 2023

Build your own .NET from dotnet/dotnet

.NET is now buildable on Linux directly from the dotnet/dotnet repository. It uses dotnet/source-build to build .NET runtimes, tools and SDKs. This is the same build that Red Hat and Canonical use to build .NET, for example. Over time, we will extend it to support macOS and Windows.

See build instructions to build the VMR on your own machine. Building in a container will be the easiest approach for many people, since our dotnet-buildtools/prereqs container images contain all required dependencies.

We're calling this new repository a Virtual Mono Repository (VMR). It has the benefits of a true monorepo but is a regularly-updated projection of the many existing repos that contributors work in (more efficiently) ever day. We believe that the split between the VMR and the much smaller "working repos" is the future of the .NET project. We expect that cross-cutting features will be easier to build in the VMR, however, we're not quite that far along yet.

We see this new approach as being a significant step forward in approachability for building .NET as a whole product from source.

Prior to .NET 8, building from source was possible, but required creation of a "source tarball" from the dotnet/installer commit that corresponded to a release. This is no longer necessary. The repository will have tags corresponding to each release, as well as main and release/8.0-previewN branches which continually track the state of the product.

@danroth27
Copy link
Member

@leecow @JonDouglas @lambdageek @thaystg @lewing

These three improvements listed above are for web scenarios, so I'm planning to cover them in the ASP.NET Core blog post:

@richlander
Copy link
Member

richlander commented Feb 16, 2023

.NET 8 + Ubuntu Chiseled container images

We are publishing Ubuntu Chiseled images with .NET 8. This type of image is for developers that want the benefit of appliance-style computing, even more so than you get with regular containers. We expect that Ubuntu chiseled images will be supported in production by both Canonical and Microsoft by the time .NET 8 ships.

We plan to ship to dotnet/monitor images exclusively as Ubuntu Chiseled, starting with .NET 8. That's notable because the monitor images are the one production app image we publish.

Chiseled images have a lot of benefits:

  • Ultra-small images (reduced size and attack surface)
  • No package manager (avoids a whole class of attacks)
  • No shell (avoids a whole class of attacks)
  • Non-root (avoids a whole class of attacks)

You can see the pattern for producing chiseled images, with our aspnetapp sample. It only requires a one-line change.

Chiseled images are currently published to our nightly repos, for .NET 6 and .NET 7 versions.

@richlander
Copy link
Member

richlander commented Feb 16, 2023

Linux support and baseline target

We are updating our minimum baselines for Linux for .NET 8. There are three notable changes.

  • The .NET product will be built targeting Ubuntu 16.04, for all architectures. That's primarily important for defining the minimum glibc version for .NET 8. For example, .NET 8 will fail to even start on Ubuntu 14.04, for example, due to this change.
  • For Red Hat Enterprise Linux (RHEL), we will support RHEL 8+, dropping RHEL 7.
  • We will only publish a support statement for RHEL, however, we intend that support to apply to other RHEL ecosystem distros.

There are no other significant changes. We will continue to support Linux on Arm32, Arm64, and x64 architectures.

Note that these changes only apply to the Microsoft build. Organizations using source-build will make different choices, typically producing one build for and that only works with one distro version, like Ubuntu 24.04.

The following demonstrates the Ubuntu 16.04 glibc version and a pattern for discovering it for other distros.

$ docker run --rm ubuntu:16.04 ldd --version
ldd (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

@svick
Copy link
Contributor

svick commented Feb 16, 2023

@richlander

.NET 8 container images are non-root-capable

I originally misread that as ".NET 8 container images are not root-capable". Have you considered using different phrasing to avoid that confusion?

@richlander
Copy link
Member

richlander commented Feb 16, 2023

Do you have a suggestion?

"Non-root" and "rootless" are the two common terms. They equally apply to the Chiseled image, for example. Whatever the term is we use for that, we should use sometime very similar for these other images, like "non-root-capable" or "rootless-capable".

I guess we could use ".NET 8 container images include a non-root user" as the title and then in the text explain that this makes them "non-root capable". Would that be better?

Part of the issue is that this is mostly a new concept. We talked to the Chainguard folks. They are doing something similar, although their images are much more like our Chiseled ones. In terms of generic images, this approach appears to be new. As a result, there isn't really a term. I agree that between "images with a non-root user" and "non-root-capable images", that the former is simpler and easier to understand language. Either would work, however. Again, this is all new so the terminology feels strange.

Thanks for pushing on this. It is helpful.

@stephentoub
Copy link
Member

stephentoub commented Feb 17, 2023

New Performance-Focused Types in the Core Libraries

Multiple new types have been added to the core libraries to enable developers to improve the performance of their code in common scenarios.

The new System.Collections.Frozen namespace provides FrozenDictionary<TKey, TValue> and FrozenSet<T> collections. These types provide an immutable surface area such that, once created, no changes are permitted to the keys or values. That in turn enables the collections to better optimize subsequent read operations (e.g. TryGetValue) based on the supplied data, choosing to take more time during construction to optimize all future accesses. This is particularly useful for collections populated on first use and then persisted for the duration of a long-lived service, e.g.

private static readonly FrozenDictionary<string, bool> s_configurationData =
    LoadConfigurationData().ToFrozenDictionary(optimizeForReads: true);
...
if (s_configurationData.TryGetValue(key, out bool setting) && setting)
{
    Process();
}

The existing ImmutableArray<T>.Builder type also gained a new method for converting its contents into an ImmutableArray<T> efficiently. .NET 8 introduces DrainToImmutable(), which will return the current contents as an immutable array and reset the builder's collection to a zero-length array, choosing the most efficient approach for doing so. This method can be used instead of conditionally calling ToImmutable() or MoveToImmutable() based on the count of elements.

Another example of a new type that helps a developer to invest a bit of time upfront in exchange for much faster execution later is the new IndexOfAnyValues<T> type. In addition to new methods like IndexOfAnyInRange, new overloads of IndexOfAny have been added that accept an IndexOfAnyValues<T> instance, which can be created to represent a set of T values for which to search. The creation of this instance handles deriving whatever data is necessary in order to optimize subsequent searches. For example, if you routinely search for all ASCII letters and digits plus a few punctuation characters, you might previously have written:

private static readonly char[] s_chars = "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".ToCharArray();
...
int i = str.IndexOfAny(s_chars);

That, however, requires either not doing any kind of vectorization to improve the efficiency of the search, or it involves taking time on each invocation of IndexOfAny to compute the necessary state to speed up the operation. Now instead, it can be written as:

private static readonly IndexOfAnyValues<char> s_chars = IndexOfAnyValues.Create("-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz");
...
int i = str.AsSpan().IndexOfAny(s_chars);

precomputing all of that state once such that it's available for reuse on every subsequent IndexOfAny invocation.

This pattern repeats itself again with the new CompositeFormat type. .NET has long had support for string formatting via APIs like string.Format and StringBuilder.AppendFormat, e.g.

static string GetMessage(int min, int max) =>
    string.Format(CultureInfo.InvariantCulture, "Range from {0} to {1}", min, max);

C# 6 added support for string interpolation, and then C# 10 in conjunction with .NET 6 significantly improved the efficiency of these operations, enabling the same operation to be written as:

static string GetMessage(int min, int max) =>
    string.Create(CultureInfo.InvariantCulture, $"Range from {min} to {max}");

but doing all of the work that can be precomputed (e.g. parsing the format string) at compile time rather than on each invocation of string.Format. That, however, requires the format string to be known at compile time so it can be parsed at compile time... what if it's not known until run-time, such as if it's loaded from a resource file or some other dynamic means? For that, .NET 8 adds the CompositeFormat type. Just as with IndexOfAnyValues<T>, it enables taking an operation that would otherwise need to be done on each use and lifting it out to be done once.

private static readonly CompositeFormat s_rangeMessage = CompositeFormat.Parse(LoadRangeMessageResource());
...
static string GetMessage(int min, int max) =>
    string.Format(CultureInfo.InvariantCulture, s_rangeMessage, min, max);

These new overloads also support generic arguments, to avoid boxing overheads associated with taking everything as object.

.NET 8 Preview 1 also adds support for new performance-focused hashing algorithms, including the new XxHash3 and XxHash128 types that provide implementations of the fast XXH3 and XXH128 hash algorithms.

@agocke
Copy link
Member

agocke commented Feb 21, 2023

One small item that I forgot about until now:

NativeAOT has preview support for MacOS x64 + ARM64 in Preview 1, thanks to a lot of great external contributions from Filip Navara and am11. Filip in particular got MacOS ARM64 working.

Never mind, Jan mentioned this a month ago and I forgot that comment as well :)

@leecow leecow changed the title What's new in .NET 8 Preview 1 [WIP] What's new in .NET 8 Preview 1 Feb 27, 2023
@jbatt33
Copy link

jbatt33 commented Mar 15, 2023

.NET 8 container images are non-root-capable

Does remote debugging into a container image work for non-root containers?

@JonDouglas
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests