Hacking C#: Development for the Truly Lazy - Simon Painter - NDC Copenhagen 2022

  Рет қаралды 16,905

NDC Conferences

NDC Conferences

Күн бұрын

Пікірлер: 84
@tordjarv3802
@tordjarv3802 2 жыл бұрын
Maybe I'm to much of a physicist but I think that 9*tempCentigrade/5 + 32 is more readable than anything presented in this video.
@pagorbunov
@pagorbunov 2 жыл бұрын
You need to abstract cause it was just a simple sample.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
In the real world, I probably would do something like that, especially as it doesn't really matter for this one example. I just didn't want to get too bogged down in real-world detail when I was talking through the example.
@tordjarv3802
@tordjarv3802 2 жыл бұрын
@@pagorbunov while it is true that using other forms of chaining operations together in more complicated situations is better, this was a talk about being a lazy programmer so making an example where the end result is more complicated than the starting point kind of defeats the purpose of the example.
@tordjarv3802
@tordjarv3802 2 жыл бұрын
@@simonpainter2242 It is ok. I really enjoyed your talk. I particularly liked your approach to add default values in case of missing values.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
@@tordjarv3802 That's a good point. I'll have a think about that particular example for the next iteration of this talk, Thanks :)
@redpepper74
@redpepper74 2 жыл бұрын
After learning Java and Python for a year or so and picking up some Haskell, C# looks like the best of both worlds when it comes to OOP and functional. Extension methods seem great for general-purpose libraries, and LINQ looks like straight-up good declarative programming. It’s exciting seeing all the stuff .NET can be used for, can’t wait to get started.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
I like it. LINQ is one of C#'s very best features. Along with Pattern Matching and record types. I hope you enjoy working with it!
@alexclark6777
@alexclark6777 2 жыл бұрын
36:00 Is the ContainsConsecutiveNumbers going to scale? Given that it's recursive (and I'm not 100% sure but I don't think C# will do some kind of fancy tail-recursion optimization) isn't this likely to smash the stack over a certain array length? It may have been a bit easier on the heap (and probably the stack!) to just iterate and compare current to previous, stopping when either the condition has been falsified (current != previous) or verified (end of array). In fact that might make for an interesting generic function, a "private static bool ConsecutiveAll" which takes an IEnumerable and does exactly that.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
It likely won't scale. Sadly C# doesn't implement any of the nice tail optimised recursion functionality you get in F#. Since writing this talk (about 3 or 4 years ago) I've learned it's also possible to do some of that with use of the Zip function in LINQ as well.
@tejeshreddy6252
@tejeshreddy6252 2 жыл бұрын
This was an interesting presentation, Simon. Although I don't agree with a lot of your points, as some other commenters have pointed out, I appreciate the effort you've put into this. I also appreciate the civility you've displayed to bad faith comments, it is often hard to be unfazed by trolls in the comments. Kudos to you!
@simonpainter2242
@simonpainter2242 2 жыл бұрын
Thanks. At the very least I hope I was entertaining :)
@akitelesforo
@akitelesforo Жыл бұрын
Great talk, appreciate how you play c#, beauty of linq
@simonpainter2242
@simonpainter2242 Жыл бұрын
Thanks!!!
@ConductiveFoam
@ConductiveFoam 2 жыл бұрын
This was very interesting, if not for the specific extensions then for the approach. Thinking I'll be able to use this for some of the legacy stuff I maintain for my day job actually.. Thanks a bunch! I've got an extension I like quite a bit: Extracting the non-null elements in an enumerable public static IEnumerable NonNull(this IEnumerable source) => source.Where(e => e is not null).Select(e => e!)
@simonpainter2242
@simonpainter2242 2 жыл бұрын
nice, I like that one. It's not a problem I encounter often, but I can see it being useful.
@CRBarchager
@CRBarchager 2 жыл бұрын
13:53 Shouldn't the second line of map be x => x / 5 ?
@larsthomasdenstad9082
@larsthomasdenstad9082 2 жыл бұрын
Good catch. I hope your oven baked duck turned out OK.
@prouleau4440
@prouleau4440 2 жыл бұрын
For me, that demonstrate the signal-to·noise ratio of that monad is terrible. The classic math formula on 1 line is way simpler and everyone learned to read and write that at primary school. Beside that, many interesting tricks.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
@@prouleau4440 Thanks. Perhaps I should swap the example at some point. I went with the temperature conversion as the simplest example I could think of, since I didn't want to get too bogged down in real-world detail.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
Thanks. I've had an email about that too. I've been doing this talk for years and no-one's ever noticed that mistake until today!
@rastislavsvoboda4363
@rastislavsvoboda4363 2 жыл бұрын
@@simonpainter2242 couple of years ago I've used in real app: public static class DialService { public static bool DialTel(string number) { return number .Map(ToRawNumber) .Map(ToTelUrl) .Map(UIApplication.SharedApplication.OpenUrl); } public static bool DialSkype(string number) { return number .Map(ToRawNumber) .Map(ToSkypeUrl) .Map(UIApplication.SharedApplication.OpenUrl); } private static string ToRawNumber(string number) { return new StringBuilder(number) .Replace(" ", string.Empty) .Replace("-", string.Empty) .Replace("(", string.Empty) .Replace(")", string.Empty) .ToString() .Trim(); } private static NSUrl ToSkypeUrl(string rawNumber) { return NSUrl.FromString($"skype:{rawNumber}?call"); } private static NSUrl ToTelUrl(string rawNumber) { return NSUrl.FromString($"tel:{rawNumber}"); } }
@DuRoehre90210
@DuRoehre90210 2 жыл бұрын
Yeah, I miss coding C#. Most of this looks familiar to my previous achievements, having a toolkit of generic LINQ extensions methods for "any purpose". Extra boosted by Resharper. Python is picking up a on a few modern C# features like string interpolation, partly better and partly worse, but similar. And yet, it remains much less smooth than C# extension methods. 24:32 I wouldn't necessarily agree. Adding ToArray or ToList ensures that the operation is finished, which might be important in case of databases (because locking). Passing IEnumerable around extends the runtime to ..
@AndersBaumann
@AndersBaumann 9 ай бұрын
ToList() is very dangerous when you are working with a large database. I have experienced out-of-memory exceptions multiple times because of a ToList. In my company we have added code that puts a limit to the number of objects in memory to be robust against a misplaced ToList.
@kazimierzszadkowski1800
@kazimierzszadkowski1800 2 жыл бұрын
In my opinion proposed "improvement" of ToFahrenheit is insanity. One liner would be best. Version with variables is still ok, readable and simple. Version with "Map" forces me to think what is actually going on there. Don't like it at all :(
@pagorbunov
@pagorbunov 2 жыл бұрын
You need to abstract cause it was just a simple sample.
@PbPomper
@PbPomper 2 жыл бұрын
I fully agree. Some of these proposals are not readable at all. Everyone loves small methods, but it shouldn't go at the expense of readiblity. But his most important message came across very well and I fully agree with abstracting boilerplate code by using generic extensions. Basically DRY and OCP.
@Robert-G
@Robert-G 2 жыл бұрын
not to mention the runtime costs are orders of magnitude above the straightforward no-nonsense version
@simonpainter2242
@simonpainter2242 2 жыл бұрын
​@@PbPomper That was roughly the main principle I was trying to bring across. Most of the ideas I was presenting here were intended as inspiration for a way of thinking about C#, rather than "these are all of the extensions you need and how to use them". I didn't think readability was too bad, but that may be a personal preference thing. Always keen to hear if you've got more & better ideas though? These are just my personal time-savers that I tend to throw into new projects
@simonpainter2242
@simonpainter2242 2 жыл бұрын
@@Robert-G I'm not sure they're necessarily orders of magnitude worse. I do tend to focus on brevity and readability over performance though. My reasoning is that it's easier these days to throw a bit of money at Azure than to have the developers spend longer working on an enhancement.
@lawrencejob
@lawrencejob 2 жыл бұрын
Map deserves a deeper dive than it got in this presentation - it came across like speaker didn’t know about IEnumerable.Select but of course that’s not the case. I do think such a general use of monads defeats the point of using monads though (unless you have an agenda like handling nulls/optionals or errors) - this topic should have gotten more time imo bc I think it’s a hidden gem in this talk that probably confused people (reading comments like “Map==Select??”)
@simonpainter2242
@simonpainter2242 2 жыл бұрын
I think I should make a point of explaining the difference between Map and Select the next time I do this. It's obvious to me, but I've been doing it for years, so it's easy for me to inadvertently miss out an important explanation. I didn't want to get too deep into FP and Monads in this talk - I have another in which I do a much deeper dive. I thought it might be interesting to at least touch on the subject. I probably should have chosen a better example, perhaps, though.
@omarbousbia6916
@omarbousbia6916 2 жыл бұрын
indexes are a cool feature in C#, but one downside of it is that you can't do go to definition on them
@simonpainter2242
@simonpainter2242 2 жыл бұрын
that's true, but when they're used in the right place, it's a small price to pay, I feel
@CRBarchager
@CRBarchager 2 жыл бұрын
42:30 The question section is difficult to follow along as you cannot hear the question. It would be great if the speaker would repeat the question before answering it.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
Apologies. I usually try and repeat the question. I must have missed this one. I'll try and be more vigilant in future!
@CRBarchager
@CRBarchager 2 жыл бұрын
@@simonpainter2242 Thank you for answering.
@Robert-G
@Robert-G 2 жыл бұрын
dictionaries that return null on not found are only useful in specific cases, and then they will be specific wrappers around an actual dictionary. Finding null is not the same as not having the value. Putting that into the bcl is not going to happen. There’s a GetValueOrDefault on immutable diction, it might come to the Enumerable extension class at some point… btw: That’s what TryGetValue is for, tells you whether you found it, and then let you use it, without looking it up twice, as the code is doing here (contains & indexer) I thought most of the tricks are really hacks that increase runtime cost sneakily without people knowing why their server are spending a lot more time on GC sweeps. And they also make stuff more convoluted not easier to follow at all. However, there were some nice nuggets I’ll take away from it. Thanks :-)
@simonpainter2242
@simonpainter2242 2 жыл бұрын
Thanks. I'm glad I was some small use :) I'd tend to use the IDictionary wrapper I proposed here when I have a default value in mind. I tend to avoid uses of Null wherever it's possible. I'm not sure I agree it makes the code more convoluted, I was trying to cut down on the amount of code on display. My reasoning is that no-one necessarily cares what's behind the boilerplate extension method. I hope I was of some use though. Thanks so much for watching :)
@Robert-G
@Robert-G 2 жыл бұрын
​@@simonpainter2242 dang small screens. my post read a bit more negative than intended. But I do have a bit of a default skepsis against adding stuff that allocates or is cool, vs a no-nonsense in-your-face version.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
@@Robert-G I can see your point & I don't disagree. Amongst my aims here though, was to disguise recurring bits of boilerplate that we're all used to using with a meaningful description. In my head, it's better for junior developers, who want to quickly understand the meaning of a codebase, but without needing to decode the meaning of every little block of C#.
@Robert-G
@Robert-G 2 жыл бұрын
@@simonpainter2242 I use the one where the variable part of the code can be passed as a closure all the time (you called it donut :D ). That’s perfect for reuse and also to hide code with lots of chest hair that needs to work in all kinds of scenarios, but shouldn’t be intimidating to use. Absolutely with you on that.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
@@Robert-G I honestly have no idea what the correct term for the Doughnut is :p I suspect it might be a "Thunk", but I'm probably wrong. It's definitely a powerful technique though & very in line with the SOLID principles.
@michaelnurse9089
@michaelnurse9089 2 жыл бұрын
KZbin is buggy. I upvoted once for the talk and once for the Thundercats reference. Instead of recording two upvotes it did none. Strange.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
oh well, at least you enjoyed the talk, I hope?
@cccyberfamilydk
@cccyberfamilydk 2 жыл бұрын
Do you have a github link?
@oleggavrilov7083
@oleggavrilov7083 2 жыл бұрын
So you could report and block that nonsense? Smart move mate
@simonpainter2242
@simonpainter2242 2 жыл бұрын
@@oleggavrilov7083 No need to be unkind.
@oleggavrilov7083
@oleggavrilov7083 2 жыл бұрын
@@simonpainter2242 please let me decide for myself
@mar_sze
@mar_sze 2 жыл бұрын
There were some nice things in this but also surprisingly many that I would consider actually pretty bad practice.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
which bits? I'm happy to look into any issues before I do this talk again
@mar_sze
@mar_sze 2 жыл бұрын
@@simonpainter2242 I think most has already been mentioned other comments, and I mostly agree with it, such as: - Recursive approaches might scale badly - Using ContainsKey + get instead of TryGetValue - Returning null for missing keys - Over-func`ing. I use funcs and extension methods a lot (and I agree with the "rules" you set up, well done!), but also we need to keep in mind they do come with a cost and sometimes might make readbility worse than improve it (e.g. the chained .Map() instead of a simple expression) Btw, I never thought of using index with params, so that was a nice little nuget. Another trick I like: in some cases you could use generics instead of a type dictionary, which will be faster: private static class Impl { public static Func? Func } Impl.Func = s => s.Trim(); Impl.Func = d => Math.Round(d); public static T Clean(T value) => Impl.Func?.Invoke(value) ?? value;
@Mr7Shane
@Mr7Shane 2 жыл бұрын
@@simonpainter2242 The example of "Map", what is your problem with the local variables? What do you mean "waste local variables" and "var a is wasting spacing".
@simonpainter2242
@simonpainter2242 2 жыл бұрын
@@Mr7Shane they're instantiated and used for a single line, then never used again. If the function were incredibly long, they're still being held in memory until the end of the function, even though they are of no further use.
@rastislavsvoboda4363
@rastislavsvoboda4363 2 жыл бұрын
10:47 this is IsNotNullOrEmpty, or did I miss something? public static bool IsNullOrEmpty(this IEnumerable @this) => !@this?.Any() ?? true;
@simonpainter2242
@simonpainter2242 2 жыл бұрын
Isn't IsNullOrEmpty for Strings? The example I gave was to do the same thing with Enumerables
@rastislavsvoboda4363
@rastislavsvoboda4363 2 жыл бұрын
@@simonpainter2242 I mean your code is IsNotNullOrEmpty, not IsNullOrEmpty
@simonpainter2242
@simonpainter2242 Жыл бұрын
@@rastislavsvoboda4363 I see what you mean, I'll have a look and see whether a correction is needed. Thanks!
@cverde1234
@cverde1234 2 жыл бұрын
I'd like to see the like/dislike ratio on this video. There are some good points but also some mistakes and bad code.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
Weirdly I have twice as many likes for this video as my FP video from Porto. I have no idea how many dislikes I have (and honestly I don't think I could live with that knowledge if it were available). Hopefully it's a sign that folks are feeling generous and forgiving my faults :) That or folks *really* hate FP.
@jessemorgan8226
@jessemorgan8226 2 жыл бұрын
Most of these are the exact kind of black-box 'art' that make you cringe when you have to take over some pre-existing codebase and you can see the developer has gone out of their way to implement things using the most 'intelligent' implementations they can think of, using as many syntactic bells and whistles they can find, feeling proud of themselves that they have made such masterpieces of 'elegance' - but completely failing to recognise that so much of the elegance is in their head and not the code that it is actually obfuscating the codebase and overcomplicating it for anyone but them. He even mentions that there are probably newer syntactic bells and whistles in newer C# versions and that some of his designs may be 'out of date' I am also struck by the extra number of function calls his code will be generating causing more and more stack frame setup and usage. Simpler code is not out of date because there are new idioms available in newer language versions. Simpler code is not less lines either. Simpler code is code that takes the least time to reason about to a coder who has never looked at the codebase before. Newer syntax is great for heavy lifting where it is appropriate and makes things better. Use what is fit for purpose not what is the newest.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
I think it's one of those things where a bit of common sense is called for. I agree that it can be taken too far, and code can end up hard to read. When I add in these sorts of extensions though, I try and make each one as small and discrete as possible, and with a clear naming convention, so hopefully no-one would even *need* to look at the code behind it. When this sort of approach is done right (easier said than done!) I'd argue that it's actually easier to reason out what the code is doing, as there's less "code noise" obscuring the intention of the code. I'm basically advocating for a declarative code style over Imperative.
@BryonLape
@BryonLape 2 жыл бұрын
Developers not gathering requirements is the first big mistake.
@simonpainter2242
@simonpainter2242 Жыл бұрын
I can't disagree with you here, although in my experience, the biggest problem is the customer/business not actually *Knowing* what they want in the first place! Another reason I try to write very "low noise" code - it's easier to change if there's a proper confirmation of an unclear requirement.
@BryonLape
@BryonLape Жыл бұрын
@@simonpainter2242 Never ask a customer what they want, they rarely know, and often when they think they do, its wrong. Ask them what they want to do. What are they trying to accomplish. How does that fit into the flow of their day.
@jalvrus
@jalvrus 2 жыл бұрын
Extension methods and the ability to create "fluent" APIs is one of the best things to ever happen to C#. The funny thing about that is that it was all created to serve Linq-to-SQL, which is hardly ever used. JFYI, your dictionary extensions could be more efficient: this.TryGetValue(x, out var value) ? value : defaultValue; Also, don't forget default values for parameters: ToLookupWithDefault(this, K x, V defaultValue = default) => ...
@Kefir0
@Kefir0 2 жыл бұрын
> Linq-to-SQL, which is hardly ever used What do you mean, LINQ to SQL translation is used in EF / EF Core which are everywhere.
@simonpainter2242
@simonpainter2242 2 жыл бұрын
Thanks. I'll have a look at the TryGetValue code ready for the next time I do this talk.
@samuelschwager
@samuelschwager 2 жыл бұрын
Map already exists, it is called Select :P
@oleggavrilov7083
@oleggavrilov7083 2 жыл бұрын
Finally
@simonpainter2242
@simonpainter2242 2 жыл бұрын
Map and Select aren't the same thing. Select operates on each element of an Enumerable separately. Map operates on the entire source object. If you called Map(x => ... on an Enumerable, then x would be the Enumerable itself
@etiennelemieux472
@etiennelemieux472 Жыл бұрын
13:57 This version is buggy. x/5 became x/9...
@simonpainter2242
@simonpainter2242 Жыл бұрын
Thanks. I'll have a look & see if I can fix the slide for next time
@etiennelemieux472
@etiennelemieux472 Жыл бұрын
@@simonpainter2242 oh glad you answered, didn't know you would read this. I found your presentation very interesting (and entertaining), with many resources and ideas to re-use.
@simonpainter2242
@simonpainter2242 Жыл бұрын
@@etiennelemieux472 thanks :) and yes, I always try and keep an eye on the comments threads.
Where’s C# headed? - Mads Torgersen - NDC Copenhagen 2022
1:01:28
NDC Conferences
Рет қаралды 29 М.
Life hack 😂 Watermelon magic box! #shorts by Leisi Crazy
00:17
Leisi Crazy
Рет қаралды 79 МЛН
龟兔赛跑:好可爱的小乌龟#short #angel #clown
01:00
Super Beauty team
Рет қаралды 13 МЛН
ТИПИЧНОЕ ПОВЕДЕНИЕ МАМЫ
00:21
SIDELNIKOVVV
Рет қаралды 1,6 МЛН
啊?就这么水灵灵的穿上了?
00:18
一航1
Рет қаралды 54 МЛН
Federico Lois - Metaprogramming for the masses
59:47
DotNext — конференция для .NET‑разработчиков
Рет қаралды 1,2 М.
Functional Programming with C# - Simon Painter - NDC London 2023
1:09:05
NDC Conferences
Рет қаралды 17 М.
Back to Basics: Efficient Async and Await - Filip Ekberg - NDC Porto 2022
1:02:00
Plain Text - Dylan Beattie - NDC Copenhagen 2022
59:20
NDC Conferences
Рет қаралды 165 М.
The best way to create a string in C# that you shouldn't use
16:41
Nick Chapsas
Рет қаралды 70 М.
Creating my own programming language in 1 day
2:02:18
JPT
Рет қаралды 1,3 М.
Domain-Driven Refactoring - Jimmy Bogard - NDC London 2022
1:00:03
NDC Conferences
Рет қаралды 46 М.
Life hack 😂 Watermelon magic box! #shorts by Leisi Crazy
00:17
Leisi Crazy
Рет қаралды 79 МЛН