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.
@pagorbunov2 жыл бұрын
You need to abstract cause it was just a simple sample.
@simonpainter22422 жыл бұрын
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.
@tordjarv38022 жыл бұрын
@@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.
@tordjarv38022 жыл бұрын
@@simonpainter2242 It is ok. I really enjoyed your talk. I particularly liked your approach to add default values in case of missing values.
@simonpainter22422 жыл бұрын
@@tordjarv3802 That's a good point. I'll have a think about that particular example for the next iteration of this talk, Thanks :)
@redpepper742 жыл бұрын
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.
@simonpainter22422 жыл бұрын
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!
@alexclark67772 жыл бұрын
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.
@simonpainter22422 жыл бұрын
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.
@tejeshreddy62522 жыл бұрын
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!
@simonpainter22422 жыл бұрын
Thanks. At the very least I hope I was entertaining :)
@akitelesforo Жыл бұрын
Great talk, appreciate how you play c#, beauty of linq
@simonpainter2242 Жыл бұрын
Thanks!!!
@ConductiveFoam2 жыл бұрын
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!)
@simonpainter22422 жыл бұрын
nice, I like that one. It's not a problem I encounter often, but I can see it being useful.
@CRBarchager2 жыл бұрын
13:53 Shouldn't the second line of map be x => x / 5 ?
@larsthomasdenstad90822 жыл бұрын
Good catch. I hope your oven baked duck turned out OK.
@prouleau44402 жыл бұрын
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.
@simonpainter22422 жыл бұрын
@@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.
@simonpainter22422 жыл бұрын
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!
@rastislavsvoboda43632 жыл бұрын
@@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}"); } }
@DuRoehre902102 жыл бұрын
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 ..
@AndersBaumann9 ай бұрын
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.
@kazimierzszadkowski18002 жыл бұрын
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 :(
@pagorbunov2 жыл бұрын
You need to abstract cause it was just a simple sample.
@PbPomper2 жыл бұрын
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-G2 жыл бұрын
not to mention the runtime costs are orders of magnitude above the straightforward no-nonsense version
@simonpainter22422 жыл бұрын
@@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
@simonpainter22422 жыл бұрын
@@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.
@lawrencejob2 жыл бұрын
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??”)
@simonpainter22422 жыл бұрын
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.
@omarbousbia69162 жыл бұрын
indexes are a cool feature in C#, but one downside of it is that you can't do go to definition on them
@simonpainter22422 жыл бұрын
that's true, but when they're used in the right place, it's a small price to pay, I feel
@CRBarchager2 жыл бұрын
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.
@simonpainter22422 жыл бұрын
Apologies. I usually try and repeat the question. I must have missed this one. I'll try and be more vigilant in future!
@CRBarchager2 жыл бұрын
@@simonpainter2242 Thank you for answering.
@Robert-G2 жыл бұрын
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 :-)
@simonpainter22422 жыл бұрын
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-G2 жыл бұрын
@@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.
@simonpainter22422 жыл бұрын
@@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-G2 жыл бұрын
@@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.
@simonpainter22422 жыл бұрын
@@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.
@michaelnurse90892 жыл бұрын
KZbin is buggy. I upvoted once for the talk and once for the Thundercats reference. Instead of recording two upvotes it did none. Strange.
@simonpainter22422 жыл бұрын
oh well, at least you enjoyed the talk, I hope?
@cccyberfamilydk2 жыл бұрын
Do you have a github link?
@oleggavrilov70832 жыл бұрын
So you could report and block that nonsense? Smart move mate
@simonpainter22422 жыл бұрын
@@oleggavrilov7083 No need to be unkind.
@oleggavrilov70832 жыл бұрын
@@simonpainter2242 please let me decide for myself
@mar_sze2 жыл бұрын
There were some nice things in this but also surprisingly many that I would consider actually pretty bad practice.
@simonpainter22422 жыл бұрын
which bits? I'm happy to look into any issues before I do this talk again
@mar_sze2 жыл бұрын
@@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;
@Mr7Shane2 жыл бұрын
@@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".
@simonpainter22422 жыл бұрын
@@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.
@rastislavsvoboda43632 жыл бұрын
10:47 this is IsNotNullOrEmpty, or did I miss something? public static bool IsNullOrEmpty(this IEnumerable @this) => !@this?.Any() ?? true;
@simonpainter22422 жыл бұрын
Isn't IsNullOrEmpty for Strings? The example I gave was to do the same thing with Enumerables
@rastislavsvoboda43632 жыл бұрын
@@simonpainter2242 I mean your code is IsNotNullOrEmpty, not IsNullOrEmpty
@simonpainter2242 Жыл бұрын
@@rastislavsvoboda4363 I see what you mean, I'll have a look and see whether a correction is needed. Thanks!
@cverde12342 жыл бұрын
I'd like to see the like/dislike ratio on this video. There are some good points but also some mistakes and bad code.
@simonpainter22422 жыл бұрын
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.
@jessemorgan82262 жыл бұрын
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.
@simonpainter22422 жыл бұрын
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.
@BryonLape2 жыл бұрын
Developers not gathering requirements is the first big mistake.
@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 Жыл бұрын
@@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.
@jalvrus2 жыл бұрын
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) => ...
@Kefir02 жыл бұрын
> 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.
@simonpainter22422 жыл бұрын
Thanks. I'll have a look at the TryGetValue code ready for the next time I do this talk.
@samuelschwager2 жыл бұрын
Map already exists, it is called Select :P
@oleggavrilov70832 жыл бұрын
Finally
@simonpainter22422 жыл бұрын
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 Жыл бұрын
13:57 This version is buggy. x/5 became x/9...
@simonpainter2242 Жыл бұрын
Thanks. I'll have a look & see if I can fix the slide for next time
@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 Жыл бұрын
@@etiennelemieux472 thanks :) and yes, I always try and keep an eye on the comments threads.