I am definitely using them for writing small services used with dependency injection, but thanks for the warning. It is just too nice that I can have 4-5 services in my primary constructor and yet the compiler is smart enough to only create the backing fields for the ones I actually use. So, I can bring in IConfiguration and ILogger, and not worry too much if I am actually doing logging or accessing the configuration at the time. I know the compiler will only bring in what I have used in my code.
Great video Zoran! I really love the fact that you mentioned possible issues with passing parameters directly to methods and not only explained what primary constructors are.
Thank you, Zoran, for the excellent explanation. However, I have one question: Is it worth and possible to use the Primary constructor when I want my class properties to be private and readonly?
You can use it in that case, too. I have tried to say that the primary constructors makes your code by one line pet property shorter and that is all you get. And if you used role syntax to initialize all properties at once, then the primary constructors will save you two lines of code total. That is all there is in them. Anything more you might want to squeeze out of them could put you in trouble. It is a rather minor feature.
Functional programming in C# isn't meant to replace OOP but to complement it. Many problems are better suited to an OOP approach, while others benefit from FP. Having both paradigms available gives developers more tools to tackle a wide range of problems effectively.
i am somewhat disappointed that primary constructors haven't gone all the way. in kotlin, you can specify yourself whether something is only a parameter to the constructor (in which case it can only be used to initialise fields, not in the methods of the class), or you can specify that they are a field of the class, in which case the field gets generated for you. i hope to see something like this in the future
It is possible that C# will receive a few updates to this feature later, once it becomes clear how the programmers are using this feature. But I do agree that, this way, the feature looks half-baked.
There is one big problem I have with primary constructors. There's no way to validate the arguments coming in the constructor. For declaring DTOs sure, but if that class will encapsulate anything, I need to avoid constructing invalid objects. Besides we have records for DTOs. So yeah I don't think I'll be using this feature.
You have stumbled upon the critical element that so many programmers do not understand, and I will tell you the answer cold-turkey way. There is no validation in an object. Now, don't dismiss it lightly as so many others do, but start thinking about it, and, in due time, you will see what designers of C# and many other programmers, including me, see clearly. For a domain model to be valid, it must pass a construction process that depends on the scenario. Since the object itself cannot determine the scenario in which it is used, it is not entitled to perform validation either. If you wish to oppose this statement, then start thinking how exactly would each domain object you use in your code validates itself. I promise you will end up saying: It cannot.
@@zoran-horvat thank you for replying, Zoran, however I fail to understand what you're trying to say. Sure domains can be complex and validity of domain objects can be situational, however most objects can benefit for certain sanity checks. For instance if an argument received at construction is for example null and it is dereferenced in at least one flow implemented by the type, then surely it makes sense to validate it during construction and avoid instantiation in an invalid state. Sure domain entities may not be aware of the context, but they don't need to be if they rely on certain things to be able to work. Besides not implementing a validation on construction, will push the validation to all the clients of that type, and more code equals more errors
@@aivascu Trivial validations are fine and you can do that with primary constructors the same as you do with regular ones: just validate a value on assignment and it is done. As I pointed out in the video, I don't see class parameters as variables one would use throughout the class body. Only use them in the assignment and you will stay safe.
@@zoran-horvat I see what you mean, but implementing something as trivial as checking if a string is null or empty requires throwing two different exceptions in two different control-flow statements, not to mention checking for length, format or boundaries. I guess it is technically doable using the new static functions offered by ArgumentException and something similar to Guards from .NET Community Toolkit or Dawn.Guard, but it sure is inconvenient, and much less readable. I am still not convinced about how useful this constructors are, but thank you for the explanation.
I think i dislike it because what if function parameter have the same name as the primary contructor parameters, i think there is a possibility to mess up too here in a lot of ways.
@@WDGKuurama According to the common rules of C#, the function parameter is resolved first. Naming the constructor parameters by common field naming is dubious because that naming is then visible to the caller.
So primary constructors are a tool for use in Functional Programming? If yes why not just teach functional programming and then use the functional tools in the language to demonstrate that? Instead it seems there's a push to get procedural programmers to use functional tools without understanding why or what purpose they serve leading to a lot of confusion. It reminds me of when c++ brought us Object Oriented Programming and most people just called it "C with classes". We are now in the "Procedural with functional bits" era.
That is the wrong view in my opinion because it acknowledges that programmers are lazy and uneducated. Why not put it this way: Expect programmers to learn programming. It is not that hard if you drop the common excuses that only paralyze your progress. Your example with C++ is a good one. I have never heard anyone I worked with say that in ten years of my career as a C++ programmer, all until I started speaking in public. My point is that that is a blanket statement used to hide behind it and nothing else - a cheap excuse for not learning. That is the loser's wisdom.
@@zoran-horvatI think you've viewing my comment as an attack rather than an observation. What is the purpose of a primary constructor to a non functional programmer? None. It's just a way to write less code, but then they start doing weird and wrong things with the new shiny tool because they still think procedurally rather than functionally. They might write functional looking code (because it's more modern looking) but they are still thinking like they are stuck in the past. Perhaps instead of just adding functional bits to c#, they should have just tried to move people to F# and kept the cool stuff there.
I am definitely using them for writing small services used with dependency injection, but thanks for the warning. It is just too nice that I can have 4-5 services in my primary constructor and yet the compiler is smart enough to only create the backing fields for the ones I actually use. So, I can bring in IConfiguration and ILogger, and not worry too much if I am actually doing logging or accessing the configuration at the time. I know the compiler will only bring in what I have used in my code.
Great video Zoran!
I really love the fact that you mentioned possible issues with passing parameters directly to methods and not only explained what primary constructors are.
Thank you, Zoran, for the excellent explanation. However, I have one question: Is it worth and possible to use the Primary constructor when I want my class properties to be private and readonly?
You can use it in that case, too. I have tried to say that the primary constructors makes your code by one line pet property shorter and that is all you get. And if you used role syntax to initialize all properties at once, then the primary constructors will save you two lines of code total. That is all there is in them. Anything more you might want to squeeze out of them could put you in trouble. It is a rather minor feature.
Functional programming in C# isn't meant to replace OOP but to complement it. Many problems are better suited to an OOP approach, while others benefit from FP. Having both paradigms available gives developers more tools to tackle a wide range of problems effectively.
i am somewhat disappointed that primary constructors haven't gone all the way. in kotlin, you can specify yourself whether something is only a parameter to the constructor (in which case it can only be used to initialise fields, not in the methods of the class), or you can specify that they are a field of the class, in which case the field gets generated for you. i hope to see something like this in the future
It is possible that C# will receive a few updates to this feature later, once it becomes clear how the programmers are using this feature. But I do agree that, this way, the feature looks half-baked.
Excellenrlr explaination. Channel subscribed. Hope I will learn new stuff.
There is one big problem I have with primary constructors.
There's no way to validate the arguments coming in the constructor. For declaring DTOs sure, but if that class will encapsulate anything, I need to avoid constructing invalid objects.
Besides we have records for DTOs. So yeah I don't think I'll be using this feature.
You have stumbled upon the critical element that so many programmers do not understand, and I will tell you the answer cold-turkey way.
There is no validation in an object.
Now, don't dismiss it lightly as so many others do, but start thinking about it, and, in due time, you will see what designers of C# and many other programmers, including me, see clearly. For a domain model to be valid, it must pass a construction process that depends on the scenario. Since the object itself cannot determine the scenario in which it is used, it is not entitled to perform validation either. If you wish to oppose this statement, then start thinking how exactly would each domain object you use in your code validates itself. I promise you will end up saying: It cannot.
@@zoran-horvat thank you for replying, Zoran, however I fail to understand what you're trying to say.
Sure domains can be complex and validity of domain objects can be situational, however most objects can benefit for certain sanity checks.
For instance if an argument received at construction is for example null and it is dereferenced in at least one flow implemented by the type, then surely it makes sense to validate it during construction and avoid instantiation in an invalid state.
Sure domain entities may not be aware of the context, but they don't need to be if they rely on certain things to be able to work.
Besides not implementing a validation on construction, will push the validation to all the clients of that type, and more code equals more errors
@@aivascu Trivial validations are fine and you can do that with primary constructors the same as you do with regular ones: just validate a value on assignment and it is done.
As I pointed out in the video, I don't see class parameters as variables one would use throughout the class body. Only use them in the assignment and you will stay safe.
@@zoran-horvat I see what you mean, but implementing something as trivial as checking if a string is null or empty requires throwing two different exceptions in two different control-flow statements, not to mention checking for length, format or boundaries. I guess it is technically doable using the new static functions offered by ArgumentException and something similar to Guards from .NET Community Toolkit or Dawn.Guard, but it sure is inconvenient, and much less readable.
I am still not convinced about how useful this constructors are, but thank you for the explanation.
Thanks for this golden video!
I think i dislike it because what if function parameter have the same name as the primary contructor parameters, i think there is a possibility to mess up too here in a lot of ways.
Would be fine with proper naming convention for primary constructor, like m_ for member, p_ param, here c_ could do the trick maybe.
@@WDGKuurama According to the common rules of C#, the function parameter is resolved first.
Naming the constructor parameters by common field naming is dubious because that naming is then visible to the caller.
@@zoran-horvat thanks!
So primary constructors are a tool for use in Functional Programming? If yes why not just teach functional programming and then use the functional tools in the language to demonstrate that? Instead it seems there's a push to get procedural programmers to use functional tools without understanding why or what purpose they serve leading to a lot of confusion. It reminds me of when c++ brought us Object Oriented Programming and most people just called it "C with classes". We are now in the "Procedural with functional bits" era.
That is the wrong view in my opinion because it acknowledges that programmers are lazy and uneducated. Why not put it this way: Expect programmers to learn programming. It is not that hard if you drop the common excuses that only paralyze your progress.
Your example with C++ is a good one. I have never heard anyone I worked with say that in ten years of my career as a C++ programmer, all until I started speaking in public. My point is that that is a blanket statement used to hide behind it and nothing else - a cheap excuse for not learning. That is the loser's wisdom.
@@zoran-horvatI think you've viewing my comment as an attack rather than an observation. What is the purpose of a primary constructor to a non functional programmer? None. It's just a way to write less code, but then they start doing weird and wrong things with the new shiny tool because they still think procedurally rather than functionally. They might write functional looking code (because it's more modern looking) but they are still thinking like they are stuck in the past. Perhaps instead of just adding functional bits to c#, they should have just tried to move people to F# and kept the cool stuff there.
@@auronedgevicks7739 I didn't see it as an attack. I am hearing that kind of thinking all the time.