The New Constructor Type Coming in C# 12 is Weird

Поделиться
HTML-код
  • Опубликовано: 22 ноя 2024

Комментарии • 379

  • @lowds
    @lowds Год назад +575

    We’re about two C# versions away from being able to have a certification exam dedicated to object creation and initialization

    • @logank.70
      @logank.70 Год назад +43

      I think we're already about there. There are so many features now that you have to agree as a development team what features you aren't going to allow.

    • @robl39
      @robl39 Год назад +81

      What can be confusing about a Ref struct value task async record 😂

    • @myname2462
      @myname2462 Год назад +3

      @@robl39 :D

    • @kenbrady119
      @kenbrady119 Год назад +3

      Aaaargghhh! I guess it's time to go back to BASIC!!

    • @KoScosss
      @KoScosss Год назад

      @@robl39 depends on schedular too

  • @pablocom
    @pablocom Год назад +83

    In my humble opinion: confusion it creates > benefit we get

    • @igorthelight
      @igorthelight Год назад +9

      I think that most languages get bloated with features that do almost the same but in a new "cool" way.

    • @BlackDragon-tf6rv
      @BlackDragon-tf6rv Год назад

      @@igorthelight ehjm how js classes are just old objects prototypes with another syntax

    • @bobweiram6321
      @bobweiram6321 Год назад +2

      These new features hide what's going on behind the scenes. Few programmers will know about the implicit code, resulting in less code. I just learned about record class and record struct.

  • @LeMustache
    @LeMustache Год назад +115

    While this seems alright, I feel like doing what Typescript does (automatically creating & assigning fields when you add an access modifier to a constructor parameter) would be more flexible and clear than what they're planning here.

    • @CabbageYe
      @CabbageYe Год назад +7

      Yeah I prefer that I think

    • @Krilllind
      @Krilllind Год назад +10

      I was just about to comment the same thing. This looks way better to me:
      class Person
      {
      Person(
      private string firstname,
      private string lastname) {}
      }
      You could even allow for read-only here and it would still be very readable. Only thing is that it's deviating from Records syntax.

    • @modernkennnern
      @modernkennnern Год назад +3

      Doesn't work; C# allows multiple constructors while JS does not

    • @Krilllind
      @Krilllind Год назад

      @@modernkennnern See that's the entire point of a team working on a language, it can evolve over time🌟

    • @LeMustache
      @LeMustache Год назад +3

      @@modernkennnern Fair point, I didn't consider it.
      It doesn't make introducing it impossible, though. You could always impose some restrictions when using this feature. Even the same as the current prototype presented in the video imposes.
      So we're basically stuck between the TS syntax which is nice, intuitive and simple but inconsistent with how the records work and the record's syntax which is less intuitive and much different to how constructors look like now, but consistent.
      Since I've never been a fan of C# records, I'd still prefer them going the TS route.

  • @borgking620
    @borgking620 Год назад +53

    I feel the C# team when adding new features have stopped thinking about why they are adding features. A lot of the recent bloat feels like they saw something that was working in different languages, but they didn't stop thinking if this was appropriate for the language. Like what are they trying to solve? primary constructors are basically record syntax for classes, which itself was just adding a new keyword for what they are doing now + a bit of syntactic sugar?
    To go to one of my more extreme opinions I would say it even goes back to Auto-Properties which are just syntactic sugar for technically not breaking encapsulation while functionally breaking it and without actually acknowledging why you would or wouldn't encapsulat in the first place...
    The core problem imho is that the C# team seems to add features without thinking about what you would want to encourage, and what you wouldn't. Kotlin for example is default non-nullable to discourage null-use, and offers different approaches with the Optional-type for example. What are primary constructors trying to encourage, except for just having an extra-way to write a constructor? Kotlin uses it to decouple actual values from initialization logic (Kotlin encourages not having more than one constructor), but for C# I feel they just put it in because people like it in Kotlin...
    Sometimes a language with fewer features (that are more coherent) is better for creating good software...
    /edit: Previously I wrongly stated that Kotlin only had one constructor. Thanks Vasiliy for pointing that out!

    • @vasiliychernov2123
      @vasiliychernov2123 Год назад +3

      >Kotlin doesn't actually have more than one constructor
      This is incorrect. You can have secondary constructors which delegate to the primary one, or have no primary constructor at all and declare multiple different constructors using "constructor" keyword in the class body. If you meant you can't have more than one primary constructor, well, that should be obvious.

    • @Dimencia
      @Dimencia Год назад +3

      Most of the recent focus has been trying to remove 'boilerplate', code that we write over and over in 90% of use cases. A big chunk of usings at the top of every file, static void Main, and etc are all things that just get in the way of understanding the code, they tell us nothing that we need to know and make it seem more complex than it is. This falls into the same category; the code is much easier to understand and maintain when it's concise and to the point, and this can be used as-is with DI (which a good 90% of modern code uses), which otherwise can easily take up an entire page of nothing-code
      If you really prefer it to be verbose, you can write lowered code yourself. If you think lowered code is hard to read or understand, then you see firsthand why syntactic sugar is valuable

    • @borgking620
      @borgking620 Год назад +2

      ​@@Dimencia I think you misunderstood. I am not against syntactic sugar at all. I just think that when adding features the considerations should go beyond "this is done often, so lets add a shortcut", but something that is purposeful in encouraging good design.
      If you have two features that look similar on the surface, but are different in subtle details that might lead to confusion and actually create problems (like Primary constructors in classes vs the same in records)
      If you have features that actually encourage bad design patterns (like auto-properties do by telling you that a field is encapsulated, when in fact it is usable as if it wasn't), that can also create problems.
      On the other hand you have stuff like the null-conditional and null-coalescing-operator (?. and ??) which encourage checking for nulls and therefore making the code more safe without creating massive boilerplate.
      I also really like the automatic main for short programs, as this was just boilerplate in cases where you would want a 2-3 files-program
      My point is that a feature should not just be a shorter way to do stuff, but something to encourage good and clean design. It should remove redundant information without removing necessary context. It shouldn't be easy to confuse but clear up confusion.

  • @astralpowers
    @astralpowers Год назад +22

    My first thought was the confusion with the record semantics. Maybe just extend the record semantics, like adding the field keyword to make it a field instead of a property. For example: public record class Person(field string name, int Age) will have name as a field and Age as a property.

  • @juri1music
    @juri1music Год назад +57

    Every time I create a constructor in TypeScript, I wonder why I can't do something similar in C#. I will be very happy if this feature is finalized and it will be included in the final .NET 8 release
    In TS this looks like next
    constructor(
    private myPrivateField: string,
    public myPublicField: string
    ) {
    // constructor logic goes here
    }

    • @thecubicnoobik9792
      @thecubicnoobik9792 Год назад +3

      Short answer: usually that's a bad idea to have public fields and you should use properties instead.

    • @diadetediotedio6918
      @diadetediotedio6918 Год назад +7

      @@thecubicnoobik9792
      If your fields are readonly it is not really a problem

    • @lordmetzgermeister
      @lordmetzgermeister Год назад +1

      @@diadetediotedio6918 It's not a problem until it becomes a problem. That's why we have encapsulation.

    • @diadetediotedio6918
      @diadetediotedio6918 Год назад +4

      @@lordmetzgermeister
      Encapsulation won't save your code from breaking when it has to break, that doesn't even make sense, when you make a field readonly it's precisely because you're building immutable models, other languages of more functional veins keep the same pattern in relation to that.

    • @lordmetzgermeister
      @lordmetzgermeister Год назад +2

      @@diadetediotedio6918 Of course it will. What won't save you, on the other hand, is not understanding why we actually have properties.

  • @lordmetzgermeister
    @lordmetzgermeister Год назад +12

    I like that primary ctors use the same syntax as records, it's clean and simple. I hate that it looks the same but acts differently.
    If they unify those two and add all the initialization options (access modifiers, get/set/init, required, readonly,...) it would be quite complex but still more concise than what we currently have.

  • @patrick71994
    @patrick71994 Год назад +4

    I really like this feature for the many cases where you are only using the ctor for dependency injection. It doesn’t mean that you have to use this feature for every ctor from now on. Just don’t use it when it doesn’t make sense or switch to a record.
    I really like this

  • @jeremymarsch1584
    @jeremymarsch1584 Год назад +4

    I liked the Kotlin implementation. It seemed expressive and clear. TypeScript does something similar as well, and after years and years of using DI, I've learned the view the constructor not so much as a place to put logic, but more as a declaration of the dependencies for my class. The primary constructor really seems to cement this philosophy. I like it!

  • @Maxim.Shiryaev
    @Maxim.Shiryaev Год назад +6

    Could save a couple of lines but on the other hand it could force a programmer to work as such a code-lowering tool (like sharplab) just to figure out what this code _actually_ means. And the main problem is the confusion with records so that exactly the same syntactic construction leads to another result.

  • @diadetediotedio6918
    @diadetediotedio6918 Год назад +29

    I think the C# team should be more concerned with improving compiler type inference (it's really terrible compared to something like Kotlin or Rust), and also working on a solid escape analysis system, but it's an interesting feature still so.

    • @jongeduard
      @jongeduard Год назад +2

      I kinda agree and I have even done a suggestion in the csharplang github repo to be able to declare things with var variableName; (without a type behind it) and infer the type based on later assignments, but it got downvoted and rejected.
      Though strangely I must also admit that I am actually used to being very explicit in specifying types in C# code as well (this is probably because I am a C# developer since the very beginning of .NET), so it's also something I feel difficulty with to have a very strong opinion about. :)
      But currently I am very actively learning Rust too and this influences my ideas a lot (absolutely magnificent programming language), bringing me back to the idea of flexible inference again.

    • @anthonysteinerv
      @anthonysteinerv Год назад

      And if you compare all 3 with C++ they are all in diapers.

    • @diadetediotedio6918
      @diadetediotedio6918 Год назад +1

      @@anthonysteinerv
      Yes, yes, I think after much thought I can see, you have... SEGMENTATION FAULT (core dumped)

    • @anthonysteinerv
      @anthonysteinerv Год назад

      @@diadetediotedio6918 You know there are exception too in C++? and that you can code without them in both C++ and C#, just the error message is different. UnhandledException or NullPointerException from Java, or any of those Fancy errors, are just that, fancy errors. So weird ass comment. And doesn't change the fact that C++ is years ahead of any other programming language in type inference.

    • @diadetediotedio6918
      @diadetediotedio6918 Год назад +1

      @@anthonysteinerv
      Yes dear, I know that there are exceptions in C++, and this is more of a problem in many cases than a positive thing (as we can see in the "Meeting C++ 2022", Rust doesn't have this problem for 99% of the cases), I think you had a hard time understanding that my statement was a joke. I don't give a shit about type inference in C++, because I'm talking about C#, I was getting inspiration from two languages with insanely powerful type inference, which are Kotlin and Rust, I honestly couldn't care less about using C++ as an example in this case . C++ has type inference on return types, if you can't conceive of how this is a problem from a code readability point of view. But I found your statement quite interesting, can you show me how the type inference of C++ is superior to that of a language like Rust for example?

  • @metaltyphoon
    @metaltyphoon Год назад +32

    This is becoming crazy to keep up. Record struct and record class already behaves differently. Now this… I can see now how Rust and Go have the right approach “There is only ONE way to create an object”. If you want to use the convention of “NewObject” (Go) or “Object::new()” (Rust), then it is up to you.

    • @BenjaminBrienen
      @BenjaminBrienen Год назад +1

      Yet even rust has:
      MyStruct { field = value }
      MyTupleStruct(value)
      MyStruct::new(value)
      MyStruct::merely_a_convention(value)
      my_macro!(value)
      my_macro! { value }
      Then add on all the verbosity of using generic arguments, sometimes even a :: fish operator.

    • @metaltyphoon
      @metaltyphoon Год назад +12

      @@BenjaminBrienen none of what you said was a way to fundamentally construct a struct. Everything you wrote are “helpers”

    • @henrycgs
      @henrycgs Год назад +3

      well, rust’s case goes deeper than that. new is just a function that you may or may not define. you create structs and enums by using their inline constructors and return them. is clear and it’s simple.

    • @_sorashi
      @_sorashi Год назад

      @@henrycgs you literally said the same thing as OP

    • @henrycgs
      @henrycgs Год назад

      ​@@_sorashi I might be wrong, but I'm pretty sure OP edited their comment to include that stuff

  • @computer9764
    @computer9764 Год назад +26

    The confusion between classes, structs, records(classes), and record structs is already too much. I like the record idea, but I think having a direction to move towards is important. Sharing syntax but doing different things is a mine field that should be avoided.
    I do most of my work in C# and it's hard for me to do something different without a guide/flowchart pulled up and
    It's also a minefield to have the required keyword introduced, but not really be usable in many situations because JSON deserialization doesn't set it properly. It seems like they're thinking about adding more to the language without thinking of the long-term. I don't want to insult anyone working on the language; it's really a great language; I just think we need to maybe think of a breaking change that could consolidate all these disparate attempts to make the language more modern.

  • @yngndrw.
    @yngndrw. Месяц назад

    This has only just come onto my radar so I'm only a little late. Although the underlying implementation uses hidden fields, logically I see primary constructors being closely related to the concept of closure. If you look at the compiler-generated code and compare primary constructors to the closure of a local variable, you can see how it uses exactly the same techniques internally:
    - A lambda function is a hidden method within your class.
    - Adding closure of a local variable moves that hidden method into a hidden nested class, with a hidden field representing the closure.
    - Primary constructors use hidden fields on your class, but the extra hidden nested class is not required as the scope spans the entire class.
    There are some other parallels you can draw - Remember how classes used to be approximated in JavaScript before native classes were added? They used nested functions with closure - Which looks very similar to what's happening with primary constructors.
    I thought that it was interesting to point out the parallels with closure as I've not seen it mentioned elsewhere.
    As to whether or not I think it's a good idea: No, I think it adds too many contradictions with other parts of C# to justify the benefit of slightly reducing your class initialisation code.

  • @LeutnantJoker
    @LeutnantJoker Год назад

    For how applications work nowadays I like this. An injection constructor is never called (outside of testing). All it does is define the dependencies. And it kind of makes sense to have that in the class declaration header itself

  • @fred.flintstone4099
    @fred.flintstone4099 Год назад +1

    Some of these new features and syntactic sugar are nice, but some of it just makes the language complex and confusing, much to learn, much to remember, "cool" things that are rarely used, and things that I come across that I would not be familiar with, or be easy to grasp. I like records and init setters though. I would rather see something useful like a Result type like in Rust.

  • @Nekroido
    @Nekroido Год назад

    I like the way they implemented similar feature in PHP 8: constructor property promotion. You just pass visibility, type, and property name as contructor parameters and use them as if they were declared in your class: ```__construct(protected string $firstName, protected string $lastName, string $regularParam)```. Remove visibility, and it's now a regular parameter.

  • @AConversationOn
    @AConversationOn Год назад

    A note on phrasing, in native english we say "*What* it will look like", rather than "How". Though we do sometimes say "How it will look". Confusing, but the what/how issue is quite common in non-native speakers and it sticks out in phrasing. You otherwise would sound pretty native.

  • @talwald1680
    @talwald1680 Год назад

    I love the kotlin approach, but F# also has it right -
    Use type keyword to define a type, add an atribute to signify that it is a struct, and enable let bindings (init logic) anywhere in the class.
    Records use a different syntax to highlight the difference.

  • @kostasgkoutis8534
    @kostasgkoutis8534 Год назад +34

    "Back in my day, we only had simple constructors, no separations between primary and secondary, everyone was equal. We wrote all our good old boilerplate and we were happy about it too! Nowadays, young people are fighting needlessly whitespace left and right, as if they don't have the best IDEs and AI autocompletion tools, they don't even write code anymore, they just press Tab and call it a day. Ah, life was so simple. Those were the times." says, rolling in his armchair.
    Yeah... I'm not convinced. Sorry.

    • @diadetediotedio6918
      @diadetediotedio6918 Год назад

      LMAO

    • @Tekner436
      @Tekner436 Год назад +2

      Yep, nowadays we can write the same software, just in 20 different styles.

    • @seesharp81321
      @seesharp81321 Год назад

      I really hate this AI code completion. Don't know what the I stands for, but it's not intelligence. Constantly hitting key unnecessary, totally slowing me down

    • @douwehuysmans5959
      @douwehuysmans5959 Год назад

      @@seesharp81321 I immediately turned that s*** off

  • @killymxi
    @killymxi Год назад +1

    The reason I'd like all constructors to use a keyword like "init" - it does not need to be renamed when the class is renamed.
    Default behavior is all over the place already regarding readonlyness.
    If this is going to be added - it better come with something like "public" and "readonly" specifiers to be able to achieve desired behavior.
    Maybe C# should start to introduce the "mutable" keyword so it would be easier to go with readonly by default.

  • @youtube-is-cringe
    @youtube-is-cringe Год назад +12

    Seems like in some time C# will look something like C++ with all the grammar and 14 ways to init a variable😂

    • @igorthelight
      @igorthelight Год назад +2

      Even the Python which positions itself like "easy and readable" already have so much bloated features... ;-)
      Oof...

  • @antonmartyniuk
    @antonmartyniuk Год назад +4

    It's really a confusing feature but when implemented properly it might be helpful like in Kotlin. So if Microsoft is going to do this - please make it once and do it properly

  • @benjaminclehmann
    @benjaminclehmann Год назад +2

    I think given that records already do it with differing semantics it probably ought to default to the record behavior and then you can add an access modifier (public/private/protected) in front of the identifier to get the different behaviour.
    Or perhaps a different modifier, as one might expect `public` to only change the visibility level, not whether it's a field or a property.

  • @DaviGn
    @DaviGn Год назад +1

    C# becoming ES. This kind of short constructor already exists, including such things as private, readonly and so on.
    Someone suggested to specify property or field in the proposal about an hour ago. Maybe a follower from here :D

    • @nickchapsas
      @nickchapsas  Год назад

      Primary constructors were a C# 6 feature that was scrapped last minute. It's not an ES/TS/JS concept

  • @billy65bob
    @billy65bob Год назад +1

    I have to agree, the feature needs more thought put into it. Maybe C# 13.
    IMO it makes more sense to let records have modifiers (i.e. readonly) instead of whatever this is.

  • @ivantatarchuk697
    @ivantatarchuk697 Год назад +6

    For me personally, it is a kind of magic I dislike. It would be better to have one-for-all syntax feature like records to fit all these kinds of operations.

  • @jameshancock
    @jameshancock Год назад +4

    Needs public/private and properties as you said with set/init.
    And record and class should work the same.

  • @Avabin
    @Avabin Год назад

    That might be a good way to create the same behaviour as records, however only if those two behave the same way. Specifying an access modifier in primary ctor would be nice too, I find it easier to read, especially with a lot of value object and dto classes.

  • @Tamer_Ali
    @Tamer_Ali Год назад +4

    Hi Nick,
    I hope you talk about Vertical Slice Architecture and compare it with Clean Architecture and when you recommend to use each one of them?

  • @jamesmussett
    @jamesmussett Год назад +2

    As like a lot of other people in the comments I much prefer typescript's approach. Although I do know that the idea was dismissed mainly because C# supports multiple constructors unlike typescript.
    Personally, I'm not really keen on the proposal and probably won't utilize it when it's introduced, especially when you have behavioural differences between records and classes. DI is a pain, but i can live with it.

  • @calvinwilson3617
    @calvinwilson3617 Год назад

    Awesome to hear about the AWS course! Love the others you offer

  • @diadetediotedio6918
    @diadetediotedio6918 Год назад +1

    A better approach for this would be like:
    public class User
    {
    public User(private readonly string firstName, private readonly string lastName)
    {
    // Initialization code goes here
    }
    }
    This solves the need for a init keyword and also makes it more explicit about what the code does
    A thing like:
    public class User
    {
    public User(property FirstName, readonly property LastName)
    { ... }
    }
    Could also be done for properties, so taking properties as public-by-default (because there is no reason to not do so, it is a default in the language) you can make them very shorthand

    • @nickchapsas
      @nickchapsas  Год назад

      This defeats the purpose of the primary constructor being instantly obvious. It can't move from the class declaration. That's the whole point

    • @diadetediotedio6918
      @diadetediotedio6918 Год назад +1

      @@nickchapsas
      I think it's more obvious than the constructor that looks like records but actually creates private fields. You could also make it so that it is only possible to declare these constructors as the first members of a class (generating a compilation error if the opposite is done), but in any case that seems to me the only way to do this without making classes easily confused with records, in addition to being an existing and common thing in TypeScript.

  • @DanteDeRuwe
    @DanteDeRuwe Год назад +20

    Why not just follow the Typescript way and put access modifiers in front of constructor parameters to make them fields/properties?
    e.g. public class Person { public Person(private readonly string firstName) }

    • @volan4ik.
      @volan4ik. Год назад

      Your example is a little bit complicated. Better to not introduce new syntax at all instead of doing what you want

  • @markovcd
    @markovcd Год назад

    I was really glad to hear at the end that you also have the same problem with it as me. I was cringing entire video because of this inconsistency.

  • @BradleyMyers16
    @BradleyMyers16 Год назад

    I personally like Dart's approach to this, where you write the field yourself, and as a parameter to the constructor, simply reference this.fieldName. In c# it would look like this:
    class Person {
    private readonly string name;
    public Person(this.name) {}
    }
    var john = new Person("John Smith");
    This seems way more flexible and readable to me while eliminating the extra assignment line.

  • @hifiguitarguy7578
    @hifiguitarguy7578 Год назад

    The big thing I see missing here, param validation.
    Unless your class is IValidateableObject, and DI should trigger that upon resolution.
    But that's gonna be weird for other instantiation outside of DI.
    What I've been wanting are param attributes, think of [FromBody] except more like [NotNullOrWhitespace].
    I hate writing boilerplate param validation on ctor and methods.
    Some may not know VB has a default constructor syntax, but in C# we have [InjectionConstructor] and I believe we also have serialization ctor attributes.

  • @AlexKushnirNET
    @AlexKushnirNET Год назад

    It would be nice if Microsoft could apply the same approach we have in the typescript for constructor vars, where the variable access level can be defined explicitly in the constructor.

  • @DummyFace123
    @DummyFace123 Год назад

    I’d like it to mirror typescript, I think they got it right. Declare properties in the constructor, and also have initialization code in one constructor.
    Anything else would just be confusion

  • @ApacheGamingUK
    @ApacheGamingUK Год назад

    My immediate thought, when seeing this, was the naming conventions. It was shown in the video that it causes a conflict. Underscore prefixed fields denote private object scope, while parameters are passed without the underscore prefix. Because it just uses the raw parameter name, without prepending an underscore, it makes it read like a local scope variable, rather than an object scope private field. I don't like the fact that this removes that distinction.

  • @ThisCanNotBTheFuture
    @ThisCanNotBTheFuture Год назад +35

    New versions of C# come out so fast now I feel like we're being trolled by Microsoft.

    • @igorthelight
      @igorthelight Год назад +2

      Once per year as most other languages.
      Personally, I don't think that we NEED all of those changes ;-)

    • @ThisCanNotBTheFuture
      @ThisCanNotBTheFuture Год назад

      @@igorthelight Agreed.

  • @sirflimflam
    @sirflimflam Год назад +4

    Remember when C# was rigid by design? Compared to the early days it's unrecognizable.

  • @v0id_d3m0n
    @v0id_d3m0n Год назад +1

    I think being explicit is more important than bekng concise. In this case, a lot is obfuscated imo (specifically the mutability and access of the variables), which seems like a code smell to me.

  • @xparadoxical69
    @xparadoxical69 Год назад

    it just doesn't feel good at the moment. I agree with the entire video, it will only bring more confusion to an already large confusing list of ways to create an object, and it's a limited feature. The syntax of primary constructors should simply allow you to put AUTO-property (no custom accessor bodies) and field declaractions there *in their full form*, that is class C(public readonly int i, j, k; /*public by default*/ ISomething { get; init; }). But that would make people split the "parameter" list into multiple lines, at least one per a member declaration. That's why imo the record-like syntax for classes should be scrapped and the feature should be a specially annotated block in the class body: init { /*property (not restricted to auto-props) and field declaractions, or in other words any declaraction that can also be made a parameter; the order of declaractions matters, member names are converted to camel case parameter names*/ TypeName { /*this is a constructor, so here goes a list of statements*/ } }

  • @freddyflares2757
    @freddyflares2757 Год назад

    It's a bit much. The naming of init {} further confuses things because in some classes there can be an Initialize() method which will be called later some time after construction.

  • @acetributon
    @acetributon Год назад

    It honestly looks more simple than calling it over and over, a javascript perception. I have yet to touch c#, but this looks promising.

  • @rGunti
    @rGunti Год назад

    I do like the idea, especially with dependency injection. I do think though that stuff like an init block is overcomplicating it a bit. At this point, I'd pick a regular constructor. The reason I started using stuff like records is that I can quickly cobble some classes together and to have them comparable for unit tests.
    And, as most others said, maybe the TypeScript route would be better. Allow any access modifiers in the (primary) constructor to make them fields. If you want to add another constructor, you could then be forced to call the primary one or just not allow it.

    • @holger_p
      @holger_p Месяц назад

      It's a dilemma between having it complicated but hidden and simplified writing ...or less hidden and all visible, but more to type.

  • @DanielFerreiraMonteiroAlves
    @DanielFerreiraMonteiroAlves Год назад

    I was waiting for primary constructors for a long time after playing with Kotlin in the past. Kotlin has a lot of features that would be amazing to use in C# like delegated properties, extension methods and properties with contexts, etc.

  • @tharfagreinir
    @tharfagreinir Год назад

    I can understand the thinking behind this feature - assigning properties directly from parameters passed into the constructor is a big part of what you do in constructors. However, I'm not sure that getting rid of the property declarations all together is such a good idea as it can lose transparency and flexibility. It really does look like they're trying to use ideas from records and implementing them for classes but for me at least, there's a reason why classes are the way they are.

  • @TheMAZZTer
    @TheMAZZTer Год назад

    TypeScript has something similar to this, while you still need to add the arguments to the constructor, you can prefix them with public or private to automatically create properties on the class. Angular templates leverage it for DI as you stated this sort of thing is useful for. Interesting to see something similar coming to C#.
    I feel if you need code in your constructor this feature doesn't make as much sense as you're not saving much by omitting the formal constructor declaration. Might as well do it at that point. So I would be OK with a primary constructor not having code behind it. VS should be given a lightbulb action to convert a primary constructor into a formal one for cases where a dev needs to add code.
    I think required properties are going to be the better feature here, at least for my uses. That said constructors have their place as well, though I think if I had a constructor with only boilerplate as in your example I would want required properties.

  • @Dxpress_
    @Dxpress_ Год назад

    Definitely wouldn't mind adding some Kotlin language features over to C#.
    I hope this means interface delegate implementations might be on the horizon as well.

  • @ExpensivePizza
    @ExpensivePizza Год назад

    Great feature. They only thing that bothers me is the subtle difference between the public properties of records vs the private properties of classes. This distinction will confuse people and lead to mistakes and possibly bad practices.

  • @8ytan
    @8ytan Год назад

    Worth it just for the dependency injection benefits IMO, but the lack of consistency with records is just asking for people to get confused and make mistakes.

  • @davidkroukamp
    @davidkroukamp Год назад

    First used this in Kotlin, I liked it helped to remove redundant code. Sure there are cases where it might not be worth the lines saved, but still love it.

    • @borgking620
      @borgking620 Год назад +1

      I also like it in Kotlin, but for another reason: It forced me to acknowledge what is the actual "default" way to create an object. Since Kotlin only encourages one constructor for anything non-standard I would need to create a static function (well, "companion object function"), which forces me to actually name it, which removes a lot of confusion when I have a lot of ways to create an object, and what is actually the "official" way an object works.
      for example a "struct Temperature" with 2 static function "FromCelsius" and "FromFahrenheit" and a private value "inKelvin", that is used in the default constructor is a lot more clear, than a constructor that takes two arguments, one of which is an enum used to define what scale the temperature is in. With only having one constructor and all values being saved Kotlin encourages the first pattern.
      /edit: Kotlin can have more than one constructor, it is just not as common as in other languages.

  • @ddd12343
    @ddd12343 Год назад

    Quick Google search shows that primary constructors has already been discussed to be implemented even before release of C# 6. Took a really long time.

  • @yuGesreveR
    @yuGesreveR Год назад +1

    Another problem with this feature (besides the readonly problem) is that there is no way to declare fields as protected

  • @jimread2354
    @jimread2354 Год назад +2

    It used to be code was hard to read because machine language or assembly were not syntactically similar to spoken languages, but at least everything that happened was represented in the code. Now, I feel like it's getting hard to read because one line of code can trigger so many operations that aren't represented in the codebase but that to affect the codebase (like adding fields that aren't visually present). The syntactic sugar is getting so thick, you can't see the shape of the cake. I feel like if you condense too much functionality into a single line of code, while easier to write, it can start to become difficult to maintain. For this particular feature, having the ability to add logic seems to undermine the whole feature because now you've just got your parameterized constructor and you're really not saving anything, you're just scattering the definition around and obscuring the effects of the code. Personally, I would limit the use of this to really trivial cases, otherwise you end up with:
    class definition (also maybe constructor parameters) : more class definition stuff here
    {
    fields (except the ones that are up there in the class def line)
    properties
    implement the apparently nontrivial constructor whose parameters are up there in the class definition
    function that uses fields that aren't actually in the class definition, they're just implicit because of the function parameters tacked on to the end of the class name, because now that's also a constructor definition whose implementation is (maybe) down here.
    }
    it's kind of a mess if you ask me.

    • @igorthelight
      @igorthelight Год назад

      Agree!
      Even Python have this feature bloat problem now (and it presents itself as easy and readable).

  • @markgottselig3059
    @markgottselig3059 Год назад

    This feature would be nicer if we had the bangbang operator that was taken out. I have no guarantee that my DI system will be injecting a valid instance, and I almost always want to check for null in my constructor

  • @CyrinInflatophin
    @CyrinInflatophin Год назад

    People should be wary about adding too many new syntaxes to a mature language like C#, all it does is add complexity and heighten the learning curve. Plus, with this particular feature, it seems to go against the way people write classes - don't add a bunch of named private fields to a class, only to have them exposed later as properties - just use auto-properties. I get the argument about dependency injection, and sure, it would reduce the amount of code you need to write in that specific situation... but it still seems like the wrong way to go about it.

  • @Papierkorb2292
    @Papierkorb2292 Год назад

    I see a lot of comments mentioning typescript constructors, but I think that would cause more confusion, since different constructors could create different properties.

  • @Palladin007
    @Palladin007 Год назад +12

    I won't use this feature.
    I like the records approach, if I just need a collection of values it saves me a lot of work.
    But with the normal classes I often have more, there the constructor is rather a minor matter - or the class is too complex.

  • @DevonLehmanJ
    @DevonLehmanJ Год назад +7

    I would settle for "init" being a keyword we can use to mean "constructor". Just to make ctors more concise and not repeat the full type name, and make it consistent across all classes.

    • @phizc
      @phizc Год назад +1

      Perhaps
      .ctor( string arg )
      {
      }

  • @andyfitz1992
    @andyfitz1992 Год назад

    I can see the advantagious idea of simplfying constructor based DI code into a class with this pattern but I can't help but think that adding some kind of mapping attribute to inform the compiler of whether the parameter would be [Field] or [Property] would be more flexible? Perhaps akin to the same syntax that minimal API routes adehere to for the handler delegate.....just my two cents.

  • @andersborum9267
    @andersborum9267 Год назад +3

    It's definitely going to reduce the amount of boiler plate required to accept (and verify) dependencies, but at the cost of yet another way to define classes/structs. Is it possible to still do manual validation? (i.e. public class Person(readonly string firstName) { if (string.IsNullOrWhiteSpace(firstName)) { .. } } and still have the compiler assign the private field?

  • @gbjbaanb
    @gbjbaanb Год назад

    If this new constructor syntax is designed to solve a problem with DI constructors (which is a problem) then its addressing the symptom and not the cause. Its like swallowing a spider because you swallowed a fly. MS should be looking at compiler tweaks to make DI less of a dog, and perhaps even making compiler features to inject (or mock) function calls so DI is not needed in the first place!

  • @dimalisovyk5277
    @dimalisovyk5277 Год назад +1

    As usually, C# takes feature from other languages. It exists in TS and Kotlin

  • @zaoralj
    @zaoralj Год назад +1

    It would be nice to have readonly and something for null check as well (!!)

  • @raptorjesus3396
    @raptorjesus3396 Год назад +5

    I and many of the community have argued against realizing the record constructor arguments as public properties. Now the fabulous dotnet team, proposes the very same feature, in addition to the record constructor which is the very same syntax. In German we say "die ham doch wohl den Arsch offen". But that would be to impolite to write in a discussion. So I'll just leave my anger here

  •  Год назад +1

    What about the way Typescript allows defining fields -
    in the constructor function you define the parameters as how they should behave -
    public constructor (private name: string, private surname: string) {} // This will create private name and surname fields.

    •  Год назад

      Didn't see such love for Typescript in the comments 🙃

  • @Colton7909
    @Colton7909 Год назад

    I'd like to build on the work record has already done. Public mutable properties by default, but with the ability to add private/protected/internal readonly to the declarations. I tend to use get only properties for DI instead of readonly fields anyway. If you need init logic, make a regular constructor.
    ...or nothing. Not sure I love this feature.

  • @HarshColby
    @HarshColby Год назад

    For consistency and because the backing fields are hidden from view, they need to be private and mutable. I like the init { } keyword best of the options given.
    Just my 2 cents.

  • @cyril113
    @cyril113 Год назад +1

    This and records should have been the same feature. Like in Kotlin you can add the "data" keyword and it will turn into a record but the constructor/property semantics are still the same as with normal classes. I like this feature but I don't like the inconsistency it creates.

  • @robinpage2730
    @robinpage2730 Год назад

    I recently had an epiphany: functions are just glorified macros. You peel away the layers of abstraction, you find the underlying assembly language/machine code is just macros. It's macros all the way down.

  • @kylekinnear8878
    @kylekinnear8878 Год назад

    I wish it was just the record syntax but for classes. Big difference would be that class properties are mutable, whereas record are immutable. I just want to eliminate POCO boilerplate.

  • @jongeduard
    @jongeduard Год назад

    Yep, I think it's valid to say that it's a bit too confusing in combination with the existing record struct and record class syntax in the language.
    I think they need to do something extra with more keywords to make the distinction between this new constructor syntax with the existing record syntax larger.
    I also see a problem that we need to use underscores inside the default constructor (which looks bad) if we want to prefix our fields that way, while this naming style has become the convention in many projects now. It does not fit well anymore.

  • @mikim.6338
    @mikim.6338 Год назад

    I would prefer to have a constructor that works similarly to the one in Dart:
    class Car {
    String make;
    String model;
    String yearMade;
    bool hasABS;
    Car(this.make, this.model, this.yearMade, this.hasABS);
    }
    This way you don't mix constructor with the line responsible for class declaration.
    Also, current proposal will be looking ugly if you add 5 (or more) variables and implement two or more interfaces and maybe add some generic parameters as well.

  • @TheZigsDk
    @TheZigsDk Год назад

    I'd really prefer leaning more on the required keyword, which remove the dangers of property DI.

  • @logicalsparrow2130
    @logicalsparrow2130 Год назад

    Unfortunately, this doesn't solve one of my common uses cases: creating classes that will go through JSON conversion. Those require either a constructor with no parameters or some custom code. However, I like it when I can use a constructor with all the necessary parameters since calling that is more concise than initializing each property. In other words, I need this feature to be able to generate two constructors.
    I would prefer to maintain the ability to add as many modifiers as I normally would be able to use. Additionally, as mentioned by at least one commenter below, I'd prefer this to create properties instead of fields by default to be at least mostly consistent with records, and the field keyword can switch it back. At least the new syntax would mean that the adding field keyword wouldn't break old code.

  • @mrx10001
    @mrx10001 Год назад +1

    Idk why not just modify record at that point so it uses fields instead of properties and just have the ability to set private/protected/public in the field deceleration.
    Seems rather weird to have 2 different ways for such a minor thing.

  • @F1nalspace
    @F1nalspace Год назад

    Hmm i dont like it very much. The reason for this is simple: I really hate when compilers automatically modifys or generate codes - making it unnessecary hard to follow the control flow.
    This is especially true when you use attributes that are designed to do this -> POCO ViewModel or automatic dependency injectors for example.
    But if this feature will come and i need to deal with that - then i would want to have at least control of the visibility like this:
    class User(string firstName, string lastName) -> private by default, fields only
    class User(private string firstName, private string lastName) -> same as the first one
    class User(readonly string firstName, readonly string lastName) -> private readonly fields
    class User(public string firstName, public string lastName) -> public properties -> CamelCase
    class User(internal string firstName, internal string lastName) -> internal properties -> CamelCase
    The same for structs and for records - it should be consistent.

  • @barionlp
    @barionlp Год назад +3

    they have to find a way to make clear what the differences are

  • @nooftube2541
    @nooftube2541 Год назад

    It would be nice to have constructor for services that automatically set all parameters from base ctor (if it single, for instance)

  • @Galakyllz
    @Galakyllz Год назад +5

    With every update to C#, I'm convinced that they're trying to kill it.

  • @rc3043
    @rc3043 Год назад

    Why not allow: public class User(public string firstName, private string LastName, private readonly Age) or do it like Golang and have Upper-case exposed and lower-case not exposed. Readonly can stay as keyword.

  • @jellylovecz5475
    @jellylovecz5475 Год назад

    I would prefer something along the lines of:
    primary
    {
    private string firstName;
    private string lastName;
    }
    Instead of having it on top of the class definition.

  • @EminoMeneko
    @EminoMeneko Год назад

    Thank you for the presentation. I think it is quite messy.
    As long as it does not break what I do so far, I am not against that new feature though.

  • @AlanDarkworld
    @AlanDarkworld Год назад

    Nick, you should do a Kotlin channel as well! C# is nice, but Kotlin is just awesomeness on a whole new level.

  • @BeansEnjoyer911
    @BeansEnjoyer911 Год назад

    The algorithm sent me this video. Been doing purely functional work for a bit now, and coming back to C# and OOP stuff is kinda weird. I know there are probably benefits if everyone on the team plays nice with the convention, but it’s a lot of extra moving around for very little benefit in my eyes.

  • @nove1398
    @nove1398 Год назад

    Having the properties directly exposed would be awesome, very concise I would vote for that.

  • @lemoncrazedcamel
    @lemoncrazedcamel Год назад

    Really wish they would just yoink the Kotlin implementation. It’s just so simple and streamline

  • @obinnaokafor6252
    @obinnaokafor6252 Год назад

    Excellent feature

  • @everythingiscoolio
    @everythingiscoolio Год назад

    They shouldn't re-invent the wheel. Unless there's an underlying philosophy that doesn't align with the kotlin approach, they should make it as similar as possible. init is by far the best, even though there is really no perfect solution for this except just keeping your constructors empty. In the long run that'll be better anyway. It's great to see what we're able to do now.

  • @inzyster
    @inzyster Год назад

    I can kinda see it useful if I only do dependency injection in a constructor, but then again, I’d also like to have null checks.

  • @pqsk
    @pqsk Год назад

    C# is starting to look like swift and kotlin. I agree this change could cause a lot of confusion. I'm sure Linus Torvalds could give us a rant on why he hates all of this syntactic sugar 😅😅😅

  • @paulkoopmans4620
    @paulkoopmans4620 Год назад

    Well I like the general concept!! I would love to skip my constructors and fields. But both Rider and VS support me enough in generating them and the only way it would work is indeed if it is really really easy, obvious and clean.
    I don't like that the same visual code does different things!! Consistency is key!! C# could match Kotlin. We have var and value as keywords. But unfortunately the tone has been set already with the record type. So I personally would think:
    // (A) What we have now, and allow for readonly to generate getter only
    public class SomeClass(string FirstProperty, readonly string SecondProperty)
    {}
    // (B) Same as A, but explicit with property keyword (property as a contextual keyword is pretty safe
    public class SomeClass(property string FirstProperty, readonly property string SecondProperty)
    {}
    // (C) Ability to create fields with explicit contextual keyword
    public class SomeClass(property string FirstProperty, readonly field DbContext _dbContext)
    {
    SomeClass {
    // would be my favourite, as it is matching the current constructor logic the closest.
    }
    }

  • @franciscovilches7424
    @franciscovilches7424 Год назад

    more confusion.
    would be nice if at one point Microsoft decided to start from scratch with a trimmed down language based on c#. One where there is only one way to do something, not 10. They can pick only the modern features

  • @MrChocolike
    @MrChocolike Год назад

    One correction regarding the Kotlin part: You said at around 7:00 that firstName and lastName in your example were fields. That is incorrect - there is no way to directly declare fields in Kotlin. firstName and lastName in the example were simply constructor parameters you could've used in an init block. (To be honest, I wasn't aware a primary constructor could have parameters defined like that prior to this video. I'm also not sure if I like that it is possible)

  • @ViniciusMiguel1988
    @ViniciusMiguel1988 Год назад

    I think injectable properties is the way to go for DI most of our constructors are getting bloated with DI injection

  • @memelet
    @memelet Год назад

    Just like Scala. I like it.

  • @lx2222x
    @lx2222x Год назад

    It's nice to have :D