4 ms·
I am not current with C#. If I may ask - which features specifically?
by seadan83 2y ago
I am not current with C#. If I may ask - which features specifically?
- CharlieDigital 2y ago455: Primitive Types in Patterns, instanceof, and switch (Preview) https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns https://learn.microsoft.com/en-us/dotnet/csharp/language-ref... https://timdeschryver.dev/blog/pattern-matching-examples-in-csharp#why-pattern-matching https://timdeschryver.dev/blog/pattern-matching-examples-in-... 469: Vector API (Eighth Incubator) https://devblogs.microsoft.com/dotnet/dotnet-8-hardware-intrinsics/ https://devblogs.microsoft.com/dotnet/dotnet-8-hardware-intr... 473: Stream Gatherers (Second Preview) I didn't read it closely enough to determine if this is more like LINQ over C#'s IEnumerable or more like System.Threading.Channels. https://chrlschn.dev/blog/2023/10/dotnet-task-parallel-library-vs-system-threading-channels/ https://chrlschn.dev/blog/2023/10/dotnet-task-parallel-libra... 476: Module Import Declarations (Preview) Some bits of this: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10#global-using-directives https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/cs... But probably more aligned with: https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#adding-a-packagereference https://learn.microsoft.com/en-us/nuget/consume-packages/pac... 477: Implicitly Declared Classes and Instance Main Methods (Third Preview) https://learn.microsoft.com/en-us/dotnet/core/tutorials/top-level-templates https://learn.microsoft.com/en-us/dotnet/core/tutorials/top-... 480: Structured Concurrency (Third Preview) Also feels like one aspect of System.Threading.Channels.
- neonsunset 2y agoAlso add structured concurrency to the list - it's a subset of functionality that arises from simple usage of Task composition and async/await since their introduction. Other than that, note that Panama Vectors are in a rough shape at this moment. Perhaps more feedback from users will make the authors realize that both API and implementation are flawed and map poorly onto many critical parts of algorithm implementations, particularly shuffles. They require a lot more API changes and implementation work to catch up to the current state of Vector APIs in .NET. Of course the reality of not having access to stack buffers and fast off-heap memory allocation/deallocation also hinders the usability. In the end, both of these will be at least partially mitigated with pain of engineers who work on e.g. Lucene, but it's something that comes to C# "naturally" and is easily accessible to a developer that does not have as much prerequisite knowledge.
- CharlieDigital 2y ago> Also add structured concurrency to the list - it's a subset of functionality that naturally arises Task composition and async/await since their introduction. Could be wrong, but the JEP feels like it goes a bit deeper than `async/await` in C#. It feels like a hybrid between Task and Channels but operating at a lower level.
- neonsunset 2y ago> Could be wrong, but the JEP feels like it goes a bit deeper than `async/await` in C#. It feels like a hybrid between Task and Channels but operating at a lower level. Reading the proposal again, it's difficult to agree with this. The proposal talks about concepts that occur naturally when writing asynchronous code with C# (or F#, which has its own pros and cons, but mostly nicer combinators). For example: Response handle() throws ExecutionException, InterruptedException { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { Supplier<String> user = scope.fork(() -> findUser()); Supplier<Integer> order = scope.fork(() -> fetchOrder()); scope.join() // Join both subtasks .throwIfFailed(); // ... and propagate errors // Here, both subtasks have succeeded, so compose their results return new Response(user.get(), order.get()); } } becomes the following in C# async Task<Response> Handle() { var user = FindUser(); var order = FindOrder(); return new(await user, await order); } For the happy path, the difference can be more drastic <T> List<T> runAll(List<Callable<T>> tasks) throws InterruptedException, ExecutionException { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { List<? extends Supplier<T>> suppliers = tasks.stream().map(scope::fork).toList(); scope.join() .throwIfFailed(); // Propagate exception if any subtask fails // Here, all tasks have succeeded, so compose their results return suppliers.stream().map(Supplier::get).toList(); } turns into var results = await Task.WhenAll(tasks); // Or, assuming .GetUser returns Task<GitHubUser> var names = new[] { "java", "dotnet", "golang", "rust-lang", "python" }; var repos = await Task.WhenAll( names.Select(n => GitHubApi.GetUser(n)); And so on and so forth. You can mix and match more complicated flows with CancellationToken and its CancellationTokenSource, TaskCompletionSource, Task.WhenAll/Any/Each (the last one transforms a collection of tasks into an asynchronous sequence of results). Apply exception handling at per-task or task collection level for additional customization. All of this occurs by composing the building blocks, rather than needing complex and bespoke API.
- seadan83 2y agoI appreciate the detailed response - than you!