17 Pieces of C# Syntax That Make Your Code Short

  Рет қаралды 19,845

Zoran Horvat

Zoran Horvat

Күн бұрын

Become a sponsor to access source code ► / source-code-17-c-95476297
Join Discord server with topics on C# ► codinghelmet.com/go/discord
Enroll course Beginning Object-Oriented Programming with C# ► codinghelmet.com/go/beginning...
The syntax of the C# programming language is changing. It has been changing since version 1, and we are still witnessing the addition of more details to it. Have you ever considered why we are getting these pieces of syntax and not some other?
In this video, we will revisit a number of seemingly minor improvements added to the language over the years and draw them to a conclusion: Novel C# syntax makes writing pure functions easy.
It takes time to accept pure functions as a design tool and a lot of practice to make the most out of them. But one thing I promise to you: Once you get there, you will never look back to the old-school imperative coding.
And more: Your code will be way shorter than it used to be. How much shorter? 50-70% on average. That should motivate every programmer to start using the novel C# syntax as intended.
⚡️Chapters:
⌚ 00:00 Intro
⌚ 00:53 Imperative code (100% length)
⌚ 03:17 Object-oriented code (57% length)
⌚ 05:35 Comparing different styles
⌚ 06:45 Functional code (50% length)
⌚ 09:17 Pure functions (40% length)
⌚ 11:58 Conclusion
Thank you so much for watching! Please like, comment & share this video as it helps me a ton!! Don't forget to subscribe to my channel for more amazing videos and make sure to hit the bell icon to never miss any updates.🔥❤️
✅🔔 Become a patron ► / zoranhorvat
✅🔔 Subscribe ► / @zoran-horvat
⭐ Learn more from video courses:
Beginning Object-oriented Programming with C# ► codinghelmet.com/go/beginning...
⭐ Collections and Generics in C# ► codinghelmet.com/go/collectio...
⭐ Making Your C# Code More Object-oriented ► codinghelmet.com/go/making-yo...
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
⚡️ Have a look at our other Videos :
👉 Using GitHub Copilot to Write Complex Code | Step-by-step Tutorial ► • Using GitHub Copilot t...
👉 Coding with GitHub Copilot - Beginner to Master | VS Code Demo ► • A Comprehensive Guide ...
👉 What is Covariance and Contravariance in C# ► • What is Covariance and...
How to Initialize a Clean ASP.NET Core Project with Entity Framework Core and Identity ► • How to Initialize a Cl...
👉 The Null Conundrum: A Guide to Optional Objects in C# ► • How to Avoid Null Refe...
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
⭐ CONNECT WITH ME 📱👨
🌐Become a patron ► / zoranhorvat
🌐Buy me a Coffee ► ko-fi.com/zoranhorvat
🗳 Pluralsight Courses ► codinghelmet.com/go/pluralsight
📸 Udemy Courses ► codinghelmet.com/go/udemy
📸 Join me on Twitter ► / zoranh75
🌐 Read my Articles ► codinghelmet.com/articles
📸 Join me on LinkedIn ► / zoran-horvat
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
👨 About Me 👨
Hi, I’m Zoran, I have more than 20 years of experience as a software developer, architect, team lead, and more. I have been programming in C# since its inception in the early 2000s. Since 2017 I have started publishing professional video courses at Pluralsight and Udemy, and by this point, there are over 100 hours of the highest-quality videos you can watch on those platforms. On my KZfaq channel, you can find shorter video forms focused on clarifying practical issues in coding, design, and architecture of .NET applications.❤️
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
⚡️RIGHT NOTICE:
The Copyright Laws of the United States recognize a “fair use” of copyrighted content. Section 107 of the U.S. Copyright Act states: “Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by reproduction in copies or phono records or by any other means specified by that section, for purposes such as criticism, comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an infringement of copyright." This video and our KZfaq channel, in general, may contain certain copyrighted works that were not specifically authorized to be used by the copyright holder(s) but which we believe in good faith are protected by federal law and the Fair use doctrine for one or more of the reasons noted above.
#csharp #dotnet #functionalprogramming

