The .NET Thread: For all things .NET

ShuggyCoUk

Ars Tribunus Angusticlavius
9,975
Subscriptor++
I like that it's consistent way to add extension properties and can add static members. But it didn't seem all that transformative. It's not adding Type classes or anything.

The example in the video is not that transformative. You eliminate the () whoop. They aren't accessible by reflection on Person so the distinction of a property verses a (single/pair) of get/set is weak.
It's good. I like the consistency of the syntax with declaring a type as that's normally what you do and the discoverability.

Really the trick is the implicit or explicit and I don't think it's really meaningful in the example - the nice aspect is avoiding the brittle base class problem.

Where you could use it is somewhat better (but still not great) poor man's discriminated unions which he mentions. But you still have to do alll the plumbing/casting yourself.

like so (no clue if this works with generics or the syntax for that. Remove the <T> and replace the other T with object if that works)
Also no clue if the inner class trick works or not, YMMV

Code:
// Leaf of T value
// Node of Tree<T> left *  Tree<T> right
public sealed class Tree<T>
{
    // the space wasted here is why - in managed languages with deterministic GCs like C# and Java
    // sub class based implementations are likely better in perf
    // You can't actually make C++ style union types - but still they can be very useful in some areas
    private  readonly bool _isLeaf;
    private  readonly T _value;
    private  readonly Tree<T> _left;
    private  readonly Tree<T> _right;

    // assume constructors for each, likely static Make methods and the like that guarantee
   // the invariants

    public explicit extension Leaf for Tree<T> Person
    { 
        public T Value => this._value;
    }

    public explicit extension Node for Tree<T> Person
    { 
        public Tree<T> Left => this._left;
        public Tree<T> Right => this._right;
    }

    public TResult Apply(Func<Leaf, TResult> onLeaf, Func<Node, TResult> onNode)
    {
        return _isLeaf ? onLeaf(((Leaf)this)) : onNode(((Node)this))?
   
    }

    // But actually more useful is hiding things entirely anyway, which doesn't need extension types,
    // I include it here to demonstrate
    public TResult Fold(Func<T,TResult> onLeaf, Func<TResult,TResult,TResult> combine)
    {
              // You could make this out of Apply. 
              // But it would be (without nuts amount of compiler work) very slow
              // and an absolute bitch to debug
             // This would also blow the stack - you'd write it non recursively
             if (_isLeaf)
             { 
                 return onLeaf(_value);
             }
             return combine(_left.Fold(onLeaf, combine), _right.Fold(onLeaf, combine))?
    }

The key thing is the Apply bit would give you the relevant "types" in the callbacks without actually sub classing. Not sure it gets you much though because there's still the tedious manual apply. GADT without pattern matching knowing about them aren't very nice basically.[/code]
 

nimro

Ars Tribunus Militum
2,097
Subscriptor++
Here's Microsoft's What's new in C# 13 article so that you don't have to watch obnoxious youtubers.

For params:
The params modifier isn't limited to array types. You can now use params with any recognized collection type, including System.Span<T>, System.ReadOnlySpan<T>, and types that implement System.Collections.Generic.IEnumerable<T> and have an Add method. In addition to concrete types, the interfaces System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.Generic.ICollection<T>, and System.Collections.Generic.IList<T> can also be used.

The extension types stuff isn't in public preview so not in that article, there's an explainer in the 2024 Build blog.