This is looking pretty clean. Unsure if I'll use it anytime soon, but it sounds cool. Unrelated, I really hope they add readonly to the Primary Constructors. Bit annoying that it was pushed to replace those assignment only constructors, but didn't cover the common readonly usecase.
Wow. So many questions. How does serialization play into these extension types? What if you JSON serialize Person? Can extension types have their own private fields/state? Could FavoriteDrink pull from a field that isn’t on Person, but is on Adult.
They can't own state. They are meant to add different behaviors to already existing data based on context in which it is used. I think the better example would be extending some PropertyBag types like ClaimsPrincipal or other Dictionaries with type safe properties.
I don't know, but given that Serialization usually is performed on the instance type using reflection I doubt that these extension methods will be included in the output. They are not really instances, i.e. they don't hold state. As a counter example, assume serialization _does_ work. What would you then expect de-serialization to look like? You can't populate Age with a value since it does not have a backing field to store it. So serialization is bust I am pretty sure.
@@pfili9306 I'm not so sure about that. Check out the example in the official announcement docs. They show an example where classes Person and Organization are pulled in, and each Person object needs an Organization property passed in, but in this example scenario there is only one Organization object for the whole application, making the extra property for Person tedious to assigns. So they make an implicit extension for Organization, add a private static Organization ourOrganization = new Organization("C# Design");, and then add a CreatePerson function that always assigns the new Person object with ourOrganization as the Organization property. The property is static in this case, but I don't see anything mentioning that as a restriction rather than what happened to make sense in the scenario.
Being able to add properties now is a huge deal. What I still sorely miss is being able to take someone's class and say, "Um, actually, this Type DOES Implement this Interface! Here's how!" Struggling to think of examples, but for some older code, it'd be nice to not need to use .Cast to get the correct type all the time, maybe?
I so desperately want to be able to attach an interface to an existing class using extensions. So many times I wished for the convenience of having a method that takes an interface and passing some 3rd party object along except it, of course, doesn't implement my interface. So instead I have to write stupid wrapper classes all the time. Just pretend it has the interface if it already offers all the methods and properties!
Just use functions. Life will be easier. No more class, static, interface, wrapper etc... (ps: it's good to use Interfaces in OOP or code that interact with OOP)
Its been on the cards for a while so I'm glad its almost here. The fact you can now introduce properties is really nice - great way to shape something you don't own or control.
After all these years, I can't believe they're finally giving us extension properties. This is pretty hype as it's more than that as well. Although I have to say I'm a bit disappointed in the explicit extension. Don't get me wrong, it's a great feature. But in your example you check for their age, then inside the conditional branch you do the explicit conversion. The problem with this is that there is nothing tying the age check to the conversion. This relies on the developer to know when such extensions are valid or intended to be used. It would be nice if they added the ability to provide like a where clause on the extension declaration to define when it's valid. Then maybe you could simply do something like `if (person is Adult adult)`. This way you can make extensions only valid in certain contexts, and also be coupled to those contexts. But I mostly work in TypeScript these days and I'm pretty spoiled on the powerful type system there. This is already an absolute game changer as it is and I'm not trying to complain.
I wouldn't be surprised if they build up to something of that nature in a later release after they get feedback on this initial C# 13 implementation of it. I doubt they would put a boolean condition on the ability to cast to the explicit extension type itself. There isn't really a precedent for that, even with generic constraints. Doing so would hide the boolean condition from the calling code entirely (abstracted behind the cast operation). However, I could see there being a "best practice" of defining, in such explicit extension scenarios, a `TryCreateAdult(out Adult adult)` kind of method that does the boolean check and sets `adult` to `this` when true. That way people would be able to leverage pattern matching and naming conventions to achieve that goal. IF that became so commonplace as to be annoying, then they might discuss potential strategies for optimizing the syntax or at least standardizing it. Perhaps with a `TryExtend` magic method, similar to what they do for TryParse and Deconstruct, etc.
The biggest pain point I previously had with extension methods has been with unit testing + Moq. I’m curious how mocking extended types would work with this new feature.
Fun fact: since the `Age` member can return different values by the time you call it, the Framework Design Guidelines book defines as a good practice to keep it as a method instead of a property. They even give the example of something that they consider broken in .NET which is the `DateTime.Now` property - which, according to the authors, should be a method, but it was too late to change by the time they noticed it.
Not really. Most properties don't change value each time you get them. Those who do more often than not, should be methods, according to the Framework Design Guidelines.
@@viniciusvbf22 aah, I misunderstood you. I thought you meant "can change" not "changes every time". Edit: But in this case the Age property wouldn't change every time you called it 🤷♂️
For anyone here confused with extension methods, I will ask you to search about a thing called 'universal function calling syntax', and then to experiment a bit with C# actual extension methods. They don't do anything that is not already possible, but make the code cleaner and more sequential. It is the reason you can write: var arr = [ 1, 2, 3, 4, 5, 6, 7 ]; var even = arr.Where(x => x % 2 == 0).Select(x => x * 3).Select(x => $"Result is: {x}"); Instead of writting: var even = Select(Select(Where(arr, x => x % 2 == 0), x => x * 3), x => $"Result is {x}"); Both things are literally possible to do, but one of them is clearly more annoying, noisy and requires more cursor movimentation (if you don't want to store everything in a local temporary variable, which is also annoying).
To be fair even with the extensions, you would probably write it in a way that is on multiple lines i.e var even = arr .Where(x => x % 2 == 0) .Select(x => x * 3) .Select(x => $"Result is: {x}"); and you would probably write the latter as: var a= arr.Where( x=> x%2 ==0); var b = a.Select(x => x * 3); var even = b.Select(x => $"Result is {x}); The syntax is a bit more concise and readable. But I think the game changer is it makes writing more readable code the easier default. Whereas before it was kind of up to one programmers interpretation, with extensions you are pushed in the direction of writing good code. The only part that is a bit harder to read is that all of the lines eventually return a value that is stored in the variable at the top of the operation. I think if you wanted to go to the full 9s you could have a .StoreAs extension that you wrote at the end. That would make it read better in a left to write fashion, but would likely require more in depth changes to the language so it would become arr .Where(x => x % 2 == 0) .Select(x => x * 3) .Select(x => $"Result is: {x}") .StoreAs(IEnumerable even);
@@NickSteffen No? I don't often find people that would write the version with extensions using intermediate variables, this don't make any sense unless you are doing something very fishy. Also, I'm considering multiple lines, I generally use them as well and with extension methods it feels much natural, sequential and direct. And for the storage part, I think you are just not used to how programming languages work, I really don't think this is a problem per se and I recommend delving into studies to get better at it over time. With time you will be able to see how this all works. But for a brief explanation here, functions return values, and values in C# can be objects that have methods OR extension methods. When you write: var even = ar.Where(x => x % 2 == 0).Select(x => x * 3)...; You are just saying::: take this array, filter all the elements where 'element % 2 == 0'; then take the returned result and map each element on it as 'element * 3'; then take the returned result and map each element on it as 'Result is {element}'; then let the result be returned into the variable attribution. You can write the same thing without extension methods (althought it would take much more work to do so), take a look at the builder pattern and how it is implemented and I think it will be clearer for you how this generally works.
@@diadetediotedio6918 I think you completely misunderstood my answer… The example with intermediate variables with describing was you would do if extensions didn’t exist. It was a counterpoint to your second example on how unreadable it would be. A good programmer would never write it in that unreadable way. My last point was a completely theoretical what if, yes I understand program languages don’t work that way. They also didn’t work “that way” before extension methods were a thing. Fluent/ universal method style is just changing how programming languages work to bend the syntax to how human language works. So the fact that they don’t work that way now is irrelevant to the point. Also C# can in fact work this way in some very limited cases though, since you can declare variables in a dictionary’s TryGetValue method. So for example you can: arr .Where(x => x % 2 == 0) .Select(x => x * 3) .ToDictionary( ( x => x),(x => $“Result is {x}”)) .TryGetValue(6, out int result) Notice how at the end I’m both declaring a value and saving the result into it. You can do the is in some other places like type checks in if statements ex: if( x is string y) Console.WriteLine(y); This type of style is more easily readable for humans as we read continuously in one direction. You don’t have to jump back to the top to see where the variable is being saved. You could absolutely change c# to do this in more cases fairly easily. Now would it be a good idea to do that… I’m not sure, it would at least be interesting.
@@NickSteffen My second point was to highlight that writing in the same way you would write using extension methods would be uglier, I'm not saying that necessarily you would do that (althought I'm pretty sure many people would do). If this was your objection then read again my note on storing things as intermediate variables to improve clarity (implied from context). Next, it is not irrelevant. The fact that we can write fluent functions in that manner is precisely because they work in that way, it does not "change how programming languages work" even if it is to align it better with 'how human language works" (which I can partially concede). Your example with dictionary don't make sense as well, it is a very bizarre way of writting what would be much better written as just .First(...) or .FirstOrDefault(...), to create a dictionary you would already need to iterate through all items so there is no advantage on using it. Also, this works that way in this specific case because then you are fundamentally dealing with another resource of the language, a similar result could be achieved using 'ref' and the semantics are not the same, TryGetValue returns something (a boolean confirming the existence of the item) and it stores the result in the out pointer (because at the time C# had not fast and reliable booleans, many languages nowadays don't have an 'out' thing for example). As for the 'x is string y' example, it is another completely different mechanics of the language again, there is nothing to do with how 'out' works. The convenient 'x is string y' is a modern construct (in early C# versions you had to type manually 'x is string' and then '(string)x' or do 'x as string' and then 'x != null'). As of your question about this being more "easily readable" because it reads continuously in one direction, I don't think I necessarily agree with you absolutely on this. I can buy the point that this is better , but I wont that this is the step to follow for many reasons. I know you are not sure about if this is a good idea, but I'll argue as you held that position (so I can focus on responding anyone who is willing to defend it): First of all, because it is untrue, humans also write things in a name -> description fashion, for example when we respond to someone we can do: A. (responds to point A) B. (responds to point B) And when we want to describe something we have a resource in language that is ':', so we can say: something: this is something (explains) Even when I'm writting this response, and when you did wrote your response, you used attribution in this same sense (for example when giving the example, you said 'ex: (code)'). So it is untrue that this is a direction that should be followed by readability. Second, programming is for humans the same way mathematics is also for humans, the same way everything humans do is ultimately for humans, and in mathematics nobody is arguing of how f(x) = y is a terrible syntax and nobody understands it, you are removing the formal aspect of programming which is that makes it easily readable and generally predictable (human language is inherently noisy and ambiguous, this is why even when programming languages try to approximate to human language they keep a safe distance to what is actually reasonable). Third, because this would make a radical rupture between every single language out there that don't work that way. When you make a change that affects the entire way we reason about programs in a specific language, this should be EXTREMELY more justified than that, because then someone writing C# will arrive in another language (like C, C++, Rust, Go, Kotlin, etc) and suddenly everything he knew will not be valid here, this is one of the reasons of why even arguable that indexes in programming languages should start with 1 (because we usually start counting with 1 in human language) this is not necessarily a good idea as it would break many assumptions when moving from one language to another. As for the end, you can also use extension methods to achieve what you want, you can for example write a: public static void StoreAs(this T self, out T @in) => @in = self; And it would work like you wish.
The one feature I would find really good is a way to extend interfaces to these types. If you have an interface like IAge { int Age {get;} }, it would be super cool if you could extend Person so it implicitly implements that interface so you can pass it directly into methods or constructors without having to create a new wrapper around them.
That explicit extension use case is actually interesting. What it almost lets you do (or what that syntax almost seems to let you do on the surface) is have a class more or less inherit from multiple classes at the same time, not just interfaces. Like if there was some sealed class from a third-party library that I wanted to add support for say a custom serialiser system I was making, I could add an extension to that class which defines the serialise and deserialise methods, even though I can't edit that class directly.
Hmmm. Yeah, I'd be interested to know how that works with reflection APIs. In order to REALLY be useful for dynamic situations, you'd need `typeof(Person).GetProperties()` to include stuff like `Age`, etc.
Can't wait for this feature. I hope the IDE will help make it obvious where code is comming from, is some property from third-party library, is it from your own extension or from some other third-party extension library. Otherwise it would be a very confusing trying to some out where some random property is from. 🫠
In kotlin, it’s common to write extension methods for types within your own code base because it allows for utilities that don’t clutter up the code of the class itself. Now take val and var from kotlin, too.
Would these extension properties work for model binding in Maui? They could be useful for adding properties to a model that would previously require a converter.
This looks really good, though I am somewhat sceptical of the practical benefits of explicit extensions. I just can't see them actually being used but I might be wrong. Most wanted feature: anonymous object spread operator like in js/ts e.g. var shirt = { Name = "Shirt", Size = 20 }; var shirtWithDescription = { ...shirt, Description = "A red T-Shirt" } // { Name = "Shirt", Size = 20, Description = "A red T-Shirt" }
I would see the benefits of explicit extensions if they were not tied to a specific type, like for example public explicit extension Named { public string Name { get; } } So you would be able to do structural typing and this would be extremely useful. But I'm not sure if this syntax allows it, as I didn't readed the docs of this yet.
I feel like explicit extensions are really missing some way to enforce whether it can be casted. Like in the example Nick gave, I'd want to actually be able to ensure that person is only an adult if person.Age >= 18.
@@mbpoblet A. It is more ergonomic as "encapsulating the type" would require you to make a wrapping method for each property/method of that same type OR expose it through a property. B. You can use it over generics easily without needing to cast in some specific circumstances (which would allocate memory / this is solvable with wrappers but the friction would be even bigger).
Definitely like the extension properties. Though I'm not sold on explicit extensions since it seems to leave us with 2 overlapping definitions for polymorphism. What's the use case for this?
I wonder if this will be the case for sealed classes from other libraries and how the polymorphism would play in our own library would an adult be a person?
@@rogeriobarretto but sealed classes are sealed for a reason. It's just stupid to provide a feature (inheritance), to provide the tools to control this feature (sealed classes), and then to provide ANOTHER feature to ignore the restrictions (explicit extensions). I believe explicit extensions were invented for anything else except inheriting sealed classes.
@@ЕгорФедоренко-с2щ The problem of ignorance is that it is impossible to beat without the person wanting to learn. Try to understand first what is an extension method and what it solves before arguing on internet.
Does new extension approach work for sealed classes ? Because it seems it's only scenario where you cant inherit class and want to extend it with this approach. Making a new type with extension looks wrong to me, but it seems noone really care about clean code anymore
Everytime I wanted to create a smart enum, I ended creating a class with some default values and a parser. Every time I used it, I always figured out that I may need something more flexible than a fixed list of values, not mentionning that a bunch of procedures should be handled by a factory. I really think that there is fewer use cases for smart enums than originaly expected.
I wonder how this compares to sth like Traits in Rust. Would it be possible to use extensions as generic type constraints? Sth like Add(T value, T other) where T has extension AddOperatorExtensions. Or would it be possible to completely omit the generic one and use a similar approach to the dyn keyword of rust? Sth like Log(LoggableExtension value) => value.Log() This would make C# much more powerful
I'm not 100% sure, but I don't think you cane use extensions as type constraints, but you will be able to extend a type to implement an interface, so while the syntax in your example might not work, you will be able to do effectively the same.
One weird feature I'd like is something like `foreach { ... } empty { ... }` (also for `for`) Where if it doesn't go into the foreach (or for) body because the enumerable is empty or what have you, it will execute the content in the empty body.
Very cool, but I really do hope they also add support for adding interface implementations AND for adding interface implementations to structs, both for static members (eg. operator overloads) as well as instanced. This would be huge, because it could introduce very simple ways of making an external library compatible with your system. One video I'd really like to see from you once this gets implemented is the performance comparison. Does having these types of extensions allocate extra memory? And is invoking the Age property trough an extension slower than if it was a property on the Person object? I know that even if it was slower, the difference would probably be small, but if you were to use this in a more performance critical scenario, that small difference would add up quickly
It looks like swift extensions that rust borrowed from (and have stated it in the passed with traits) which is awesome. It would be better if you can just inline extend it like in javascript with prototype i think it is. The implicit to explicit is a cool feature too, to define a custom type and type the variables. All in all great feature.
Do you know if there is any information on how these additional members appear in reflection APIs when using implicit extensions? Like, if I do `typeof(Person).GetProperties()`, would I be able to see `Age` in some capacity?
Nice feature, can you test it with JSON serialization and deserialization, does it include the extension properties in json string? Can you add Json attributes (such as name) to the extensions properties?
@@jonas9 I don't get it either. If an existing class doesn't have all features you like, just make a new one that inherits from it. Why are there new fancy features required?
Towards type classes. In Scala 2 it used to be called "implicit" and now "given". But in Scala it can be parametrized like for ex ToStringable { string ToString() }. Can we now define such a crosscut concept and implement it for neccessary types?
So many questions here. 1. What about sealed classes 2. Is an extended property a real extention or is it added to the class itself on runtime and will it add to the PropertyList in reflection (I can see ORM frameworks fail there big time) 3. Because you can use this, does that mean you can invoke events (which can only be invoked privately) 4. Because you can use this, can you call private fields and methods in the class 5. Can you extend enums as well and add values 6. Is it just like an ordinary extention, and namespace based, or will the compiler do this during begin of runtime and extend the class itself. 7. Can the implicit extention also create custom constructors. 8. Can you override virtual methods A lot to be exited about, but it is also a bit scary with this kind of questions. O lot of finding out
I can already say I am going to use this all the time. I would like it if they made it slightly more like Rust's trait impls than it already is, and let you implement interfaces as an extension.
As someone who loves extension methods: The implicit variation sounds fantastic and I am also fairly certain that this will replace the existing extension methods in almost all scenarios in which they are used today. The explicit variation I'll need more time to warm up to, though. Right now this mainly seems useful when there are classes out of your hand that are sealed, but I'd worry that this is going to be misused in other scenarios where inheritance would be the "correct" answer. There's a potential for messy and inconsistent code bases here. There is always a certain risk when features are introduced that can potentially achieve the same thing as something that already exists, and it makes it harder to understand for new devs what to use when. Still, a very exciting and welcome change!
Yeah... I can see why they wanted to add the explicit approach (to get around naming conflicts and complaints about polluting the namespace), but pretty sure I'll basically always use the implicit approach.
@@BittermanAndy I also plan to use the implicit one, because the explicit seems rather completely useless if it is targetted to a specific type, but I'll try it when it becomes ready.
I know this shouldn't bother me as much as it does...BUT...why do we use the "int" type to refer to things that should never be negative? I know Microsoft does it quite a bit too (I'm looking at you Count property) but why not let the compiler enforce as many rules as we can? It's impossible for a person to be negative years old so why not use an unsigned type? It might be nitpicky but still bugs me in an irrational way.
Eh, yeah, I sorta agree, but I don't feel as strongly about it as I used to. You're right that a person can't be -1 years old, but they're extremely unlikely to be uint.MaxValue years old (or even (uint)int.MaxValue + 1 years old) either, so...?
@@diadetediotedio6918 Yeah I can see that. Some of the things I was reading was "why force a language that wants to run on the CLR to implement unsigned types if it doesn't have that concept?" Assuming it's a type-safe language why wouldn't you support unsigned types? I try to delegate as many decisions on what is correct to the compiler as I can. Supporting unsigned types seems like a good idea because you can express your intent a bit clearer (and not have to constantly check for < 0). Could be a phase I'm going through at the moment though too.
I may be misunderstanding, but C# has unsigned int, but it's a bit cumbersome since C# defaults to signed integers, and you need to explicitly cast between int and uint.
The question I have is can this extension implement interfaces. I find the need to add an interface to a type I don't control many times I have to resort to wrappers.
Do c# extension have something like the orphan rule? Looks like explicit extension is a better way than orphan rule, but i'm still curious about whether implicit extension requires this rule.
Yay! Looking forward to this new feature. Extensions that were essentially properties but addressed as methods always felt a little weird. This in addition to the explicit functionality is a welcome add.
That is why I chose .NET over any other language for API (and others) development. C# is constantly on the move to become better and not becoming complacent and releasing updates every 300 years, unlike a certain cup of coffee, until it had a new competition.
Not sure, but since you can add extension static methods, I'd be surprised if you couldn't. `Person.Create` could be created in terms of implicit extensions as of C# 13(.. maybe 14; unsure whether statics are coming in 13)
This makes the reference to this a bit vague, but I like it. I wish they’d added another keyword than ‘this’ though. I do like the implict and explicit pattern that is used for casting operators now being added to extension methods.
How do you test this ? I tried the SDK 9.0.100-preview.5.24274.2 from the Daily Channel, but with it Visual Studio doesn't know any "public implicit extension".
How does explicit extension improve C# compared to inheritance? It looks like an Adult is almost exactly like a new class inheriting Person and extending it with a new property. And in which namespace do these new extensions live? Normally extension methods would live in a different namespace than the classes they extend, like all those Add... and Use... methods used in Program.cs or Startup.cs.
I've not typically used a lot of extension methods but I think this would be preferred. However... what happens if the class you don't own (Person, in this case), is sealed, for example? How much different is the explicit form from inheritance? Granted, you can't get at anything inside the extended class that's not public, which would be different because an inherited class you would be able to access protected, for example.
will we be able to use pattern matching "if(person is Adult adult)"? And is it possible to add operator behaviour to any type? I often want to add the values in a vector but there is no built in + in vector, and you cant do it yourself directly on the System.Numerics.Vector class so far
Great stuff, Do you happen to test/check how this implicit/explicit extension properties will behave when serializing/deserializing to a Json for example?
How is the access level with that new features? Will it be possible to also get access to protected or even private fields, or is in that scenario just like an extension method?
Thanks for the heads up and the interesting intro, Nick! Would you mind clafirying why we need to consider leap years to find the age? Am I missing something really obvious? 🙂
@@gbjbaanb thank you, that's what I thought it may be the case but better to be safe than sorry. Essentially the year subtraction could make you older by 1 year, if you haven't reached your birthday month yet, if I understand correctly.
I thought about trying this out for myself, but apparently I am missing something. Are there any instructions on how can I get this feature working on my own computer? As a professional software developer I would be very much interested in playing with pre-preview features in order to have cutting edge knowledge of C# and .NET. I have .NET 9 preview 4 installed, and I am using "preview" as my language version, but I couldn't get this to work. After some furious research I found out that apparently this feature is not yet in the main branch of the csharplang repo nor the roslyn repo, but still only in the roles branch in the former repo.
An extension is a convenience to neatly call public methods on a type you may or may not own, and may or may not be possible to derive from. (Implicit or explicit, same comment applies - the only difference is, do you want to only be able to use your methods when you explicitly opt in to them, or always have them available). A subclass complicates the type hierarchy and (for this purpose) may not be possible if the type you wish to extend is sealed, or already has other subclasses (no multiple inheritance), or is constructed by somebody else and passed to you.
@@Brondahl [edited to remove unnecessary rudeness] If you want to create a derived class ShapeExtensions, then the existence of Circle, Square, Triangle, all already derived from Shape, means that you can't do so - you cannot have multiple inheritance of both Shape and ShapeExtensions. But, if ShapeExtensions are an extension instead of a derived class, it all works perfectly (for all derived classes) with no other changes needed. I said CONSTRUCTED by someone else. If a library passes you a Shape as a parameter, and you want ShapeExtension to be a class derived from Shape, you can't contact the owner of the library and say "hey, don't give me a Shape, give me a ShapeExtension instead" (or maybe you can, but they might say no). But if ShapeExtension is an extension, you can happily treat their Shape as a ShapeExtension and they never need to know.
🤦♂Yeah, sorry ... brain farting all over the place. Somehow convinced myself you could declare a subclass and then "as"-cast a parent object down to it. No idea what I was thinking.
I wonder how the explicit extension works under the hood.... It would seem as it would allocate a new region in memory. How this is done is important for game dev for example because if the memory region of the extended type is scattered, it can cause a bunch of cache misses.
Interesting. I'm left wondering if it'll now be possible to add properties and methods to an existing static type. Looks good though. I've wanted extension properties for ages.
Great content as always, Nick. As you were discussing the explicit extension, I couldn't help but wonder how this is different than a subclass. Then that made me wonder if the implicit extension is different from the static extension method in that the implicit extension is actually just a subclass where the base class can be implicitly converted. So if I have an implicit extension method, is the the runtime actually implicitly coercing the base class to the subclass then calling the extension method? If so, are there any performance considerations there?
Love it! Now I'm curios - will it be possible to mock such extended methods and properties? One of the disadvantages of current extension is that it is a static methods and we can't mock them.
I don't fully understand the idea of explicit extension - how does it differ from regular inheritance? I understand that it may be more efficient, but does it in any way extend what we could do in C#?
If Adult derived from Person, you could not cast a person to an adult. You would need to create a new adult and copy the data. If Person was sealed you would not be able to do this. What if Person was an abstract class?
@@WileeRunner42 Or a struct. Or an enum. Or weirder types like Funcs and Actions delegates... Or generic types. You could extend tons of types in one go by extending a generic type that matches certain "where" criteria, etc.
For this level of customization why not use class inheritance? I feel like I'm missing something. There's got to be more of a reason for C#13 extensions than an inheritance workaround for `sealed` classes.
No. Extensions can't have state. It's possible to somewhat work around that by having a static weak hash map from the object to the variable, but that obviously won't work with structs.
Thanks for the video Nick! Great as always. But one question: can these extensions add & modify private fields? If so then i see problem if you are using DDD and have business rules in your model which can be jailbreaked by simply creating an implicit / explicit extension. Or may i´m wrong here?
They cannot, extension methods in general are only normal methods with a nicer syntax. The thing interesting me here is both the possibility of having some niceties (like .dp/.sp/.rem of Kotlin for UI) and a possible structural parametric polymorphism.
Yeah, fields are impossible in this sense without modifying the CLR, and this I think would not be good anyway (because it would be a mess, literally, because serialization and many assumptions about data layout we need to make when developing programs). But you can simulate this explicitly if you want with a weak hash map.
In the video as an example was shown a situation, where you could use simple inheritance to extend Person class capabilities and get the same experience with properties and Adult class. But you won't be able to use inheritance if class is sealed. Does this new C# feature works with sealed classes?
The one time when clickbait title isn't actually clickbait at all. The hype IS justified.
Thank you for the heads up
It is indeed
Use the DeArrow extension and you will get non-clickbait titles.
So it's not clickbait... Lol clickbait is only when it is not justified, if you give worms to fish without fishing them, then its not bait is food
If this is "changing everything", your code base has bigger problems.
This is looking pretty clean. Unsure if I'll use it anytime soon, but it sounds cool.
Unrelated, I really hope they add readonly to the Primary Constructors. Bit annoying that it was pushed to replace those assignment only constructors, but didn't cover the common readonly usecase.
they could add the val keyword and copy kotlin syntax
Wow. So many questions.
How does serialization play into these extension types? What if you JSON serialize Person?
Can extension types have their own private fields/state? Could FavoriteDrink pull from a field that isn’t on Person, but is on Adult.
They can't own state. They are meant to add different behaviors to already existing data based on context in which it is used. I think the better example would be extending some PropertyBag types like ClaimsPrincipal or other Dictionaries with type safe properties.
I don't know, but given that Serialization usually is performed on the instance type using reflection I doubt that these extension methods will be included in the output. They are not really instances, i.e. they don't hold state.
As a counter example, assume serialization _does_ work. What would you then expect de-serialization to look like? You can't populate Age with a value since it does not have a backing field to store it.
So serialization is bust I am pretty sure.
@@sunefred Very interesting observations, I'd like to try this out and see
What about sealed classes? I'm assuming this would be disallowed but didn't know.
@@pfili9306 I'm not so sure about that. Check out the example in the official announcement docs. They show an example where classes Person and Organization are pulled in, and each Person object needs an Organization property passed in, but in this example scenario there is only one Organization object for the whole application, making the extra property for Person tedious to assigns.
So they make an implicit extension for Organization, add a private static Organization ourOrganization = new Organization("C# Design");, and then add a CreatePerson function that always assigns the new Person object with ourOrganization as the Organization property.
The property is static in this case, but I don't see anything mentioning that as a restriction rather than what happened to make sense in the scenario.
Being able to add properties now is a huge deal.
What I still sorely miss is being able to take someone's class and say, "Um, actually, this Type DOES Implement this Interface! Here's how!"
Struggling to think of examples, but for some older code, it'd be nice to not need to use .Cast to get the correct type all the time, maybe?
You would be able to implement interfaces with extensions. It's the second purpose of extensions
You would probably like rust's traits
@@zachemny How does that work? Do you have a link to where it's described?
Adapter pattern
@@zachemny That would mean I could mock dependencies that I don't own and don't have an interface, awesome
I so desperately want to be able to attach an interface to an existing class using extensions. So many times I wished for the convenience of having a method that takes an interface and passing some 3rd party object along except it, of course, doesn't implement my interface. So instead I have to write stupid wrapper classes all the time.
Just pretend it has the interface if it already offers all the methods and properties!
This. You hit the nail in the head
Yes, C# lang team calls it "shapes" AKA duck-typing
Great use case.
@@ryan-heath Is there a proposal for this somewhere?
Just use functions. Life will be easier. No more class, static, interface, wrapper etc...
(ps: it's good to use Interfaces in OOP or code that interact with OOP)
Its been on the cards for a while so I'm glad its almost here. The fact you can now introduce properties is really nice - great way to shape something you don't own or control.
After all these years, I can't believe they're finally giving us extension properties. This is pretty hype as it's more than that as well. Although I have to say I'm a bit disappointed in the explicit extension. Don't get me wrong, it's a great feature. But in your example you check for their age, then inside the conditional branch you do the explicit conversion. The problem with this is that there is nothing tying the age check to the conversion. This relies on the developer to know when such extensions are valid or intended to be used. It would be nice if they added the ability to provide like a where clause on the extension declaration to define when it's valid. Then maybe you could simply do something like `if (person is Adult adult)`. This way you can make extensions only valid in certain contexts, and also be coupled to those contexts. But I mostly work in TypeScript these days and I'm pretty spoiled on the powerful type system there. This is already an absolute game changer as it is and I'm not trying to complain.
I wouldn't be surprised if they build up to something of that nature in a later release after they get feedback on this initial C# 13 implementation of it. I doubt they would put a boolean condition on the ability to cast to the explicit extension type itself. There isn't really a precedent for that, even with generic constraints. Doing so would hide the boolean condition from the calling code entirely (abstracted behind the cast operation).
However, I could see there being a "best practice" of defining, in such explicit extension scenarios, a `TryCreateAdult(out Adult adult)` kind of method that does the boolean check and sets `adult` to `this` when true. That way people would be able to leverage pattern matching and naming conventions to achieve that goal. IF that became so commonplace as to be annoying, then they might discuss potential strategies for optimizing the syntax or at least standardizing it. Perhaps with a `TryExtend` magic method, similar to what they do for TryParse and Deconstruct, etc.
The biggest pain point I previously had with extension methods has been with unit testing + Moq. I’m curious how mocking extended types would work with this new feature.
Fun fact: since the `Age` member can return different values by the time you call it, the Framework Design Guidelines book defines as a good practice to keep it as a method instead of a property. They even give the example of something that they consider broken in .NET which is the `DateTime.Now` property - which, according to the authors, should be a method, but it was too late to change by the time they noticed it.
Wouldn't that be most properties then?
In reality properties are just sugar for a field with Get and Set methods 🤷♂️
Not really. Most properties don't change value each time you get them. Those who do more often than not, should be methods, according to the Framework Design Guidelines.
@@viniciusvbf22 aah, I misunderstood you. I thought you meant "can change" not "changes every time".
Edit: But in this case the Age property wouldn't change every time you called it 🤷♂️
For anyone here confused with extension methods, I will ask you to search about a thing called 'universal function calling syntax', and then to experiment a bit with C# actual extension methods.
They don't do anything that is not already possible, but make the code cleaner and more sequential.
It is the reason you can write:
var arr = [ 1, 2, 3, 4, 5, 6, 7 ];
var even = arr.Where(x => x % 2 == 0).Select(x => x * 3).Select(x => $"Result is: {x}");
Instead of writting:
var even = Select(Select(Where(arr, x => x % 2 == 0), x => x * 3), x => $"Result is {x}");
Both things are literally possible to do, but one of them is clearly more annoying, noisy and requires more cursor movimentation (if you don't want to store everything in a local temporary variable, which is also annoying).
To be fair even with the extensions, you would probably write it in a way that is on multiple lines i.e
var even = arr
.Where(x => x % 2 == 0)
.Select(x => x * 3)
.Select(x => $"Result is: {x}");
and you would probably write the latter as:
var a= arr.Where( x=> x%2 ==0);
var b = a.Select(x => x * 3);
var even = b.Select(x => $"Result is {x});
The syntax is a bit more concise and readable. But I think the game changer is it makes writing more readable code the easier default. Whereas before it was kind of up to one programmers interpretation, with extensions you are pushed in the direction of writing good code. The only part that is a bit harder to read is that all of the lines eventually return a value that is stored in the variable at the top of the operation. I think if you wanted to go to the full 9s you could have a .StoreAs extension that you wrote at the end. That would make it read better in a left to write fashion, but would likely require more in depth changes to the language
so it would become
arr
.Where(x => x % 2 == 0)
.Select(x => x * 3)
.Select(x => $"Result is: {x}")
.StoreAs(IEnumerable even);
@@NickSteffen
No? I don't often find people that would write the version with extensions using intermediate variables, this don't make any sense unless you are doing something very fishy. Also, I'm considering multiple lines, I generally use them as well and with extension methods it feels much natural, sequential and direct.
And for the storage part, I think you are just not used to how programming languages work, I really don't think this is a problem per se and I recommend delving into studies to get better at it over time. With time you will be able to see how this all works.
But for a brief explanation here, functions return values, and values in C# can be objects that have methods OR extension methods. When you write:
var even = ar.Where(x => x % 2 == 0).Select(x => x * 3)...;
You are just saying::: take this array, filter all the elements where 'element % 2 == 0'; then take the returned result and map each element on it as 'element * 3'; then take the returned result and map each element on it as 'Result is {element}'; then let the result be returned into the variable attribution.
You can write the same thing without extension methods (althought it would take much more work to do so), take a look at the builder pattern and how it is implemented and I think it will be clearer for you how this generally works.
@@diadetediotedio6918 I think you completely misunderstood my answer… The example with intermediate variables with describing was you would do if extensions didn’t exist. It was a counterpoint to your second example on how unreadable it would be. A good programmer would never write it in that unreadable way.
My last point was a completely theoretical what if, yes I understand program languages don’t work that way. They also didn’t work “that way” before extension methods were a thing. Fluent/ universal method style is just changing how programming languages work to bend the syntax to how human language works. So the fact that they don’t work that way now is irrelevant to the point.
Also C# can in fact work this way in some very limited cases though, since you can declare variables in a dictionary’s TryGetValue method. So for example you can:
arr
.Where(x => x % 2 == 0)
.Select(x => x * 3)
.ToDictionary( ( x => x),(x => $“Result is {x}”))
.TryGetValue(6, out int result)
Notice how at the end I’m both declaring a value and saving the result into it. You can do the is in some other places like type checks in if statements ex:
if( x is string y)
Console.WriteLine(y);
This type of style is more easily readable for humans as we read continuously in one direction. You don’t have to jump back to the top to see where the variable is being saved. You could absolutely change c# to do this in more cases fairly easily.
Now would it be a good idea to do that… I’m not sure, it would at least be interesting.
@@NickSteffen
My second point was to highlight that writing in the same way you would write using extension methods would be uglier, I'm not saying that necessarily you would do that (althought I'm pretty sure many people would do). If this was your objection then read again my note on storing things as intermediate variables to improve clarity (implied from context).
Next, it is not irrelevant. The fact that we can write fluent functions in that manner is precisely because they work in that way, it does not "change how programming languages work" even if it is to align it better with 'how human language works" (which I can partially concede).
Your example with dictionary don't make sense as well, it is a very bizarre way of writting what would be much better written as just .First(...) or .FirstOrDefault(...), to create a dictionary you would already need to iterate through all items so there is no advantage on using it. Also, this works that way in this specific case because then you are fundamentally dealing with another resource of the language, a similar result could be achieved using 'ref' and the semantics are not the same, TryGetValue returns something (a boolean confirming the existence of the item) and it stores the result in the out pointer (because at the time C# had not fast and reliable booleans, many languages nowadays don't have an 'out' thing for example).
As for the 'x is string y' example, it is another completely different mechanics of the language again, there is nothing to do with how 'out' works. The convenient 'x is string y' is a modern construct (in early C# versions you had to type manually 'x is string' and then '(string)x' or do 'x as string' and then 'x != null').
As of your question about this being more "easily readable" because it reads continuously in one direction, I don't think I necessarily agree with you absolutely on this. I can buy the point that this is better , but I wont that this is the step to follow for many reasons. I know you are not sure about if this is a good idea, but I'll argue as you held that position (so I can focus on responding anyone who is willing to defend it):
First of all, because it is untrue, humans also write things in a name -> description fashion, for example when we respond to someone we can do:
A. (responds to point A)
B. (responds to point B)
And when we want to describe something we have a resource in language that is ':', so we can say:
something: this is something (explains)
Even when I'm writting this response, and when you did wrote your response, you used attribution in this same sense (for example when giving the example, you said 'ex: (code)'). So it is untrue that this is a direction that should be followed by readability.
Second, programming is for humans the same way mathematics is also for humans, the same way everything humans do is ultimately for humans, and in mathematics nobody is arguing of how f(x) = y is a terrible syntax and nobody understands it, you are removing the formal aspect of programming which is that makes it easily readable and generally predictable (human language is inherently noisy and ambiguous, this is why even when programming languages try to approximate to human language they keep a safe distance to what is actually reasonable).
Third, because this would make a radical rupture between every single language out there that don't work that way. When you make a change that affects the entire way we reason about programs in a specific language, this should be EXTREMELY more justified than that, because then someone writing C# will arrive in another language (like C, C++, Rust, Go, Kotlin, etc) and suddenly everything he knew will not be valid here, this is one of the reasons of why even arguable that indexes in programming languages should start with 1 (because we usually start counting with 1 in human language) this is not necessarily a good idea as it would break many assumptions when moving from one language to another.
As for the end, you can also use extension methods to achieve what you want, you can for example write a:
public static void StoreAs(this T self, out T @in) => @in = self;
And it would work like you wish.
The one feature I would find really good is a way to extend interfaces to these types. If you have an interface like IAge { int Age {get;} }, it would be super cool if you could extend Person so it implicitly implements that interface so you can pass it directly into methods or constructors without having to create a new wrapper around them.
You would be able to implement interfaces with extensions, according to the initial proposal
I've been waiting for extendable properties for like a decade. So excited! C# just keeps getting better!
Extension properties at last! I've been waiting for this since 2007.
Same.
Yeah, this is for me in this update.
Seems like the WPF team could have used this. Oh wait.
If, and that's a big if, you also get the ability to have fields to store.
@@McZsh
This would not make any sense, so I don't think it is a possibility to consider.
That explicit extension use case is actually interesting. What it almost lets you do (or what that syntax almost seems to let you do on the surface) is have a class more or less inherit from multiple classes at the same time, not just interfaces. Like if there was some sealed class from a third-party library that I wanted to add support for say a custom serialiser system I was making, I could add an extension to that class which defines the serialise and deserialise methods, even though I can't edit that class directly.
Hmmm. Yeah, I'd be interested to know how that works with reflection APIs. In order to REALLY be useful for dynamic situations, you'd need `typeof(Person).GetProperties()` to include stuff like `Age`, etc.
Will it also be possible to implement an interface as an extension?
Can't wait for this feature. I hope the IDE will help make it obvious where code is comming from, is some property from third-party library, is it from your own extension or from some other third-party extension library. Otherwise it would be a very confusing trying to some out where some random property is from. 🫠
In kotlin, it’s common to write extension methods for types within your own code base because it allows for utilities that don’t clutter up the code of the class itself.
Now take val and var from kotlin, too.
Would these extension properties work for model binding in Maui? They could be useful for adding properties to a model that would previously require a converter.
Interesting. Does this work with data binding, eg in a WPF app?
some of these features are building blocks for Descriminated Union ❤. I love Extensions everything
This looks really good, though I am somewhat sceptical of the practical benefits of explicit extensions. I just can't see them actually being used but I might be wrong.
Most wanted feature: anonymous object spread operator like in js/ts e.g.
var shirt = { Name = "Shirt", Size = 20 };
var shirtWithDescription = { ...shirt, Description = "A red T-Shirt" } // { Name = "Shirt", Size = 20, Description = "A red T-Shirt" }
I would see the benefits of explicit extensions if they were not tied to a specific type, like for example
public explicit extension Named
{
public string Name { get; }
}
So you would be able to do structural typing and this would be extremely useful.
But I'm not sure if this syntax allows it, as I didn't readed the docs of this yet.
I feel like explicit extensions are really missing some way to enforce whether it can be casted. Like in the example Nick gave, I'd want to actually be able to ensure that person is only an adult if person.Age >= 18.
@@normalmighty
Well, for this you can use a new type pattern, I don't think this is the role of extensions on themselves.
I just don't see what's the supposed benefit of explicit extensions over simply encapsulating the type...
@@mbpoblet
A. It is more ergonomic as "encapsulating the type" would require you to make a wrapping method for each property/method of that same type OR expose it through a property.
B. You can use it over generics easily without needing to cast in some specific circumstances (which would allocate memory / this is solvable with wrappers but the friction would be even bigger).
Definitely like the extension properties.
Though I'm not sold on explicit extensions since it seems to leave us with 2 overlapping definitions for polymorphism. What's the use case for this?
I've been waiting for this forever! Next question.... in these extension "classes", can you also define extension operators??
explicit one just seems like an other synthax for a derived class
I wonder if this will be the case for sealed classes from other libraries and how the polymorphism would play in our own library would an adult be a person?
But its not. See Rust trait system to understand this much better.
@@rogeriobarretto but sealed classes are sealed for a reason. It's just stupid to provide a feature (inheritance), to provide the tools to control this feature (sealed classes), and then to provide ANOTHER feature to ignore the restrictions (explicit extensions).
I believe explicit extensions were invented for anything else except inheriting sealed classes.
@@rogeriobarrettoin terms of serialization, `Adult` does not exist.
@@ЕгорФедоренко-с2щ
The problem of ignorance is that it is impossible to beat without the person wanting to learn. Try to understand first what is an extension method and what it solves before arguing on internet.
Does new extension approach work for sealed classes ? Because it seems it's only scenario where you cant inherit class and want to extend it with this approach. Making a new type with extension looks wrong to me, but it seems noone really care about clean code anymore
These are still just extension methods with a new syntax. The whole point is to allow for cleaner code.
I absolutely like this feature. I'll want Smart Enums to be in C# like the Java language has
Everytime I wanted to create a smart enum, I ended creating a class with some default values and a parser. Every time I used it, I always figured out that I may need something more flexible than a fixed list of values, not mentionning that a bunch of procedures should be handled by a factory.
I really think that there is fewer use cases for smart enums than originaly expected.
Bro finally C# is getting some good stuff
Records make a decent replacement for smart enums, right?
finally !! finally ! waiting for a long timmme long time ! :D Huray ! :)
I wonder how this compares to sth like Traits in Rust.
Would it be possible to use extensions as generic type constraints?
Sth like Add(T value, T other) where T has extension AddOperatorExtensions.
Or would it be possible to completely omit the generic one and use a similar approach to the dyn keyword of rust?
Sth like Log(LoggableExtension value) => value.Log()
This would make C# much more powerful
I'm not 100% sure, but I don't think you cane use extensions as type constraints, but you will be able to extend a type to implement an interface, so while the syntax in your example might not work, you will be able to do effectively the same.
Finally, some love for extension methods! Extensions methods are bae and now much better!
One weird feature I'd like is something like `foreach { ... } empty { ... }` (also for `for`) Where if it doesn't go into the foreach (or for) body because the enumerable is empty or what have you, it will execute the content in the empty body.
Well, you can write an extension:
IEnumerable.ForEachOrEmpty(Action itemAction, Action emptyAction)
@@theMagos Yeah, but I want syntactic sugar.
Very cool, but I really do hope they also add support for adding interface implementations AND for adding interface implementations to structs, both for static members (eg. operator overloads) as well as instanced. This would be huge, because it could introduce very simple ways of making an external library compatible with your system.
One video I'd really like to see from you once this gets implemented is the performance comparison.
Does having these types of extensions allocate extra memory?
And is invoking the Age property trough an extension slower than if it was a property on the Person object? I know that even if it was slower, the difference would probably be small, but if you were to use this in a more performance critical scenario, that small difference would add up quickly
It looks like swift extensions that rust borrowed from (and have stated it in the passed with traits) which is awesome. It would be better if you can just inline extend it like in javascript with prototype i think it is. The implicit to explicit is a cool feature too, to define a custom type and type the variables. All in all great feature.
Do you know if there is any information on how these additional members appear in reflection APIs when using implicit extensions? Like, if I do `typeof(Person).GetProperties()`, would I be able to see `Age` in some capacity?
Whats the difference between using explicit and just extending the class?
Does explicit override sealed ?
Nice feature, can you test it with JSON serialization and deserialization, does it include the extension properties in json string? Can you add Json attributes (such as name) to the extensions properties?
Return type: this .. similar to typescript, works really nice for fluent api builders, when extending, returns the type correctly
I used to work in js, and this sounds like a mixin... I love it!
C# is on the right way from inheritance to composition
Why has it become cool to hate on inheritance now...
@@jonas9 code becomes non testable because of inheritance in most cases.
@@jonas9 I've hated inheritance since it was invented! ;-)
@@jonas9because when you change the parent you change all its children. This is very problematic.
@@jonas9 I don't get it either. If an existing class doesn't have all features you like, just make a new one that inherits from it. Why are there new fancy features required?
This gives us a lot more power. It might be an anti-pattern for 'closed'/sealed classes
In your example what does PersonExtension indicate in your implicit example? Is it just a name like the class that contains your extension methods?
Yes, it's just a name for the extension (which is not a class any more, it's another "thing").
Towards type classes. In Scala 2 it used to be called "implicit" and now "given". But in Scala it can be parametrized like for ex ToStringable { string ToString() }. Can we now define such a crosscut concept and implement it for neccessary types?
So many questions here.
1. What about sealed classes
2. Is an extended property a real extention or is it added to the class itself on runtime and will it add to the PropertyList in reflection (I can see ORM frameworks fail there big time)
3. Because you can use this, does that mean you can invoke events (which can only be invoked privately)
4. Because you can use this, can you call private fields and methods in the class
5. Can you extend enums as well and add values
6. Is it just like an ordinary extention, and namespace based, or will the compiler do this during begin of runtime and extend the class itself.
7. Can the implicit extention also create custom constructors.
8. Can you override virtual methods
A lot to be exited about, but it is also a bit scary with this kind of questions. O lot of finding out
I can already say I am going to use this all the time. I would like it if they made it slightly more like Rust's trait impls than it already is, and let you implement interfaces as an extension.
I've been waiting for this for 4 years!
why?
@@TheOnlyDominik
Cause it is amazing for structural parametric polymorphism
@@diadetediotedio6918 ok. I don't need any unnecessary theoretical features.
@@diadetediotedio6918 I only have 30 years of experience in software development, it's too complicated for me.
Bro some of us have been waiting since 2008
As someone who loves extension methods:
The implicit variation sounds fantastic and I am also fairly certain that this will replace the existing extension methods in almost all scenarios in which they are used today.
The explicit variation I'll need more time to warm up to, though. Right now this mainly seems useful when there are classes out of your hand that are sealed, but I'd worry that this is going to be misused in other scenarios where inheritance would be the "correct" answer. There's a potential for messy and inconsistent code bases here.
There is always a certain risk when features are introduced that can potentially achieve the same thing as something that already exists, and it makes it harder to understand for new devs what to use when.
Still, a very exciting and welcome change!
Yeah... I can see why they wanted to add the explicit approach (to get around naming conflicts and complaints about polluting the namespace), but pretty sure I'll basically always use the implicit approach.
@@BittermanAndy
I also plan to use the implicit one, because the explicit seems rather completely useless if it is targetted to a specific type, but I'll try it when it becomes ready.
I know this shouldn't bother me as much as it does...BUT...why do we use the "int" type to refer to things that should never be negative? I know Microsoft does it quite a bit too (I'm looking at you Count property) but why not let the compiler enforce as many rules as we can? It's impossible for a person to be negative years old so why not use an unsigned type? It might be nitpicky but still bugs me in an irrational way.
Eh, yeah, I sorta agree, but I don't feel as strongly about it as I used to. You're right that a person can't be -1 years old, but they're extremely unlikely to be uint.MaxValue years old (or even (uint)int.MaxValue + 1 years old) either, so...?
It is because unsigned int is not CLS compliant, I think this had some influence.
@@diadetediotedio6918 Yeah I can see that. Some of the things I was reading was "why force a language that wants to run on the CLR to implement unsigned types if it doesn't have that concept?" Assuming it's a type-safe language why wouldn't you support unsigned types? I try to delegate as many decisions on what is correct to the compiler as I can. Supporting unsigned types seems like a good idea because you can express your intent a bit clearer (and not have to constantly check for < 0). Could be a phase I'm going through at the moment though too.
@@logank.70 I'm on board with you, and honestly surprised I've never considered this before.
I may be misunderstanding, but C# has unsigned int, but it's a bit cumbersome since C# defaults to signed integers, and you need to explicitly cast between int and uint.
I'm very happy about this, I've been asking for this feature for years and it seems to really deliver.😉
Very good video and in terms of functionality it reminds me of my rust trains
This feels like Typescript and that's very cool, it literally solves the problems with inheritance, so cool!
The question I have is can this extension implement interfaces. I find the need to add an interface to a type I don't control many times I have to resort to wrappers.
Do c# extension have something like the orphan rule?
Looks like explicit extension is a better way than orphan rule, but i'm still curious about whether implicit extension requires this rule.
Extension methods completely changed my life as a programmer. Looking forward to this!!
Yay! Looking forward to this new feature. Extensions that were essentially properties but addressed as methods always felt a little weird. This in addition to the explicit functionality is a welcome add.
Great video. You should have included how to try this in VS Code briefly.
That is why I chose .NET over any other language for API (and others) development. C# is constantly on the move to become better and not becoming complacent and releasing updates every 300 years, unlike a certain cup of coffee, until it had a new competition.
Can we now extend static classes?
Not sure, but since you can add extension static methods, I'd be surprised if you couldn't.
`Person.Create` could be created in terms of implicit extensions as of C# 13(.. maybe 14; unsure whether statics are coming in 13)
This is quite an exciting new feature. Feels clean.
This makes the reference to this a bit vague, but I like it. I wish they’d added another keyword than ‘this’ though. I do like the implict and explicit pattern that is used for casting operators now being added to extension methods.
I don't quite understand the difference between "explicit extension" and classic OOP class inheritance
Wow i really like how they solved the problem of adding extension properties. 👍
How do you test this ? I tried the SDK 9.0.100-preview.5.24274.2 from the Daily Channel, but with it Visual Studio doesn't know any "public implicit extension".
Because it's not out yet
How does explicit extension improve C# compared to inheritance? It looks like an Adult is almost exactly like a new class inheriting Person and extending it with a new property. And in which namespace do these new extensions live? Normally extension methods would live in a different namespace than the classes they extend, like all those Add... and Use... methods used in Program.cs or Startup.cs.
I've not typically used a lot of extension methods but I think this would be preferred. However... what happens if the class you don't own (Person, in this case), is sealed, for example? How much different is the explicit form from inheritance? Granted, you can't get at anything inside the extended class that's not public, which would be different because an inherited class you would be able to access protected, for example.
You'll be able to create extensions for sealed classes.
I've been waiting for this feature for years. This and DUs, but I think I need this one more.
The stuff you care about starts at 6:00
You're welcome
This is pretty great. Discriminated unions is THE feature to fix exception nonsense in enterprise code or OneOf nonsense in smaller personal projects.
omg yes!! I am super excited about this for sure.
will we be able to use pattern matching "if(person is Adult adult)"? And is it possible to add operator behaviour to any type? I often want to add the values in a vector but there is no built in + in vector, and you cant do it yourself directly on the System.Numerics.Vector class so far
Great stuff, Do you happen to test/check how this implicit/explicit extension properties will behave when serializing/deserializing to a Json for example?
How is the access level with that new features? Will it be possible to also get access to protected or even private fields, or is in that scenario just like an extension method?
They are just extension methods, so public members only.
Thanks for the heads up and the interesting intro, Nick!
Would you mind clafirying why we need to consider leap years to find the age? Am I missing something really obvious? 🙂
He means birthday. Taking year - year gives the wrong answer by 1 after your birthday.
@@gbjbaanb thank you, that's what I thought it may be the case but better to be safe than sorry. Essentially the year subtraction could make you older by 1 year, if you haven't reached your birthday month yet, if I understand correctly.
I thought about trying this out for myself, but apparently I am missing something. Are there any instructions on how can I get this feature working on my own computer? As a professional software developer I would be very much interested in playing with pre-preview features in order to have cutting edge knowledge of C# and .NET.
I have .NET 9 preview 4 installed, and I am using "preview" as my language version, but I couldn't get this to work. After some furious research I found out that apparently this feature is not yet in the main branch of the csharplang repo nor the roslyn repo, but still only in the roles branch in the former repo.
Kinda like working with go Interfaces. This is actually very exciting.
Will these extension properties will be included in ef core model?
what problem does this solve that inheritance doesn't? curious on if it works with sealed & static classes
Whats the difference between the explicit extension and a subclass?
An extension is a convenience to neatly call public methods on a type you may or may not own, and may or may not be possible to derive from. (Implicit or explicit, same comment applies - the only difference is, do you want to only be able to use your methods when you explicitly opt in to them, or always have them available).
A subclass complicates the type hierarchy and (for this purpose) may not be possible if the type you wish to extend is sealed, or already has other subclasses (no multiple inheritance), or is constructed by somebody else and passed to you.
@@BittermanAndy EDIT: All of this was complete rubbish. Ignore me.
@@Brondahl [edited to remove unnecessary rudeness]
If you want to create a derived class ShapeExtensions, then the existence of Circle, Square, Triangle, all already derived from Shape, means that you can't do so - you cannot have multiple inheritance of both Shape and ShapeExtensions. But, if ShapeExtensions are an extension instead of a derived class, it all works perfectly (for all derived classes) with no other changes needed.
I said CONSTRUCTED by someone else. If a library passes you a Shape as a parameter, and you want ShapeExtension to be a class derived from Shape, you can't contact the owner of the library and say "hey, don't give me a Shape, give me a ShapeExtension instead" (or maybe you can, but they might say no). But if ShapeExtension is an extension, you can happily treat their Shape as a ShapeExtension and they never need to know.
🤦♂Yeah, sorry ... brain farting all over the place. Somehow convinced myself you could declare a subclass and then "as"-cast a parent object down to it. No idea what I was thinking.
@@BittermanAndy Condescending opening was unnecessary though.
I wonder how the explicit extension works under the hood.... It would seem as it would allocate a new region in memory. How this is done is important for game dev for example because if the memory region of the extended type is scattered, it can cause a bunch of cache misses.
Does this require a new runtime or can this also be used in older .NET Core versions (just a language feature)?
Well, I definitely have use cases where implicit extensions will come in handy. Like, I need them already yesterday. 🙂
Beautiful and what sealed class?
Do we know yet if this is limited to public members? I really like that properties are supported
Can you use these new exstensions to make a type implement an interface?
Interesting. I'm left wondering if it'll now be possible to add properties and methods to an existing static type. Looks good though. I've wanted extension properties for ages.
Is this an extension or subclass with implicit conversion?
Would be cool if they could add a ‘when (Age >= 18)’ and allow an ‘if (person is Adult adult) …’ pattern. 😊
what will this code compile into?
Great content as always, Nick. As you were discussing the explicit extension, I couldn't help but wonder how this is different than a subclass. Then that made me wonder if the implicit extension is different from the static extension method in that the implicit extension is actually just a subclass where the base class can be implicitly converted. So if I have an implicit extension method, is the the runtime actually implicitly coercing the base class to the subclass then calling the extension method? If so, are there any performance considerations there?
Explicit extension looks just like inheritance, without actually being that type's instance. Will this play nicely with generics too?
Love it!
Now I'm curios - will it be possible to mock such extended methods and properties? One of the disadvantages of current extension is that it is a static methods and we can't mock them.
In some sense. You can have an extension that inherits another extension and use the new keyword to shadow the base extension's member.
Have you tested with Enumeration? Sometimes I have this problem.
What is the difference between explicit extensions and class inheritance?
What is the practical difference between the explicit extension and inheritance? I have no experience with extensions so i don't know.
I don't fully understand the idea of explicit extension - how does it differ from regular inheritance? I understand that it may be more efficient, but does it in any way extend what we could do in C#?
If Adult derived from Person, you could not cast a person to an adult. You would need to create a new adult and copy the data. If Person was sealed you would not be able to do this. What if Person was an abstract class?
@@WileeRunner42 Or a struct. Or an enum. Or weirder types like Funcs and Actions delegates... Or generic types. You could extend tons of types in one go by extending a generic type that matches certain "where" criteria, etc.
@@davidesparzaguerrero4545 Good point, thanks.
For this level of customization why not use class inheritance? I feel like I'm missing something. There's got to be more of a reason for C#13 extensions than an inheritance workaround for `sealed` classes.
I have been waiting for this for years and years.
Can implicit or explicit extensions have data as well? Like, could you add a new data type for, say, the person's title or city within?
No. Extensions can't have state. It's possible to somewhat work around that by having a static weak hash map from the object to the variable, but that obviously won't work with structs.
@@phizc Ah, too bad. Then this is interesting, but not as groundbreaking as I had hoped. Thank you.
So, what's the difference between explicit extension and inheritance?
Thanks for the video Nick!
Great as always.
But one question: can these extensions add & modify private fields? If so then i see problem if you are using DDD and have business rules in your model which can be jailbreaked by simply creating an implicit / explicit extension.
Or may i´m wrong here?
They cannot, extension methods in general are only normal methods with a nicer syntax.
The thing interesting me here is both the possibility of having some niceties (like .dp/.sp/.rem of Kotlin for UI) and a possible structural parametric polymorphism.
This looks great for modding. A few questions on it. Fields? How does the lowered code look?
Fields - definitely not. That would require inheritance.
Yeah, fields are impossible in this sense without modifying the CLR, and this I think would not be good anyway (because it would be a mess, literally, because serialization and many assumptions about data layout we need to make when developing programs). But you can simulate this explicitly if you want with a weak hash map.
In the video as an example was shown a situation, where you could use simple inheritance to extend Person class capabilities and get the same experience with properties and Adult class. But you won't be able to use inheritance if class is sealed. Does this new C# feature works with sealed classes?