Пікірлер: 240
@Eltin123456
@Eltin123456 5 ай бұрын
I would argue that code readability is far more important than reducing the code by 3, 5, or even 10 lines. Not to mention, that the code should be easy to debug. It seems like a challenge to make the code as short as possible which might be suitable for Codewars, but not for production code. So I would use "syntax improvement" that are really syntax improvements - that will show the intent and keep code readable and easy to debug.
@zoran-horvat
@zoran-horvat 5 ай бұрын
I agree, but then I would add that mapping expressions are also more readable than the imperative code. Let alone that they are reducing bug count by an order of magnitude.
@lordicemaniac
@lordicemaniac 5 ай бұрын
i agree, you are missing one point, the bonus way is also easily unit testable by very little and readable blocks
@anm3037
@anm3037 5 ай бұрын
Readability and shortness do not oppose each other. Short codes are each to capture at one gaze; hence improving readability.
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@lordicemaniac Expressions are easier to test than imperative blocks.
@lordicemaniac
@lordicemaniac 5 ай бұрын
@@zoran-horvat that is what i said, at least tried to... that the last bonus form maybe looks harder to read at first, but it is much easier to make very easy to read unit tests
@AlexUkrop
@AlexUkrop 5 ай бұрын
I adore all your lectures, including on Pluralsight. You have truly changed my programming style/vision/life and my code is 10x less buggy than it was 10 years ago! Zoran Guru of Functional Programming! IoC + Interfaces + Linq + SOLID + Functional Programming (no loops, no deep branches, no cyclomatic complexity, only Linq and self-described small methods) == Success. Thanks a lot!
@pixelguy2231
@pixelguy2231 5 ай бұрын
I like how your videos summarize most of the features from any C# versions, especially the new ones. I've seen the "when" keyword before, but never understood its use until now, same for using switches to declare variables.
@zoran-horvat
@zoran-horvat 5 ай бұрын
Designers of C# are constantly watching what kind of code people write. Most of the additions to the language stem from practical needs and their net result is shorter code, i.e. the language saves us from repeatedly writing the same idioms.
@pixelguy2231
@pixelguy2231 5 ай бұрын
@@zoran-horvat Interesting fact I see
@oysteinhaga
@oysteinhaga 5 ай бұрын
As he says; F# is even more readable (preferable?). Here is a variant: let tryParse (input:string) = match System.Int32.TryParse input with | true, v -> Some v | _ -> None let produceSum (input:int seq) = match input |> Seq.toList with | [max; next; _] -> max + next | _ -> - 1 let sumGreatestTwo (input:string seq)= input |> Seq.choose tryParse |> Seq.sortDescending |> produceSum
@zoran-horvat
@zoran-horvat 5 ай бұрын
That removes at least a half of keys required to type the same code.
@user-tk2jy8xr8b
@user-tk2jy8xr8b 26 күн бұрын
Exactly same can be written in C#, modulo syntax
@fisnikmaloku3425
@fisnikmaloku3425 5 ай бұрын
I watch your videos time to time, and I have to admit that each time I watch I appreciate more the content, because I understand the code and the use-cases where I would use these techniques. You're a great mentor, I've started learning from your videos in the beginning of my career, now I feel happy to have materialized that knowledge.
@luc9volts
@luc9volts 5 ай бұрын
I like a lot your channel and your functional approach. I've been trying to do my code like this for years
@HOSTRASOKYRA
@HOSTRASOKYRA 5 ай бұрын
Thanks! It was hard but very exciting!
@FunWithBits
@FunWithBits 16 күн бұрын
This is a great example on 20 years of C# evolution. I actually used to write the code at the beginning (.net 1.1 days) and it brings me back. I'm here because it's hard to "change" how we code and our brains need continues education to stay on top of things. Its not just the "features", its how we approached it. The first part brought back to the early days. The middle part is where I am now. The last part is were I strive to be.
@SudhanshuMishraTheOne
@SudhanshuMishraTheOne 3 күн бұрын
🤯in the best possible way! Hat tip to you sir 🙇, I’ll share your channel with my team. It is a goldmine!
@yufgyug3735
@yufgyug3735 5 ай бұрын
very interesting video, i myself try to use some more modern syntax of csharp, it is usually an iterative process, balancing human readability, syntax and performance
@VladimirRoytman
@VladimirRoytman 4 ай бұрын
Awesome techniques. Very educational. Thank you for your effort!
@dzllz
@dzllz 5 ай бұрын
Your videos are very educational. Keep up the good work!
@jonathanmccarthy3985
@jonathanmccarthy3985 5 ай бұрын
Zoran Im a active Patreon subscriber and your videos are always helpful!. To be honest your videos make me uncomfortable (in a good way). It pushes me to find my gaps and progress my abilities. Thank you!
@zoran-horvat
@zoran-horvat 5 ай бұрын
Thank you for your support!
@jeremychristman1515
@jeremychristman1515 5 ай бұрын
Your comment so perfectly describes how I feel also. I really value this mans content
@_IGORzysko
@_IGORzysko 2 ай бұрын
Great video Zoran! The last code presentation is not quite readable for me but I definitely would use functional programming due to its shortness and mutable resistance in general. 🤩
@jrandallsexton
@jrandallsexton Ай бұрын
Mind. Blown.
@ucretsiztakipci6612
@ucretsiztakipci6612 Ай бұрын
Excellent content. I'm deadly curios about the performance between them.
@RiversJ
@RiversJ 5 ай бұрын
I do the FP styled code most of the time in my daily work, including using method groups as delegates (especially so even). My personal style is to do a bit less in expression bodied methods as i find the fellow who didn't write it lay struggle to read it, also still haven't taken the time to use all the Linq methods i could. Though my past experiences affect that as i used to write code where an IEnumerable was an ungodly memory hog very easily and Linq methods could easily box in not just the obvious variable but half a function chain. Learning off the aversion where appropriate (even the C#12 Linq simply doesn't hold a candle to careful proc code on blazing paths, but those are slow to write without bugs)
@nickbarton3191
@nickbarton3191 5 ай бұрын
I can honestly say that I'm writing code with pattern matching et al. Just the last step with delegates and Linq to make. Awesome Zoran.
@christensencm
@christensencm 5 ай бұрын
The pure method is beautiful! I love the Aggregate method of boiling down an IEnumerable to a single output, it can be used for tons of use cases. My challenge is seeing the pattern. Moving from OOP to FP requires you look at the requirements from a different perspective. Sometimes, when I cannot see the FP solution right away, I will write it in OOP and then refactor until it is something elegant and pure. Thanks Zoran!
@soverain
@soverain 5 ай бұрын
I like the last example. I think the difficulty lies in the lack of understanding of the Aggregate method more than the code itself.
@zoran-horvat
@zoran-horvat 5 ай бұрын
That was exactly my point. Once you switch your mind to seeing expressions, you start feeling odd when faced with something that is not an expression.
@okcharles7
@okcharles7 5 ай бұрын
Aggregate ( TAccumulator seed ,
@daaa57150
@daaa57150 5 ай бұрын
I like the Aggregate method (i.e. "reduce" everywhere else) but I tend to not use it because let's face it, it's hard to read. And even if you master it, other devs reading your code will struggle.
@hemant-sathe
@hemant-sathe 5 ай бұрын
To be very pedantic, we used the aggregate function but didn’t count the lines of it. Nevertheless, great example for moving from traditional object oriented to functional. Is there a video on map-reduce concept (not just the LINQ functions) in C# already by you? If not please make one. I have always struggled to recall it as it’s not used everyday.
@victorcomposes
@victorcomposes 5 ай бұрын
Wow, just beatuiful, thank you.
@NightKnight252
@NightKnight252 15 күн бұрын
Thanks for showing me why F# is not more popular than many people hope it to be😆
@MasterKrzychuu
@MasterKrzychuu Ай бұрын
Nice, I forgot about Clamp but now I have the perfect idea where to use it in my code, thanks! Just saying, the way you've defined your Percentage class, it is still possible to initialize it with an invalid value: "var invalid = new Percentage(75) { Value = -12345 };". Change the init setter to private set to disallow this.
@zoran-horvat
@zoran-horvat Ай бұрын
Yes, that is the topic of other videos where I explain that issue.
@inzyster
@inzyster 5 ай бұрын
Since I have a habit of benchmarking competing solutions for the same problem before picking one, I benchmarked each approach from this video. I tested 1, 5, 10, 100 and 1000 input items, all random from range (-4096, 4096) - using a fixed seed number for consistency. The last two methods win on memory allocation, which was constant (40 bytes on my machine) - so they scale best in that regard. The third method wins on performance, while the last one was sometimes twice as slow (even slower than the first two). Note that I ran this on a potato (2009 Macbook running Linux Mint), so the results may be different on something less ancient, but I'd expect the relative numbers to be just the same. So I guess the moral of the story is: BenchmarkDotNet is your friend :)
@zoran-horvat
@zoran-horvat 5 ай бұрын
I plan to make a video on benchmarking, too. But you should be aware of the overall operation. Since each of the methods completes in microseconds, and data fetching that involves persistent storage would cost milliseconds, these methods are entirely irrelevant in the holistic performance analysis. Each variant is acceptable, so the decision is with maintainability, flexibility, and other -ilities that we need in software development.
@David-id6jw
@David-id6jw 5 ай бұрын
I did some benchmarking as well. I tested list sizes of 10, 100, 10_000, and 1_000_000. I generated a random set of numbers (same set each run, generated outside the benchmarks so won't influence the runtime or memory scores) and stored them in an array (so minimal overhead on enumeration). .NET 8. Ryzen 3700 CPU. BenchmarkDotNet v0.13.12 I think the most surprising was that MagicSum1 was slower than MagicSum0. These are basic syntactic sugar improvements, but MagicSum1 was ~5% (size 10 and 100) to 25% (size 10_000 and 1_000_000) slower than MagicSum0. Meanwhile, memory usage comparisons between MagicSum0 and MagicSum1 were a bit confusing. It varied between MagicSum1 using twice as much memory, to MagicSum0 using twice as much memory. Not sure why things varied like that. MagicSum2 and MagicSum3 were a vast improvement on memory allocation, using almost none regardless of data set size since they don't convert all the strings to a list of ints. However speedwise, MagicSum2 substantially outperformed MagicSum3. MagicSum3 was the slowest of all the algorithms for all data set sizes aside from 1_000_000, where it returned to being on par with MagicSum0. On the other hand, MagicSum2 was always the fastest, ranging from 10% to 20% faster than MagicSum0 (what I used as the baseline). For 1_000_000 data points, the difference between the worst (MagicSum1) and the best (MagicSum2) was 10 milliseconds (MagicSum2 being 35% faster than MagicSum1) and 13 MB of allocations. There was also a 5 millisecond difference between MagicSum2 and MagicSum3. I also tried making a variant which used MagicSum2 as a base, but using explicit if checks to see if the self-assignment of the default switch condition caused any additional performance overhead. The performance of the two variants was basically identical within the noise level, so the "syntactic sugar" penalty we saw going from MagicSum0 to MagicSum1 isn't hurting MagicSum2. Same when switching MagicSum3 to a generic variant. Overall, I'd say that MagicSum2 is the best for performance, memory, and readability. MagicSum3 is OK if you prioritize composability over the other metrics, and I think would also be preferable for generics (as long as performance isn't a major concern). So yes, go for modern code and pattern matching no matter what, but the step towards composed functional programming still needs additional thought based on your particular needs.
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@David-id6jw Thank you for this input. You have got the point that the greatest advantage of the GetMagicSum3 is composability, which is favored more than speed in functional designs. However, its speed primarily depends on how the patterns are selected. I did literally nothing to help the compiler and that is the native result of letting the compiler do it all for us. The principal reason why we don't try performance optimizations in FP first is that the data crunching code is way faster than I/O anyway. Any function that requires I/O before and/or after data processing will take as much time as I/O dictates, with or without optimization of its CPU-bound part.
@antonknieriemen8682
@antonknieriemen8682 5 ай бұрын
string[] nums= ["1","2","3","4","NAN","77","dude","23"] // modern syntax i prefer is 4 lines int sumlargest2 = nums.Select(x=>int.TryParse(x,out int i32)?i32:0) .OrderByDescending(i=>i) .Take(2) .Sum();
@zoran-horvat
@zoran-horvat 5 ай бұрын
That makes an assumption of a small sequence of strings. Since that assumption is not listed in the requirements, your solution is not acceptable under the current requirements.
@aalasso2
@aalasso2 Ай бұрын
I like this condensed abstracted format you have begun making where you iterate on a simple example. It really helps highlighting not just the "how" but the "why". My personal "why" has mostly been a feeling I have had for a few years, but that does not go far in persuading colleagues. Now, a few questions - some could be viewed as thinly cloaked critiques, but they are posed as questions since I might be missing something: 1) In your final iteration, your parameter is repeatedly named `tuple`. Referring to your comment at 3:33 ("name after purpose, not type"), surely this should be `state` (or similar), no? 2) In your switch expression, the second and fourth case differ only on `count` (`1`, `2`, respectively). Could they not be collapsed to a pattern matching on `(var max, _, 1 or 2)`? 3) Your l.50 at 4:22 seems to be sacrificing security for brevity: Dereferencing `all[0]` and `all[1]` three times looks like a bug magnet to me. I would prefer a preceding line with `var (first, second) = (all[0], all[1])`, would you agree? Might there be a way to inline it, so as to get both brevity and security? 4) While using pattern matching switch expression, I find it easy to get lost in the details because the patterns themselves cannot be abstracted away and given names. Surely switch patterns can be used in both "good" and "bad" ways. I would love to see this addressed in a future video.
@zoran-horvat
@zoran-horvat Ай бұрын
I agree with your comments. There will be some videos about the switch expressions and pattern patching expressions.
@friedcrumpets
@friedcrumpets 5 ай бұрын
I really enjoyed this video. It's a great overview of modern programming and oddly enough I'm currently looking into functional programming to see if I can snatch paradigms and bring them over to C#. My main question as a game developer... do I need to be concerned for performance employing such a style of programming?
@zoran-horvat
@zoran-horvat 5 ай бұрын
Game development has a large part that is performance critical, both in terms of CPU-bound operations and garbage collection. In that respect, most of the advice I gave in this video (and most other videos on my channel) is not good advice for game developers. On the other hand, all the techniques I show are tried and tested in business applications and services, where you can truly cut your codebase in half.
@soverain
@soverain 5 ай бұрын
As a unity developer myself, I can assure you that you can effectively use some form of functional programming in game development. Sure making everything immutable and creating copies everywhere is not a good idea when we are working with large objects, but using pure functions in the underlying logic is largely feasible.
@Bankoru
@Bankoru 5 ай бұрын
I use Option monads and Linq all the time in Unity. It is not a concern unless the profiler tells you so. Most of the time performance issues are in asset memory allocations (uncompressed textures etc)and loading said assets. Async functional code and Profiler are your friends.
@friedcrumpets
@friedcrumpets 5 ай бұрын
@@Bankoru I've just had a google of Option Monads; something I've seen explained by here before and used before without realising. Thanks for the responses on this, actually really helpful 👍
@1Eagler
@1Eagler 5 ай бұрын
It reminds me the old days of C. When you open a .h file, y will see one line with 120 characters ( in 80x25) and wonder what it does and how. Sorry, im too old for these: if I need more than 10" to understand a part of a code, this code needs either a comment or refactor it.
@zoran-horvat
@zoran-horvat 5 ай бұрын
Thirty years ago t'was an' it ain't no C these years no more.
@1Eagler
@1Eagler 5 ай бұрын
@@zoran-horvat '87
@1992jamo
@1992jamo 4 ай бұрын
I have actually come back to this video, and honestly I it's incredible just how many fewer memory allocations there are with the functional approach. I ended up settling with this implementation which uses the same memory usage, but is easier for me to read. public static int SumOfTwoLargest(IEnumerable items) { var result = items .Select(item => { int.TryParse(item, out int number); return number; }) .Aggregate((max: 0, next: 0, count: 0), (acc, number) => acc.count switch { 0 => (number, acc.next, 1), 1 => number > acc.max ? (number, acc.max, 2) : (acc.max, number, 2), 2 when number > acc.max => (number, acc.next, acc.count), 2 when number > acc.next => (acc.max, number, acc.count), _ => acc }); return result.count == 2 ? result.max + result.next : -1; }
@logantcooper6
@logantcooper6 5 ай бұрын
Great content
@coderider3022
@coderider3022 2 ай бұрын
Late 20th century code - I’m going to borrow that line ! Problem is we get taught to do that then when we get a job, it’s hard to unlearn this.
@zoran-horvat
@zoran-horvat 2 ай бұрын
I know. I've been there, I've done that - for a decade at least. The good thing is that all this I am teaching exists in books. That is how I found about the problem through my career and then gradually improved.
@vivekkaushik9508
@vivekkaushik9508 5 ай бұрын
Brilliant.
@kostasgkoutis8534
@kostasgkoutis8534 5 ай бұрын
Pretty solid code, i can tell that folding through the use of an FSM is kind of a pattern for you.
@patfre
@patfre 5 ай бұрын
In the object oriented example you could reduce the curly braces to 0 if you remove the braces on the for each loops since c# counts the code in both of them as a single line so it is valid. And you also save some lines
@zoran-horvat
@zoran-horvat 5 ай бұрын
In a traditional code formatting style, that is usually considered an extreme and dangerous practice. I have nothing against it, personally.
@patfre
@patfre 5 ай бұрын
@@zoran-horvat I also have nothing against it personally because of the fact that it’s in the way I format my code makes it easier for me personally to see what it does but I am also against it in certain cases like if else statements I wouldn’t do it but if it was just a single if statement I usually do it to make it simpler. I do also understand that it may not be the best I understand both sides here
@okcharles7
@okcharles7 5 ай бұрын
Happy new year!! Now, I can be free to use "when" clause in switch expression body and many thanks for great tutorial. Btw, it seems the seed values for the max and the next in functional variations should be int.MinValue instead of 0.
@zoran-horvat
@zoran-horvat 5 ай бұрын
No need for int.MinValue because there is count set to 0 to invalidate both values initially.
@okcharles7
@okcharles7 5 ай бұрын
@@zoran-horvat you are right. Actually, what I thought was, those initial values could have made the switch case shorter, for example of Pure version: (var m, _, var c) when num > m => (num, m, c+1), (var m, var n, var c) when num > n => (m, num, c+1), _ => tuple with { count = tuple.count + 1 }, However, after your reply, I found this rule could be applied to all the cases and your intention was to apply the same logic for all.
@SirBenJamin_
@SirBenJamin_ 5 ай бұрын
My worry with C# having so many different ways to do things in the same language is that when you have a shared code base with lots of different people, there will be lots of different "flavours" or styles and implementation techniques using different styles of the language ... i.e its going to encourage inconsistency. But then on the flip side, it makes the language so powerful and means it can be used in more places. So yes, I'm not entirely sure how I feel about the current direction of C#.
@zoran-horvat
@zoran-horvat 5 ай бұрын
It is common nowadays to split large domains into smaller components - services, vertical slices, all sorts of them. I don't expect different styles to flourish within a single component if it is small enough.
@AndersBaumann
@AndersBaumann 5 ай бұрын
Hi Zoran. How to find a bug in the middle of a long, chained LINQ expression? Do you use the QuickWatch window or do you use another technique?
@zoran-horvat
@zoran-horvat 5 ай бұрын
Why would you make a long, chained LINQ expression? If there are many operations to chain, I would expect to see them split into logical sections. If an operation makes a complex transform, I would expect to see that transform pulled out into a separate method or a function. The rules of managing complexity in LINQ are the same as in any other portion of code - don't let the code grow beyond a limit you can manage.
@dwhxyz
@dwhxyz 5 ай бұрын
Another great video from Zoran! I do wonder if Microsoft are having ideas of merging C# and F# into a single language one day.
@zoran-horvat
@zoran-horvat 5 ай бұрын
I suppose not. Those are two views on software design.
@dwhxyz
@dwhxyz 5 ай бұрын
​@@zoran-horvat They are but with the rise in popularity of functional style programming along with what has been added to C# over the years has made me think there could be plans for this one day or to phase one of them out. I'm thinking quite some time in the future - 10+ years.
@johnsuckher3037
@johnsuckher3037 5 ай бұрын
if I saw the last approach in a PR I would nope out
@zoran-horvat
@zoran-horvat 5 ай бұрын
So, your mind is not there yet. That is not a problem - keep learning.
@adambickford8720
@adambickford8720 5 ай бұрын
@@zoran-horvat i do understand it... and i'd still reject it. Not because its bad code, but because i'd be the only one on the team that could maintain it, present or future.
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@adambickford8720 I was leading one such team and I have invested a lot in explaining this programming method. One of the members came to me a couple of years later to tell me that the team is still doing it that way, and that they would never trade it for their prior practices. I have never accepted the lack of education among the programmers I worked with. It is fine to not know something - there are tons of technologies I encounter daily and I don't know them. Not knowing is normal. But it is absolutely unacceptable to stick to sub par designs and refuse to learn better. I have done it through my career as a developer, as a team lead, and as a CTO - and it worked every time. But learning must be demanded explicitly. I never left it as an opt-in choice to my colleagues.
@adambickford8720
@adambickford8720 5 ай бұрын
@@zoran-horvat we have had very different experiences! My employers have *actively resisted* that kind of solution because it requires 'rock star' devs and has too much risk. They can't afford "ivory tower" solutions that require additional ramp up time educating a team. They want the most fungible cogs possible as they expect the code to far outlive the team. That kind of code becomes some esoteric thing written by the greybeards of yesteryear nobody dares touch. TBC, it's incredibly frustrating to me the answer is to dumb down the solution instead of leveling up the devs. But the reality is I have to fight tooth-and-nail just to get people to use a 'reduce' properly. And when they report 'the PR works, but it's a hack' the boss will choose 'done right now' over 'done right' every time.
@lee1davis1
@lee1davis1 5 ай бұрын
Our brains must be programed to think this way through repetition.
@zoran-horvat
@zoran-horvat 5 ай бұрын
Precisely. I haven't met a programmer who didn't understand this process. But I have heard numerous team leads who say their team members cannot understand it. Those leads believe their colleagues are incompetent.
@avaygc5646
@avaygc5646 5 ай бұрын
Can u make video about reflection and attributes im confused in that one
@Lazzerman42
@Lazzerman42 5 ай бұрын
Impressive coding skills. Still, I would not recommend using that kind of advanced c# in an Enterprise project. Simply because all teams members won't have the same skillset - this type of code will be a paria that only one or two developers will dare touching. After 5 years it will be known as the code with technical debt. IMHO, writing the shortest/smartest code is something you do when you have a small dedicated team. In an Enterprise, writing easy to read code is king for long levity.
@zoran-horvat
@zoran-horvat 5 ай бұрын
I am trying to communicate the opinion that code based on expressions, pattern matching, and value mapping is also the simplest and easiest to understand. I have done that in my teams and, once you put things that way, members on the team accept it. You should not fear giving your colleagues an opportunity to learn.
@Lazzerman42
@Lazzerman42 5 ай бұрын
@@zoran-horvat In my experience - things that are truly good, will be simplified by time. In other words, pattern matching syntax and functional program seems immature - but will probably mature and get better tooling support and "better" syntax if they bring business value. Happy new year!
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@Lazzerman42 I am sure these constructs will be even simpler in the future.
@Bankoru
@Bankoru 5 ай бұрын
I love it, but my tech lead hates I even use expression bodied methods.
@zoran-horvat
@zoran-horvat 5 ай бұрын
I know of cases like that...
@muhammadumair9074
@muhammadumair9074 4 ай бұрын
You discuss separate domain from infrastructure. My question is what are other names/concepts of infrastructure.
@TreeLuvBurdpu
@TreeLuvBurdpu 5 ай бұрын
F# is a lot of fun.
@RicusNortje
@RicusNortje 5 ай бұрын
I would love to see the performance for each method, for example the enumerator will add overhead when lowered to IL.
@zoran-horvat
@zoran-horvat 5 ай бұрын
There is an analysis in the comments. Contrary to what many opponents of modern C#, it turns out that the two functional variants are the fastest. I expected that because I have seen it so many times already.
@sideshowfrost
@sideshowfrost 5 ай бұрын
Hey, I had the same thought so tested it, and wrote about it here: blog.onelivesleft.com/2024/01/modern-c-performance-in-brief.html
@varagor23
@varagor23 5 ай бұрын
How good is the last "ulatimate" solution in terms of performance compared to the procedural approach? I see a lot of function calls there.
@zoran-horvat
@zoran-horvat 5 ай бұрын
It is the job of a compiler, especially the JIT compiler, to inline those calls. You should train your eyes to view code through transforms and not through CPU instructions, mostly because anything you imagine will execute on a CPU is probably not true. It is indicative that either approach would accumulate to no more than 0.1% of execution time if execution includes loading the data from persistent storage, and to way under 0.05% of time if producing the response would include network transfer to a distant location. In other words, execution time is irrelevant. Development time, extensibility and bug count are the primary concerns for an engineer.
@theramblingbrit4431
@theramblingbrit4431 4 ай бұрын
I was curious too, so ran some Benchmarks. In terms of performance, both "functional style" versions perform better than the more procedural styles. The "Functional" version seemsto consistently perform the best out of the 4, and personally seems the more universally readable of the two functional styles to me, so I'd go with that style personally. They also don't require any allocations unlike the more procedural versions, which tends to be the more common limitation I've come across. | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | |--------------------- |-------- |------------------:|------:|----------:|------------:| | ProceduralMethod | 0 | 2.560 ns | 1.00 | 32 B | 1.00 | | ObjectOrientedMethod | 0 | 2.613 ns | 1.02 | 32 B | 1.00 | | FunctionalMethod | 0 | 1.275 ns | 0.50 | - | 0.00 | | PureMethod | 0 | 12.430 ns | 4.86 | 128 B | 4.00 | | | | | | | | | ProceduralMethod | 1 | 20.769 ns | 1.00 | 112 B | 1.00 | | ObjectOrientedMethod | 1 | 20.779 ns | 1.00 | 112 B | 1.00 | | FunctionalMethod | 1 | 13.387 ns | 0.64 | 40 B | 0.36 | | PureMethod | 1 | 25.185 ns | 1.21 | 168 B | 1.50 | | | | | | | | | ProceduralMethod | 10 | 128.382 ns | 1.00 | 288 B | 1.00 | | ObjectOrientedMethod | 10 | 137.218 ns | 1.07 | 304 B | 1.06 | | FunctionalMethod | 10 | 95.041 ns | 0.74 | 40 B | 0.14 | | PureMethod | 10 | 126.616 ns | 0.99 | 168 B | 0.58 | | | | | | | | | ProceduralMethod | 100 | 1,056.616 ns | 1.00 | 1256 B | 1.00 | | ObjectOrientedMethod | 100 | 1,121.603 ns | 1.06 | 1272 B | 1.01 | | FunctionalMethod | 100 | 903.564 ns | 0.86 | 40 B | 0.03 | | PureMethod | 100 | 1,040.499 ns | 0.98 | 168 B | 0.13 | | | | | | | | | ProceduralMethod | 1000 | 10,481.245 ns | 1.00 | 8496 B | 1.000 | | ObjectOrientedMethod | 1000 | 12,829.850 ns | 1.22 | 8512 B | 1.002 | | FunctionalMethod | 1000 | 10,251.213 ns | 0.98 | 40 B | 0.005 | | PureMethod | 1000 | 11,721.219 ns | 1.12 | 168 B | 0.020 | | | | | | | | | ProceduralMethod | 100000 | 1,378,139.537 ns | 1.00 | 1049162 B | 1.000 | | ObjectOrientedMethod | 100000 | 1,639,344.766 ns | 1.19 | 1049132 B | 1.000 | | FunctionalMethod | 100000 | 1,212,847.956 ns | 0.88 | 41 B | 0.000 | | PureMethod | 100000 | 1,321,638.203 ns | 0.96 | 169 B | 0.000 | | | | | | | | | ProceduralMethod | 1000000 | 17,178,708.152 ns | 1.00 | 8389238 B | 1.000 | | ObjectOrientedMethod | 1000000 | 19,084,339.955 ns | 1.11 | 8389254 B | 1.000 | | FunctionalMethod | 1000000 | 12,412,192.083 ns | 0.72 | 46 B | 0.000 | | PureMethod | 1000000 | 13,565,147.292 ns | 0.79 | 174 B | 0.000 |
@chrisspire
@chrisspire 4 ай бұрын
The Discord link is broken - is Discord available for everyone? I love you content. Took me a long time to find someone with conceptual understanding and broad vision even though I am beginner at C#. There are a lot of simple solutions on TY but no one give answers to "why that desing? why that solution?". Big thanks!
@zoran-horvat
@zoran-horvat 4 ай бұрын
Try now. I have replaced the link with a redirect link that should always be up to date.
@chrisspire
@chrisspire 4 ай бұрын
@@zoran-horvat All good now. Thanks!
@antonknieriemen8682
@antonknieriemen8682 5 ай бұрын
one line int sumlargest2 = nums.Select(x=>int.TryParse(x,out int i32)?i32:0).OrderByDescending(i=>i).Take(2).Sum();
@zoran-horvat
@zoran-horvat 5 ай бұрын
That algorithm requires O(N logN)) time and O(N) space. You cannot assume that is allowed unless requirements clearly state it is, e.g. by giving an acceptable upper bound for N. The solution from the video makes no such assumptions. It produces the result in O(N) time and O(1) memory.
@user-tk2jy8xr8b
@user-tk2jy8xr8b 26 күн бұрын
Almost, but it behaves incorrectly with non-numeric input mixed with negative numbers and doesn't return -1 if there are no two biggest
@DanielOliveira-hd9uc
@DanielOliveira-hd9uc 5 ай бұрын
Nice approaches but, how about performance between each approach, which is better?
@zoran-horvat
@zoran-horvat 5 ай бұрын
What is performance when the data is loaded from storage, transformed, and then sent over the Internet? Whatever you write, and whichever coding style you adopt, the time your code takes will never approach one percent of the request-response time.
@conbag5736
@conbag5736 5 ай бұрын
@@zoran-horvat While this is true, if you concede that this approach may not be suitable for something like Game development, and if you are advocating that people should adopt a more functional approach to their C# development - I think spending a minute or so being transparent about the performance of each approach would be welcome, even if it's negligible in 95% of use-cases.
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@conbag5736 The primary target of C# are business applications. Game development, system applications, embedded systems, operating system - you can do most of that in dotnet, but you should know on your own what tradeoffs each includes and how it differs from mainstream programming.
@Bankoru
@Bankoru 5 ай бұрын
I ran a benchmark for the OOP, Functional and Pure cases. Surprisingly, functional had the best performance, followed by Pure (~18% slower), then OOP(~26% slower). In terms of memory allocation, OOP is surprisingly high (almost x1000 higher than functional in the 10000 strings case). I wish I could just post the table here. I find the pure case more interesting, but certainly less readable. Overall I'd stick to functional in this particular case (better performance/readability/memory) despite it not even using Linq (and it is faster specifically because it doesn't, although performance difference is negligible).
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@Bankoru The first two solutions collect the data into the list, and the last two don't - that is the difference in memory. Regarding CPU, I am not surprised to see the last two solutions coping well because all four solutions execute the same arithmetic operations in the same order, with only minor differences caused by the compiler optimizing them differently. Therefore, under the line, all that counts is the code structure on the screen, and that is where we can benefit the most from more expressive forms - functional design and expressions.
@luc9volts
@luc9volts 5 ай бұрын
Awesome
@AlFasGD
@AlFasGD 5 ай бұрын
The primary mistake here is measuring by LoC, which you very well reduce by including both the if statement and the code statement if the same line, which would otherwise be 2 or more lines. This greatly hinders readability, much like how the more "advanced" methods do. The point is not to write clever and short code, but readable and fast enough for your use case. The only thing I can commend for in this video is the showcase of C# features that everyone writing C# should definitely know. But returning magic tuples instead of declaring record structs for them comes against the point of the video, which is showing advanced C# features that people should be using in their code.
@zoran-horvat
@zoran-horvat 5 ай бұрын
I believe my point should have been made from the other end, though I'm not sure if I could communicate it well to the audience: _if_ you choose to design behavior in functional style, rather than object-oriented or procedural, _then_ you will have the novel syntax at your disposal and _that_ will help make your code shorter by a factor of two.
@MrFalcon58199
@MrFalcon58199 5 ай бұрын
I like using these tricks to shorten my code, but I've noticed that sometimes it has a tendency to make the code less readable, so I try to balance those things
@zoran-horvat
@zoran-horvat 5 ай бұрын
Actually, the game is to train your eyes to see expressions, rather than statements. Once you get over that, you will start reading mappings and expressions fluently, and it will be imperative constructs and block statements that will hurt readability.
@JaconSamsta
@JaconSamsta 5 ай бұрын
@@zoran-horvat Yes! In the end, it's all about conventions. One could easily argue that a for loop makes looping more difficult to understand, because all of the looping logic is contained in one piece of syntax and you need convention around how to interpret the syntax for it to be unambiguous. I for one am very happy to see more and more functional "conventions" make it into languages like C#. Yes, they may seem foreign at first and it takes time to integrate them into your own vocabulary, but they bring so much additional expressivity in the way they convey intent, it's almost crazy to think that I ever coded without them!
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@JaconSamsta Same with me, and my colleagues testify in the same spirit. Once you get there, you only turn back when there is justification: an express request for performance, an in-place algorithm, multipass algorithm, etc.
@allinvanguard
@allinvanguard 5 ай бұрын
While code readability is an important aspect (Prefer understandable over clever code) - All those syntactical improvements are exactly why modern C# feels so much better than Java. Java is still almost stuck in the imperative phase, while we have a vast array of choices to pick from.
@PetrVejchoda
@PetrVejchoda 3 ай бұрын
The fact that I can, doesn't mean I should.
@Luke-me9qe
@Luke-me9qe 5 ай бұрын
I would have thought you will put the tuples into using aliases. And I'm sure there is a reason why. Would you care to elaborate? Thx
@zoran-horvat
@zoran-horvat 5 ай бұрын
Actually, I was thinking about doing that but eventually dropped the idea. Maybe I could play a bit with that in a separate video.
@Eva-km5ng
@Eva-km5ng 16 күн бұрын
I love Haskell, I love Clojure, but the functional version of that code is unreadable. Way too clever. I would stick to the 2nd version, especially if I'm cursed to use C#. It doesn't really make sense to use the fanciest functional patterns in C# since the reason you're using C# instead of F# is most likely because your team doesn't want to learn functional programming. The last "best" way is the sort of code that convinces them that functional programming is too hard and not practical.
@robypeng
@robypeng 5 ай бұрын
Hi @zoran-horvat, I'm one of many developers out there that are still struggling to understand and shift our comprehension and perspective into a functional paradigm. I'm also not the brightest one I would say. So my question is, how can we improve ourselves, make it familiar, and to get better in this topic?
@zoran-horvat
@zoran-horvat 5 ай бұрын
Read everything you can grab. Learn every day. I have been doing that for the last 20 years and that has become my way of life ever since.
@nickbarton3191
@nickbarton3191 5 ай бұрын
Typed this code out and traced it in debug. Double awesome ! About readability, is it possible to use an alias for the tuple ? The tuple structure is repeated half a dozen times and makes it look busy. I tried an alias but couldn't make it compile, needs C# 12. I converted to a struct using ReSharper and made it immutable but it needs a constructor, deconstruct; just ugly.
@zoran-horvat
@zoran-horvat 5 ай бұрын
I feared you would come with a bug report. I never ran that code while I was working on it :) All I know about its correctness comes from my trust in the development method I applied.
@nickbarton3191
@nickbarton3191 5 ай бұрын
@@zoran-horvat It works great, even with a list of 1 or 0 items and also negative numbers. I'm just saying it's a little verbose with the repetition of the tuple.
@nickbarton3191
@nickbarton3191 5 ай бұрын
Actually, I rewrote it using a SortedSet of the largest numbers instead of a tuple with another aggregate to sum them. IMHO, it's simpler and can be parameterized for how many max values to sum. Same line count. But I appreciate the demo of C# features, for me it's having the wisdom and experience to know how and where to use them instead of procedural style. I wonder also about performance, are there pitfalls to avoid? I need to prototype more before changing production code. Time is the enemy! In theory, I'm not allowed at the laptop in weekends 🙃
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@nickbarton3191 SortedSet removes duplicates. If you wanted to go that way, the SortedList is the right collection to use.
@nickbarton3191
@nickbarton3191 5 ай бұрын
@@zoran-horvat Quite right, depends on the exact requirement I suppose but I didn't think about it.
@billy65bob
@billy65bob 5 ай бұрын
I think I would've clumsily reduced it to about 6 Linq statements. Something like: var result = items .Select(n => int.TryParse(n, out var val) ? (int?)val : null) .Where(n => n.HasValue) .OrderByDescending() .Take(2) .ToArray(); return result.Length == 2 ? result.Sum() : -1;
@spacepigs
@spacepigs 5 ай бұрын
You should use .OrderDescending() and result.Sum()!.Value for the code to compile - it's probably the most concise functional solution. There's at least this interesting but rarely discussed factoid that C# automatically lifts operators to nullable which is why this approach works in the first place.
@zoran-horvat
@zoran-horvat 5 ай бұрын
That takes O(N logN) time and O(N) space for an unknown N. Only if requirements guaranteed that N is small could we try this condensed approach. The requirements from the video are open to the possibility of working with extremely large inputs, and so I have implemented an O(N) time and O(1) space algorithm.
@mdev3987
@mdev3987 5 ай бұрын
Even though I follow the changes carefully I am getting a little bit worried about the direction of the language. Even though this is readable, and we implement somewhat a single responsibility principle, I would argue that the simplicity is getting lost in the syntax. But that’s just me.
@zumalifeguard3493
@zumalifeguard3493 5 ай бұрын
Instead of a tuple, I would have used a locally defined immutable record. The tuple requires the definition to appear multiple times, increasing cognitive overhead unnecessarily.
@zoran-horvat
@zoran-horvat 5 ай бұрын
In many places in code it is not a tuple but an assignment to several variables. On the other hand, stepping from ValueTuple to a record class may require careful consideration of performance, especially if it is instantiated many times in a loop.
@zumalifeguard3493
@zumalifeguard3493 5 ай бұрын
Good point with regard to performance.
@Katniss218
@Katniss218 3 күн бұрын
13/18 is 72%, not 57%
@zoran-horvat
@zoran-horvat 3 күн бұрын
17/30 = 57% Just because 40% of vertical space are curly braces does not allow you to pretend they are not there. The 18 vs. 30 measure shows how effective that coding style is. It shows that 40% of vertical space is wasted with no effect on what the code is doing.
@ClickOkYT
@ClickOkYT 5 ай бұрын
Wow
@rauberhotzenplotz7722
@rauberhotzenplotz7722 5 ай бұрын
What about this approach? int SumOfLargestTwo(IEnumerable source) => source.Aggregate( (default(int?), default(int?)), (current, next) => current switch { (var x, var y) when x is null || next > x => (next, y), (var x, var y) when y is null || next > y => (x, next), _ => current }, r => (r.Item1 + r.Item2) ?? -1); // ((x,y)) => (x+y) ?? -1 in the future
@az6876
@az6876 5 ай бұрын
Brilliant implementation! Can I give constructive criticism? Instead of using Aggregate, isn't the classic foreach loop better in terms of performance and readibility code? Something like this code: int MySumMethod(IEnumerable items) { (int max, int next, int count) tuple = (0, 0, 0); foreach (var item in items) { if (int.TryParse(item, out int number)) { tuple = tuple switch { (_, _, 0) => (number, 0, 1), (var max, _, 1) when number > max => (number, max, 2), (var max, _, 1) => (max, number, 2), (var max, _, 2) when number > max => (number, max, 2), (var max, var next, 2) when number > next => (max, number, 2), _ => tuple }; } } return tuple.count == 2 ? tuple.max + tuple.next : -1; } What do you think? Thank you
@zoran-horvat
@zoran-horvat 5 ай бұрын
Once you see why Aggregate is better, you will never look back. Here is what makes it better: it _forces_ you to have an explicit transform. Without it, there is no barrier to stop your codebase from becoming 100% procedural, losing every single benefit you could get from having explicit small, composable transforms.
@az6876
@az6876 5 ай бұрын
Hi @@zoran-horvat thanks for your reply. My criticism of the procedural whole is based not on the goodness of the code, which I do not discuss (on the contrary, I like it very much as in your implementation), but on the performance (and in my job I have to control that). If I do a trivial benchmark test between the Aggregate and foreach mode I proposed, I get these results: | Method | Mean | Error | StdDev | Gen0 | Allocated | |------------- |---------:|--------:|--------:|-------:|----------:| | GetMagicSum3 | 253.7 ns | 4.79 ns | 4.48 ns | 0.0253 | 40 B | | MySumMethod | 129.9 ns | 1.63 ns | 1.36 ns | 0.0253 | 40 B | This is one of the problems with this approach: apart from the readability of the code, which can be confusing for the inexperienced, the performance is often inferior (very high number of jumps, stack, etc...) and this is what still stops me in the all-procedural approach. At the moment I prefer a 'mixed' approach.
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@az6876 You are discussing 0.1 microsecond where even the simplest database query or file request that would feed the data in takes at least 1ms. There is no point in optimizing one 10,000th part of execution time.
@az6876
@az6876 5 ай бұрын
​@@zoran-horvat no, it's not 1ms, but 40% less time. In a realtime context it makes a lot of difference.
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@az6876 LINQ is not made for realtime applications, nor is C# for that matter, not even foreach. And, obviously, it is not 40% - for actual percentage, you must include the data fetching and result dispatch time. If that includes any I/O, as it does, then that 40% drops down to well under 0.1%.
@PeacefulMindss
@PeacefulMindss 5 ай бұрын
😁 have no insightful comment other than the emoji, anyway, thank you man.
@lucifer-look-
@lucifer-look- 5 ай бұрын
I am surprised such things are not obvious for people
@zoran-horvat
@zoran-horvat 5 ай бұрын
You can see from the comments how many programmers fiercely oppose this style, holding on to the practices that are decades old.
@AdamRichardz
@AdamRichardz 12 күн бұрын
This reminds me why i avoid "clever".
@banster85
@banster85 5 ай бұрын
Really interesting, but i think it could also work without the need of handling the count variable simplifying the Advance method
@zoran-horvat
@zoran-horvat 5 ай бұрын
The method must distinguish the case when there are less than two items in the sequence from other cases.
@banster85
@banster85 5 ай бұрын
I mean something like this: return number > tuple.max ? (number, tuple.max) : number > tuple.next ? (tuple.max, number) : (tuple.max, tuple.next); This should work regardless the value of the count variable
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@banster85 But what about the case when there are no two numbers in the sequence?
@banster85
@banster85 5 ай бұрын
​@@zoran-horvatin this case the next variable will remain with its initial value 0 so the ProduceSum method can do the check on this variable, if zero returns -1 otherwise the sum​
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@banster85 What if the input number is zero?
@IvarDaigon
@IvarDaigon 3 ай бұрын
Does the shortened code actually make it run significantly faster? If not then it's a waste of time because all you are doing is making it much harder to read, understand and ultimately maintain. This is why shorthand completely fell out of use, sure it was compact and efficient to write but almost nobody could read it.
@zoran-horvat
@zoran-horvat 3 ай бұрын
The final code is an expression. Your comment indicates that you prefer procedural code over declarative, and that is so 1980s. The sooner you rid that mindset, the better for you, trust me. There is a very simple empirical proof for that. I know many programmers personally who made that step and none of them ever turned back to say that expressions are not readable or something. That tells you should learn to favor expressions, too.
@hashemwannous374
@hashemwannous374 Ай бұрын
Last two xd
@zimpoooooo
@zimpoooooo 3 ай бұрын
The last version is unreadable to me :(
@zoran-horvat
@zoran-horvat 3 ай бұрын
A matter of training the eye. Trust me, soon enough all code will look like that.
@zimpoooooo
@zimpoooooo 3 ай бұрын
@@zoran-horvat Btw, great thought provoking videos, even if I may not necessarily adopt the style.
@j1shin
@j1shin Ай бұрын
So, a functional approach is presented by a functional advocate feeding functional programming fans. The outcome is pure hell for a non-functional programmer. I understand the reasoning but as some comments already stated, most programmers will struggle extremely with this approach.
@zoran-horvat
@zoran-horvat Ай бұрын
Name two non-trivial language features added to C# in the last ten years that are not either functional or performance. The C# language team is the greatest functional advocate in C#.
@bonkers_dave
@bonkers_dave 25 күн бұрын
NOT a fan of counting things like curly braces or lines of code. The most important factor is how quickly root cause can be determined and how quickly a low risk fix can be applied when there is a production issue. It should be obvious to developers with average skills what the code is doing. The quest for "elegance" has caused more disasters than the quest for simple and obvious.
@zoran-horvat
@zoran-horvat 25 күн бұрын
What is the quest for elegance? Functional code is often so condensed that there is no place to put a big into. It is known in practice that bug count is by an order of magnitude lower in code based on pattern matching than in the corresponding procedural implementation. That is where counting curly braces suddenly becomes an important metric.
@bonkers_dave
@bonkers_dave 25 күн бұрын
@@zoran-horvat "elegant" usually means optimally condensed and optimally efficient. It can't be made more efficient and it can't be made smaller. The quest for elegance is the effort to achieve the absolute optimum state. With extensive experience in financial systems, I can attest to incidents when edge cases would produce failures that could be extremely costly. Real money, accumulating over time while an elusive bug is tracked down. Ability to readily understand code is the most important factor. Shorter is not always better. The problem isn't bug count, it is time-to-fix. Companies have gone out of business because of a bug that could not be fixed fast enough.
@zoran-horvat
@zoran-horvat 25 күн бұрын
@@bonkers_dave As I said, bugs you describe are by an order of magnitude more frequent in procedural code, for which majority of programmers still testify to be "readily understandable", although it is not. Your definition of elegance is, however, missing the point entirely. I don't know of a single programmer who condenses the code for the sake of condensing it.
@bonkers_dave
@bonkers_dave 25 күн бұрын
@@zoran-horvat "I don't know of a single programmer who condenses the code for the sake of condensing it." They are out there. I don't dispute any of your points in this video. I only point out that counting things like curly braces is not an important metric.
@zoran-horvat
@zoran-horvat 25 күн бұрын
@@bonkers_dave Counting curly braces in C# tells you what kind of a programmer you are looking at, because C# has been actively eradicating curly braces and substituting it with better syntax for the last 15 years. That is the underlying thought in my video.
@Katniss218
@Katniss218 Ай бұрын
I generally agree with this channel, but damn I really dislike how unreadable the last 2 methods are. Looks a bunch of mathematical mumbo jumbo. I'd personally settle somewhere between the 2nd and 3rd variant
@auronedgevicks7739
@auronedgevicks7739 5 ай бұрын
The ultimate lesson here is don't write your own code, use a library written by someone smarter than you. Unless you want to be the person actually writing a library like that...
@oligreenfield1537
@oligreenfield1537 5 ай бұрын
I will strike that code in PR review faster than light. It’s not the compiler to figure out the code It’s your F job. 1 - Readability 2 - Performance I swear to good I have enough to all of those who think that having performance issue is acceptable because you write business application.
@zoran-horvat
@zoran-horvat 5 ай бұрын
Performance? Oh, where have you been when another commenter has posted the results of measuring performance of the four methods? Guess what, the two functional methods are the fastest. Now you can take your preconceived opinions back. Better luck next time. Consider this a revenge of the compiler
@oligreenfield1537
@oligreenfield1537 5 ай бұрын
@@zoran-horvat False the message made by the other user show that a foreach + matching pattern is 40% faster. My points are still valid. It you work in a large team where the code is handle by 3 or 5 person you have a issue of readability and skill level no everyone is interested by MS new sugar syntax. So I Will stay on my position I Will strike that code for corporate use but for you home project go head.
@zoran-horvat
@zoran-horvat 5 ай бұрын
@@oligreenfield1537 How did you remove the part about performance from your opinion? You were very specific that this code is causing a performance issue that is somehow ignored because it is a business application. Now that it turned there is no performance issue, you pretend you never said it. My point is that your preconceived notion of a lacking readability is equally wrong, but you cannot see that from that 1990s trench in which you are dwelling.
@zzzzz2903
@zzzzz2903 4 ай бұрын
​@@zoran-horvat just a side - note, I feel 90's apps were much more stable and bug-free (and faster) than today's 😔
@zoran-horvat
@zoran-horvat 4 ай бұрын
@@zzzzz2903 Actually, that is quite untrue. I know, I was there.
@adambickford8720
@adambickford8720 5 ай бұрын
I would code this 'functionally' in java streams, which are kinda like linq if you squint. I tried to avoid int specific features like `sum()`, I may not have fully understood the reqs: var magicSum = Arrays.stream("421739".split("")) .map(Integer::valueOf) .sorted(Comparator.reverseOrder()) .limit(2) .collect(collectingAndThen( toList(), twoLargest -> twoLargest.size() == 2 ? twoLargest.getFirst() + twoLargest.getLast() : -1 ));
@zoran-horvat
@zoran-horvat 5 ай бұрын
The problem with this solution is that it requires O(N logN) time and O(N) space to complete, where there is no upper bound on N. The solution from the video runs in O(N) time and O(1) space under the same constraints.
@adambickford8720
@adambickford8720 5 ай бұрын
@@zoran-horvat I'm going for something that feels straight forward to understand and maps to the problem in an 'obvious' way. This largely avoids the low-level imperative 'machinery' without being so abstract it doesn't readily convey meaning in this problem context. If there's an actual SLA we can certainly do something in our chain to achieve that.
@adambickford8720
@adambickford8720 5 ай бұрын
@@zoran-horvat It looks like java added something similar to java 21 but, as usual, it seems more limited. I see what you're doing w/the count, it essentially acts as a state identifier vs explicitly having to match all of the parts in the pattern to infer state. It kind of reminds of using bit flags vs explicit booleans to manage things; clever, but not obvious. var patternMatching = Arrays.stream("32459722".split("")) .map(Integer::valueOf) .reduce( new TwoGreatest(0, 0, 0), (twoGreatest, number) -> switch (twoGreatest) { case TwoGreatest(_, _, var count) when count == 0 -> new TwoGreatest(number, 0, 1); case TwoGreatest(var a, _, var count) when count == 1 && number > a -> new TwoGreatest( number,a, 2); case TwoGreatest(var a, _, var count) when count == 1 -> new TwoGreatest( a,number, 2); case TwoGreatest(var a, _, var count) when count == 2 && number > a -> new TwoGreatest( number,a, 2); case TwoGreatest(var a, var b, var count) when count == 2 && number > b -> new TwoGreatest( a,number, 2); default -> twoGreatest; }, (a, b) -> new TwoGreatest(Math.max(a.a, b.a), Math.max(b.a, b.b), a.count) ); var sum = patternMatching.count == 2 ? patternMatching.a + patternMatching.b : -1;
@adambickford8720
@adambickford8720 5 ай бұрын
This avoids the O(N) space issue while still allowing for more than 2 items (does youtube block github links?): var limit = 2; var topN = stream("45432722557".split("")) .map(Integer::valueOf) .reduce( List.of(), (largestNFound, number) -> concat(largestNFound.stream(), of(number)) .sorted(Comparator.reverseOrder()) .limit(limit) .toList(), (a, b) -> concat(a.stream(), b.stream()).toList() ); var sum = topN.size() >= limit ? topN.stream().mapToInt(Integer::intValue).sum() : -1;
The Ultimate Guide to C# Records
12:55
Zoran Horvat
Рет қаралды 14 М.
How to Avoid Null Reference Exceptions: Optional Objects in C#
18:13
Climbing to 18M Subscribers 🎉
00:32
Matt Larose
Рет қаралды 35 МЛН
ОДИН ДЕНЬ ИЗ ДЕТСТВА❤️ #shorts
00:59
BATEK_OFFICIAL
Рет қаралды 6 МЛН
Backstage 🤫 tutorial #elsarca #tiktok
00:13
Elsa Arca
Рет қаралды 47 МЛН
Here is How Fast is LINQ, Spans, and Everything
12:40
Zoran Horvat
Рет қаралды 10 М.
The Lesson About GUID IDs I Learned the Hard Way
15:43
Zoran Horvat
Рет қаралды 27 М.
3 Shocking Misconceptions Among C# Programmers
9:25
Zoran Horvat
Рет қаралды 13 М.
"Stop Using Async Await in .NET to Save Threads" | Code Cop #018
14:05
Manage Nulls Like a Boss and Never Fail!
21:43
Zoran Horvat
Рет қаралды 11 М.
The Blazor Competitor is Here!
15:08
Nick Chapsas
Рет қаралды 62 М.
Master the Design of Functional Types in C#
17:53
Zoran Horvat
Рет қаралды 12 М.
Is Functional Programming a Good Idea?
10:28
Sammy Engineering
Рет қаралды 16 М.
The params Keyword is Finally Fixed in C# 13!
11:15
Nick Chapsas
Рет қаралды 48 М.
💅🏻Айфон vs Андроид🤮
0:20
Бутылочка
Рет қаралды 683 М.
Телефон в воде 🤯
0:28
FATA MORGANA
Рет қаралды 1,2 МЛН
Will the battery emit smoke if it rotates rapidly?
0:11
Meaningful Cartoons 183
Рет қаралды 29 МЛН
Нашел еще 70+ нововведений в iOS 18!
11:04