The real power of learning comes from understanding the application of concepts. This is where Zoran's content truly stands apart. We get to witness how the features of C# work in harmony in a way that not many other content providers demonstrate. And yes, it can be brain-twisting sometimes, but the things worth learning usually are. Take it from me, watch these videos multiple times and play with the concepts and you'll get so much better. I can't praise this content enough.
You can be brain-twisted, oh! Just imagine the world of juniors coming to be the programmers much faster than old programmers are retired. They use linq but don't understand how and why you can pass a function as an argument to a function.
True. Functional programming assumes strong programming skills to begin with. I would never advise a beginner to try to dive into it, as that could lead to numerous misconceptions.
I’ve been exercising functional paradigms in my work projects. Separating behavior from data allows me to test behavior regardless of data and state changes makes testing predictable. I had to watch this video a few times to drill the concepts in my head!
Follow up on my comment from some months ago regarding your style of presenting. I think you nailed it. For me, you've found the perfect balance with tone variation etc. Very nice to listen to! About the contents of your video: Great as always! I love it!
Thanks! You will probably be happy to know that I am constantly reviewing my processes, from scripting, over recording, to editing, and that is in good part affected by the comments coming from people like you.
@@zoran-horvat I know ;).. That's why I wanted to follow up on my comment from some time ago. You're doing a very good job! I've been developing software for more than 25 years now, but it's always of great value to see how other developers think and incorporate some of their style into ones own.
It is the most interesting to me that the simple concept of passing functions to a function as parameters (which basically is what the demonstration is about) looks so complicated because of the language syntax. In fact, I got a grasp on the concept by learning a little of F# instead of starting to apply it in C#. The delegate definition trick to high complex function definition is neat, but first you need to really understand the concept of passing function to other functions (high order functions) As always, great explanation!
I think one important point of strong typing is is to prevent wrong assignments or wrong casts. Think about types you create to overcome positive obsession. Delegate behaves the same way as other type does. Therefore I don't think that this behavior, that strongly typed delegates cannot implicitly cast to other delegate types, will change in the future. I mean your example is a very good example. Think about it, you delegate has a name, a name that describes what the delegate does. Not consider you have a different delegate, with a different name, because it does a different thing. The computer prevents you from accidentally casting the wrong delegates to to the wrong purpose. Anyway, using .Invoke is a very good idea. I always used a lambs in this case. Never occurred to me, that I also could use Invoke.
I'm following the dark si..., just kidding, I am following the steady improvements of C# to make functional style programming in C# less verbose and align it more to the functional first langugage F#. From Language.Ext author Paul Louth to "Functional Programming in C# (@Manning)" of Enrico Buonanno to "Functional Programming with C# (@O'Reilly)" from Simon Painter, I am deeply grateful to Zoran for putting out his view on the application of the functional side of C#. I am eager to see where you are taking us.
I love your functional C# videos and your clear explanations Zoran; the issue I run into is that - as a freelancer - when I introduce these concepts/code in the projects I work on, it is very hard for colleagues to understand and/or review, let alone maintain it after I have left the project/company. So there is a definite pushback to write more OO-style C#. Have you run into this and if so, how did you handle these situations?
That is normal, since C# is an OO-first language. I think the best approach is to mix FP into an OO design. The principal step that every programmer must make is to adopt the immutable mindset. That is also the hardest step to make, so far as I can see.
the only problem i have with functional programming is that it is impossible to debug in the larger scale going line by line is way more helpfull in that case Writing readable and debuggable code should be the goal of all of us
This is precisely my issue with all of this as well. There is an iceberg and the few nice looking lines on the top are nice. But the rest of the code is extremely difficult to read and understand. If I had a huge legacy codebase and stumbled upon this during debugging, I would ask myself what the f were they thinking.
1. You don't understand why or how people do this thing, this is your "problem with functional programming". If you don't understand something you will obviously have a bunch of "problems" with that thing. 2. It is not "impossible to debug in larger scale" (I'm not even sure what you mean with "large scale" in this context, it is an empty statement), tell me exactly why do you think it is impossible to debug and give me a definition of "larger scale". 3. FP usually results in bugs and less coupling from the overhall system, so you will need to debug than without it. It is also harder to make bad untangled code (like the messy OOP legacy codebases you see here and there). This is a good tradeof most of the time.
@@diadetediotedio6918 I am precisely saying just that: it is my personal issue with it. You are really proving some stereotypes true about programmers who have a total lack of empathy or interpersonal skills. Code is primarily written to be read and maintained, not to be executed. Otherwise we'd be doing assembly.
@@lodevijk I'm sorry, there is a difference about having troube with something with that thing being objectively hard to grasp. And I think there are many misunderstandings in your coment. 1. That I somewhat "lack" empathy. I have plenty of that "empathy", I just don't find it productive to just consider a random subjective feeling as an argument against a very well and stablished way of programming. 2. Code is obviously primarily written to be , otherwise , this is literally the truth. Now, this do not mean that we should write code that is hard to read or maintain, this would surely go against our primary goal of executing software as intended (as working with code you don't understand lead to code that will not execute properly). 3. That because you find something hard, this means that thing is hard on itself. See, my problem with this is that it apply to virtually if you go far enough. Do you think a non programmer can find your well designed OOP code readable? No, that person will scream and want to die if left to maintain it, because you something to be able to that thing. The fact is that you
There is no pattern matching in the yellow box at 2:53. There are a collection expression with a spread element, and a `with`-expression. The Map function you have would better be called something else, like Match or Case which are a so-called recursor or an (non-dependent) eliminator, because usually the name Map is reserved in the functional programming context for lifting a function acting on the internals to a function acting on the external preserving the outside type, like the following `Map : (FullNameType -> FullNameType) -> (MononymType -> MononymType) -> (NameType -> NameType)`. One can generalize the `Apply` ext function to work with every `Func`. This way it will be universally useful and there will be no need to specify it again and again for each delegate type you want to add partial application to.
@@user-tk2jy8xr8b BTW the expression in the yellow box is a pattern matching expression. Don't be too religious about the use of 'match'. Try to see the bigger picture of matching patterns.
@@zoran-horvat a pattern-matching expression is literally an expression which matches some value to some pattern. In the aforementioned expression, which part is the pattern, which part is the value, and which part is the syntax that matches the value against the pattern?
@@user-tk2jy8xr8b When a chain of ternary expressions are used as a pattern matching expression, then the condition to the left of ? is the pattern and the whole expression evaluated to the right-hand expression. The final expression is evaluated in the catch-all pattern. The switch expressions are pattern matching expressions in C# by definition.mYou can transform every switch expression into a chain of ternary expressions. Therefore, the chain of ternary expressions that corresponds to some switch expression is the pattern matching expression by the same definition, too.
@@zoran-horvat the ternary operator is the recursor on the boolean type. Pattern-matching is a language feature that allows to examine value's structure by matching it to a pattern, i.e. to ask whether the value was constructed in some particular way, in a particular shape, specified by the pattern. `v is true` is a pattern-matching expression (special syntax to reason about the shape of data), `v == true` is not (it's an equality relation), `v ? t : f` is not (it's the recursor). All pattern-matching is eventually transformed into comparisons+conditional jumps (e.g. .NET) or indirect calls (e.g. Haskell) to be performed by the CPU, just as the ternary operator does, that doesn't mean the ternary operator has something to do with pattern matching.
That is easy. The with expressions cannot "freely do anything". It can only do what the containing function tells it to do. Isn't it the same with any mutable object? You can set its private state to whatever you want, but you would never emphasize that as an issue, right?
This was a really interesting video, and certainly a big eye opener. I was trying to do a lot of what is shown here with interfaces, but the delegate approach feels cleaner.
We have been told if we want to write performant C# to limit memory allocations as much as possible, reuse objects, and use preallocated memory buffers. On the other hand, in functional programming, objects (records) are thrown at the gabage collector by design. Perhaps .net is not the ideal environment for the function-oriented approach?
Garbage collection is a prerequisite for functional programming. I don't know who told you those things and what kind of software you are developing in the first place, but your observations do not apply to general programming. It could be true in games development or in embedded systems, but certainly not in general.
I want to learn how do fuctional programming in c#. How would you recoment doing this. Would you just try in c# or would it be better to learn a functional language and then return to c#.
In functional design, we acknowledge that functions belong to behavior modules that need them. Not all functions defined in one type belong together. Therefore, I could test your question with a question: Why would you?
That would mean you don't use strongly-typed delegates but only the Func delegates. The downside of that design is that arguments have no name, causing confusion in a complex model. Actually, the inability to assign strongly-typed delegates in an uncontrolled manner is a good thing. That adds type safety to functions and lambdas the same way classes add type safety to objects.
@@zoran-horvat Follow up question, I'm curious to know if there's a performance difference between a strongly typed delegate vs a Func. My guess is that it won't matter because the compiler will lower the Func to the "same" delegate type.
@@BrianHallmanac From what I know, there is no difference. There is, however, a performance penalty if you assign a Func delegate to a strongly typed delegate via a lambda. You should avoid that whenever possible, because the call then consists of two virtual calls instead of just one. There is one magnificent improvement there in Rust, where the compiler can sometimes - and quite often - figure that there is just one lambda ending up in a delegate. It then turns that lambda into a statically resolved function, ending the resolution at compile time! I believe .NET will try something similar, if not working on it already. I remember a very old paper which concluded that 1/3 of execution time of C++ programs of that time was spent on virtual function resolution. Joggling with virtual calls has always been the curse of OOP, but also its greatest strength.
I have 3 years of experience in coding all C# and I feel like a loser after watching these videos because idk if I'll be able to think like this in future ever. How you guys do it, please advise your junior fellow here
I think every programmer should learn at least one functional language along with learning the basic principles of functional programming. C# is adding more and more syntactic support for functional concepts, but they are of little use (or worse!) if those who use them do not know how to use it effectively.
Hello Zoran, I try to understand the concepts of Functional Programming via your videos. I often wonder, the model you use have only 2 properties. In reality a model would have several properties. If a model has 10+ properties, would working like this for each property be a good idea ?? What do you think ?
Actually, such models are frequent in object-oriented design, but not in functional. In functional design, we tend to group related concepts and represent them together, so a top-level type would consist of a few contained types, each consisting of a few other types, and so on. It is a true rarity to encounter a large type definition in a functional domain model.
@@zoran-horvat thanks for your prompt response. This clears to some extent. So, in OO design, for objects with fewer properties, we can implement functional design and use in other models? I am trying to implement small parts of Functional code in my OO code, but I find it difficult due to these concerns and give up.
@@zoran-horvat OO also has a steep learning curve with all the rules, anti patterns you have to be aware of. So I wouldn't say its complicated. Its just a different way of thinking. If universities would also teach functional concepts people would have an easier time adjusting.
Partial application of other functions is equivalent to dependency injection. Partial application of values is equivalent to creating a stateful object.
The real power of learning comes from understanding the application of concepts. This is where Zoran's content truly stands apart. We get to witness how the features of C# work in harmony in a way that not many other content providers demonstrate. And yes, it can be brain-twisting sometimes, but the things worth learning usually are. Take it from me, watch these videos multiple times and play with the concepts and you'll get so much better. I can't praise this content enough.
Thanks!
You can be brain-twisted, oh! Just imagine the world of juniors coming to be the programmers much faster than old programmers are retired. They use linq but don't understand how and why you can pass a function as an argument to a function.
True. Functional programming assumes strong programming skills to begin with. I would never advise a beginner to try to dive into it, as that could lead to numerous misconceptions.
@@zoran-horvat I don't know. I think this would have been easier to learn for me in the 1990s before my brain got object orientated.
I’ve been exercising functional paradigms in my work projects. Separating behavior from data allows me to test behavior regardless of data and state changes makes testing predictable. I had to watch this video a few times to drill the concepts in my head!
"let me twist your brain"
consider it twisted, but highely intrigued
Follow up on my comment from some months ago regarding your style of presenting.
I think you nailed it. For me, you've found the perfect balance with tone variation etc. Very nice to listen to!
About the contents of your video: Great as always!
I love it!
Thanks! You will probably be happy to know that I am constantly reviewing my processes, from scripting, over recording, to editing, and that is in good part affected by the comments coming from people like you.
@@zoran-horvat I know ;).. That's why I wanted to follow up on my comment from some time ago. You're doing a very good job!
I've been developing software for more than 25 years now, but it's always of great value to see how other developers think and incorporate some of their style into ones own.
It is the most interesting to me that the simple concept of passing functions to a function as parameters (which basically is what the demonstration is about) looks so complicated because of the language syntax. In fact, I got a grasp on the concept by learning a little of F# instead of starting to apply it in C#. The delegate definition trick to high complex function definition is neat, but first you need to really understand the concept of passing function to other functions (high order functions) As always, great explanation!
Another masterpiece, Zoran. An 'Apply' extension on a delegate... This is pure Zen...
Excellent! Just excellent! You sir deserve much more subscribers considering the quality of the content and educational value.
I think one important point of strong typing is is to prevent wrong assignments or wrong casts. Think about types you create to overcome positive obsession. Delegate behaves the same way as other type does. Therefore I don't think that this behavior, that strongly typed delegates cannot implicitly cast to other delegate types, will change in the future.
I mean your example is a very good example. Think about it, you delegate has a name, a name that describes what the delegate does. Not consider you have a different delegate, with a different name, because it does a different thing. The computer prevents you from accidentally casting the wrong delegates to to the wrong purpose.
Anyway, using .Invoke is a very good idea. I always used a lambs in this case. Never occurred to me, that I also could use Invoke.
I'm following the dark si..., just kidding, I am following the steady improvements of C# to make functional style programming in C# less verbose and align it more to the functional first langugage F#. From Language.Ext author Paul Louth to "Functional Programming in C# (@Manning)" of Enrico Buonanno to "Functional Programming with C# (@O'Reilly)" from Simon Painter, I am deeply grateful to Zoran for putting out his view on the application of the functional side of C#. I am eager to see where you are taking us.
A masterpiece video!
The power of closures and delegates. Nice one.
Fantastic video and teaching. Mind is truly bent. Look forward to more!
I love your functional C# videos and your clear explanations Zoran; the issue I run into is that - as a freelancer - when I introduce these concepts/code in the projects I work on, it is very hard for colleagues to understand and/or review, let alone maintain it after I have left the project/company. So there is a definite pushback to write more OO-style C#.
Have you run into this and if so, how did you handle these situations?
That is normal, since C# is an OO-first language. I think the best approach is to mix FP into an OO design. The principal step that every programmer must make is to adopt the immutable mindset. That is also the hardest step to make, so far as I can see.
"let me twist your brain". Too late Buddy. That call is way too late. :)
the only problem i have with functional programming
is that it is impossible to debug in the larger scale
going line by line is way more helpfull in that case
Writing readable and debuggable code should be the goal of all of us
This is precisely my issue with all of this as well. There is an iceberg and the few nice looking lines on the top are nice. But the rest of the code is extremely difficult to read and understand. If I had a huge legacy codebase and stumbled upon this during debugging, I would ask myself what the f were they thinking.
@@lodevijk
This is just your subjective perspective, it does not hold true because you feel like it.
1. You don't understand why or how people do this thing, this is your "problem with functional programming". If you don't understand something you will obviously have a bunch of "problems" with that thing.
2. It is not "impossible to debug in larger scale" (I'm not even sure what you mean with "large scale" in this context, it is an empty statement), tell me exactly why do you think it is impossible to debug and give me a definition of "larger scale".
3. FP usually results in bugs and less coupling from the overhall system, so you will need to debug than without it. It is also harder to make bad untangled code (like the messy OOP legacy codebases you see here and there). This is a good tradeof most of the time.
@@diadetediotedio6918 I am precisely saying just that: it is my personal issue with it. You are really proving some stereotypes true about programmers who have a total lack of empathy or interpersonal skills. Code is primarily written to be read and maintained, not to be executed. Otherwise we'd be doing assembly.
@@lodevijk
I'm sorry, there is a difference about having troube with something with that thing being objectively hard to grasp.
And I think there are many misunderstandings in your coment.
1. That I somewhat "lack" empathy. I have plenty of that "empathy", I just don't find it productive to just consider a random subjective feeling as an argument against a very well and stablished way of programming.
2. Code is obviously primarily written to be , otherwise , this is literally the truth. Now, this do not mean that we should write code that is hard to read or maintain, this would surely go against our primary goal of executing software as intended (as working with code you don't understand lead to code that will not execute properly).
3. That because you find something hard, this means that thing is hard on itself. See, my problem with this is that it apply to virtually if you go far enough. Do you think a non programmer can find your well designed OOP code readable? No, that person will scream and want to die if left to maintain it, because you something to be able to that thing. The fact is that you
What books do you recommend on category theory?
There is no pattern matching in the yellow box at 2:53. There are a collection expression with a spread element, and a `with`-expression.
The Map function you have would better be called something else, like Match or Case which are a so-called recursor or an (non-dependent) eliminator, because usually the name Map is reserved in the functional programming context for lifting a function acting on the internals to a function acting on the external preserving the outside type, like the following `Map : (FullNameType -> FullNameType) -> (MononymType -> MononymType) -> (NameType -> NameType)`.
One can generalize the `Apply` ext function to work with every `Func`. This way it will be universally useful and there will be no need to specify it again and again for each delegate type you want to add partial application to.
@@user-tk2jy8xr8b That actually doesn't work all too well in C#, due to lack of syntactic support.
@@user-tk2jy8xr8b BTW the expression in the yellow box is a pattern matching expression. Don't be too religious about the use of 'match'. Try to see the bigger picture of matching patterns.
@@zoran-horvat a pattern-matching expression is literally an expression which matches some value to some pattern. In the aforementioned expression, which part is the pattern, which part is the value, and which part is the syntax that matches the value against the pattern?
@@user-tk2jy8xr8b When a chain of ternary expressions are used as a pattern matching expression, then the condition to the left of ? is the pattern and the whole expression evaluated to the right-hand expression. The final expression is evaluated in the catch-all pattern.
The switch expressions are pattern matching expressions in C# by definition.mYou can transform every switch expression into a chain of ternary expressions. Therefore, the chain of ternary expressions that corresponds to some switch expression is the pattern matching expression by the same definition, too.
@@zoran-horvat the ternary operator is the recursor on the boolean type. Pattern-matching is a language feature that allows to examine value's structure by matching it to a pattern, i.e. to ask whether the value was constructed in some particular way, in a particular shape, specified by the pattern. `v is true` is a pattern-matching expression (special syntax to reason about the shape of data), `v == true` is not (it's an equality relation), `v ? t : f` is not (it's the recursor). All pattern-matching is eventually transformed into comparisons+conditional jumps (e.g. .NET) or indirect calls (e.g. Haskell) to be performed by the CPU, just as the ternary operator does, that doesn't mean the ternary operator has something to do with pattern matching.
OO (and DDD) has ingrained in me to protect invariants. How to prevent a invalid state transition when the `with` expression can freely do anything?
That is easy. The with expressions cannot "freely do anything". It can only do what the containing function tells it to do.
Isn't it the same with any mutable object? You can set its private state to whatever you want, but you would never emphasize that as an issue, right?
@@zoran-horvat That thought did cross my mind, but then those mistakes can only be in one place, the class itself.
This was a really interesting video, and certainly a big eye opener. I was trying to do a lot of what is shown here with interfaces, but the delegate approach feels cleaner.
We have been told if we want to write performant C# to limit memory allocations as much as possible, reuse objects, and use preallocated memory buffers. On the other hand, in functional programming, objects (records) are thrown at the gabage collector by design. Perhaps .net is not the ideal environment for the function-oriented approach?
Garbage collection is a prerequisite for functional programming. I don't know who told you those things and what kind of software you are developing in the first place, but your observations do not apply to general programming. It could be true in games development or in embedded systems, but certainly not in general.
I was really coding along and following but you just had to twist my brain 🤣🤣, I am taking a break now to unscramble my brain. See you in 5 mins!
@@kimfom You can't get away with watching this just once.
@@zoran-horvat thank you for creating these quality content. Your videos really expands my understanding
while i watched the video, there's a part where i was confused is he writing c# code or javascript code
i think i must read more from now on
I want to learn how do fuctional programming in c#. How would you recoment doing this.
Would you just try in c# or would it be better to learn a functional language and then return to c#.
I would recommend taking F# to learn FP.
hi zoran! im missing the point of this demo example here, why dont implement the add unique method inside the book record directly?
In functional design, we acknowledge that functions belong to behavior modules that need them. Not all functions defined in one type belong together.
Therefore, I could test your question with a question: Why would you?
Awesome video
could using aliases like below help with avoiding to call the 'Invoke' on the delegate object
using AuthorWithType = System.Func;
That would mean you don't use strongly-typed delegates but only the Func delegates. The downside of that design is that arguments have no name, causing confusion in a complex model.
Actually, the inability to assign strongly-typed delegates in an uncontrolled manner is a good thing. That adds type safety to functions and lambdas the same way classes add type safety to objects.
@@zoran-horvat Follow up question, I'm curious to know if there's a performance difference between a strongly typed delegate vs a Func. My guess is that it won't matter because the compiler will lower the Func to the "same" delegate type.
@@BrianHallmanac From what I know, there is no difference. There is, however, a performance penalty if you assign a Func delegate to a strongly typed delegate via a lambda. You should avoid that whenever possible, because the call then consists of two virtual calls instead of just one.
There is one magnificent improvement there in Rust, where the compiler can sometimes - and quite often - figure that there is just one lambda ending up in a delegate. It then turns that lambda into a statically resolved function, ending the resolution at compile time! I believe .NET will try something similar, if not working on it already.
I remember a very old paper which concluded that 1/3 of execution time of C++ programs of that time was spent on virtual function resolution. Joggling with virtual calls has always been the curse of OOP, but also its greatest strength.
Why a separate static class to create a booktype and not an extension method or a static method in the booktype?
That is a common practice - put creation logic in one place, put each batch of behavior into its own place, etc.
@@zoran-horvat 👍🏽👍🏽
I have 3 years of experience in coding all C# and I feel like a loser after watching these videos because idk if I'll be able to think like this in future ever. How you guys do it, please advise your junior fellow here
I think every programmer should learn at least one functional language along with learning the basic principles of functional programming. C# is adding more and more syntactic support for functional concepts, but they are of little use (or worse!) if those who use them do not know how to use it effectively.
15 years here ... i sort of understand how, but failing to understand why....
Hello Zoran,
I try to understand the concepts of Functional Programming via your videos. I often wonder, the model you use have only 2 properties. In reality a model would have several properties. If a model has 10+ properties, would working like this for each property be a good idea ?? What do you think ?
Actually, such models are frequent in object-oriented design, but not in functional. In functional design, we tend to group related concepts and represent them together, so a top-level type would consist of a few contained types, each consisting of a few other types, and so on. It is a true rarity to encounter a large type definition in a functional domain model.
@@zoran-horvat thanks for your prompt response. This clears to some extent. So, in OO design, for objects with fewer properties, we can implement functional design and use in other models? I am trying to implement small parts of Functional code in my OO code, but I find it difficult due to these concerns and give up.
Complicated yet interesting
Functional design has a steep learning curve, but eventually takes you further up than object-oriented design. The end result is very powerful.
@@zoran-horvat OO also has a steep learning curve with all the rules, anti patterns you have to be aware of. So I wouldn't say its complicated. Its just a different way of thinking. If universities would also teach functional concepts people would have an easier time adjusting.
After lisp,xslt now i have to learn f.p. in c#?
O tempora o mores.
I can easily find all implementations of an interface, then identify an offending implementation. Not so easy with delegates. How to fix that?
I am not sure what you mean. The compiler reports assignment errors to delegates the same way as with anything else in your code.
Partial aplication is equivalent to depency injection
Partial application of other functions is equivalent to dependency injection. Partial application of values is equivalent to creating a stateful object.
Ohh my poor OOP brain has been destroyed
🔥 🤯
In the 1700's you'd get burned for witchcraft coding with this black magic. I have to watch every functional video 3 or 4 times.