Adding a BETTER way to loop in C#

Поділитися
Вставка
  • Опубліковано 16 жов 2022
  • Check out my courses: dometrain.com
    Become a Patreon and get source code access: / nickchapsas
    Hello everybody I'm Nick and in this video I will show you the secret extensibility points of C#, which will allow us to bring an AWESOME feature from Kotlin into the language. Not only we will make it work as if it was an official C# feature but we will also make sure it is really performant and fast.
    Workshops
    dotnetdays | 20 - 22 Oct | bit.ly/dotnetdays2022workshop
    NDC Minnesota | 15 - 18 Nov | bit.ly/ndcminnesota2022workshop
    NDC London | 23-27 January 2023 | bit.ly/ndclondon2023
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: bit.ly/ChapsasGitHub
    Follow me on Twitter: bit.ly/ChapsasTwitter
    Connect on LinkedIn: bit.ly/ChapsasLinkedIn
    Keep coding merch: keepcoding.shop
    #csharp #dotnet

КОМЕНТАРІ • 303

  • @nickchapsas
    @nickchapsas  Рік тому +72

    A couple of things I didn't cover in the video. Firsly if you are actually going to use this, make sure you also add an analyzer to warn or error on inappropriate usecases. Also, if you wanna support descending ranges for example foreach(var i in 10..5) you'd need to add a different check in the constructor and MoveNext() to support descending iteration.

    • @nanvlad
      @nanvlad Рік тому +6

      You also need to implement Reset() method to make an iteration variable reusable

    • @maunguyenvan9296
      @maunguyenvan9296 Рік тому

      how do you implement for loop with custom step like:
      for ( int i=0; i

    • @vincentjacquet2927
      @vincentjacquet2927 Рік тому +8

      @@nanvlad You are theorically right. Unfortunately Microsoft gave up on this a while ago, as the Reset method of enumerator generated with yield throw NotSupportedException. Therefore you cannot rely on Reset unless you known which enumerator you are dealing with and how it is implemented.

    • @kamyker
      @kamyker Рік тому +5

      More importantly ref struct won't work in async code. I wonder how slow would be class with pooling.
      #Edit just change it to plain struct. Even .net List uses non-ref struct Enumerator so shouldn't matter for performance.

    • @Grimlock1979
      @Grimlock1979 Рік тому +13

      @@maunguyenvan9296 You can make an extension method on ValueTuple. So you can say: "foreach (var i in (0..50, 2))".
      Or you can extend ValueTuple, based on how ranges in Haskell work: they are of the form "[first, second .. last]". So that would be: "foreach (var i in (0, 2..50))"

  • @reecenoone3113
    @reecenoone3113 Рік тому +115

    This is why coding is a form of art… I knew about all these features but never considered putting them together in this way

    • @looperx
      @looperx Рік тому +8

      In your defense the usability of a range with for loops is not something you should have to hack in yourself. It should come with the language.

    • @EddieVillamor
      @EddieVillamor Рік тому +3

      It sure can be such a form of art, especially when you get into clean coding and trying to come up with ways to make the simplest syntax

    • @kylekeenan3485
      @kylekeenan3485 Рік тому +3

      If we all coded in our own forms of "Art" we would be back to the 90's/00's with terrible code rampant everywhere that noone understands and doesn't want to touch.

    • @EddieVillamor
      @EddieVillamor Рік тому

      @@kylekeenan3485 or you could end up with a github community with guidelines and standards that everyone follows like we have now. A form of art that people are influenced by and mimic.
      Art is influenced by each other, not every single person will want uniqueness on every single thing we create. I mean is it not true that while poetry and drawings are limitless, there's really only a select number of ways to create things that make for a better product than other techniques that give the same result. So as with coding, and as it is today, everyone can create code in whatever way they choose, but because it's so artsy, you can write several ways to make the same hello world application, but do we? Nope, we always use the same examples everywhere with the same standards, etc, and we naturally, and typically, want to use the simplest path with the cleanest looking code. So it's just a matter of exposing the art for others to be influenced by.

    • @kylekeenan3485
      @kylekeenan3485 Рік тому

      @@EddieVillamor Your talking about a dream. We see people moaning about how agile doesn't help and that is clearly documented and has standards, guidelines, training courses galore. If people under those circumstances can't get it right, then following some unique (art) coding style will be a nightmare. Coding in your own unique style that's unusual and different to standard practices will just cause time delays and tech debt. It could in theory with proper guidance and teaching become useful as you stated but it never does. If people want to deviate from standard practices then it's probably best to keep it in their own personal projects. If you do discover something generally better then write a book 😁.

  • @DryBones111
    @DryBones111 Рік тому +33

    As much as I love the simplicity of the syntax, unless it's implemented in the language itself, I wouldn't use it because it is unexpected. Anyone else coming to the codebase would be confused seeing that and not finding anything about it in the official docs.
    In a similar vein, I love playing with the implicit operators but they have the downside of hiding what's really happening underneath. You've got to weigh up the benefit with the cost of abstraction as with anything.

  • @KevinInPhoenix
    @KevinInPhoenix Рік тому +60

    It never ceases to amaze me how much effort people will spend to save a tiny bit of effort.

    • @42069_
      @42069_ Рік тому +1

      hahahahahhaahaa

    • @cheebadigga4092
      @cheebadigga4092 Рік тому +1

      well this is just an example, you could also provide enumerators for your own types and make them behave this way if appropriate in that situation

    • @billy65bob
      @billy65bob Рік тому

      This is what we call a programmer move :^)

    • @Dimich1993
      @Dimich1993 Рік тому

      true

  • @11r3start11
    @11r3start11 Рік тому +116

    Its a cool feature that could make DSL even more represented in code. But "unexpected" C# code should be maintained, documented and is not junior-friendly.

    •  Рік тому +19

      Agreed. It is a bit too clever and the benefits are IMHO not that big.

    • @neociber24
      @neociber24 Рік тому +17

      This is a feature that should be baked into C#, I don't really agree with add extension methods for this.
      I don't get why ranges don't just return an enumerator

    • @NoGamer256
      @NoGamer256 Рік тому +7

      @@fredriksjoborg7021 Let's just get back to C# 5 then it is even more simple.

    • @phizc
      @phizc Рік тому

      @@neociber24 re: why ranges doesn't return an enumerator
      ranges can't always produce a start/end value unless it's provided with a length. It's Start and End properties are Index, not int.
      E.g. "0..", anything with the hat symbol.. on my phone so I don't know how to type it... the one above the a: â

    • @DryBones111
      @DryBones111 Рік тому

      @@NoGamer256 The difference is that official language features are extensively documented and can be found in any codebase. Custom language extensions are a new thing that needs to be learned. If it provides enough value, it can be worth it. Is changing "Enumerable.Range" into ".." worth it? That's up to you.

  • @Vennotius
    @Vennotius Рік тому +21

    Having come from Python to C#, I could see myself really liking this near the beginning of my C# path. But now I have gotten used to how C# works and looks.
    This is nevertheless interesting from an educational point. And it is a good reminder that one can build your own things to meet your needs or just to make things behave more to your taste.

  • @owns3
    @owns3 Рік тому

    power of extensions - love it

  • @pw.70
    @pw.70 Рік тому

    I've used enumerators before, but never had it implemented as a feature of the code itself. Genius!

  • @ignaziomessina69
    @ignaziomessina69 Рік тому +2

    I definitely want this language feature in future version of C# natively! For me it's really fast to write and clear to read

  • @R.Daneel
    @R.Daneel Рік тому +5

    I expect this to enter the language. It also feels like its exclusion is an oversight (which, of course, it's not). The .. format is just so elegant and self-explanatory.

  • @dimasveliz6745
    @dimasveliz6745 Рік тому +11

    very interesting. Hopefully will be built in. Having this custom classes all around and having to add them as a reference to each project for Syntactic sugar purposes is a tremendously big deal. Thanks for sharing though!

  • @thinker2273
    @thinker2273 Рік тому +5

    If/when the Roles & Extensions proposal is implement into C#, you'll be able to not only make anything enumerable, but also implement IEnumerable for any type, so you'd literally be able to use Linq on ranges. You're also able to do the same for GetAwaiter which is what makes the await operator function, and you can even make types besides Task/ and ValueTask/ into acceptable return types for async methods. Extension methods (and hopefully soon Roles & Extensions) is truly one of the best features of C#.

    • @NoGamer256
      @NoGamer256 Рік тому

      They started exploring in 2017. I just don't have much hope. There is crowd of people saying that C# is getting too complex and people don't know what to use anymore. I think they listen to them.

  • @Spherous
    @Spherous Рік тому

    Omg yesss! This is a feature I very much miss from Rust when using C#. Thanks!

  • @TheSilent333
    @TheSilent333 Рік тому

    You continue to blow my mind with these little pearls. Thanks Nick!

  • @Jacobhay09
    @Jacobhay09 Рік тому +12

    I love your content. I am 100% self-trought and learned on the job where I work. So I don't get exposed to things as much I as I would like. But your small bite-sized videos keep me thinking about new ways to do things. I am able to take these back to some of our older projects and be a fresh set of eyes on them. Thanks again! I am in MN but due to budget cuts, I lost the funds set aside for training and events this year. Maybe I will be able to check you out next time you are in the citites. Keep up the amazing work!

    • @LittleRainGames
      @LittleRainGames Рік тому +1

      Best way is to start coding at home, and to just try new things and read.
      Eventually you come across stuff like this.

  • @nekuskus5218
    @nekuskus5218 Рік тому

    A super interesting way of using extensions! Thanks a lot for this

  • @alisonhj
    @alisonhj Рік тому

    I would use it, very elegant, congrats!

  • @maskettaman1488
    @maskettaman1488 Рік тому +14

    Not a fan of this feature/syntax, but still super cool to see how you'd go about implementing it. Not something I had thought of but can definitely see using in other ways in the future

  • @anaselhassani2545
    @anaselhassani2545 Рік тому

    Worked , thanks a lot!

  • @Galakyllz
    @Galakyllz Рік тому

    I didn't even think about creating useful enumerators based on native types. Great video, thanks.

  • @gui.ferreira
    @gui.ferreira Рік тому

    That is really a clever idea Nick! Well done. 👏

  • @vuquy711
    @vuquy711 Рік тому

    Awesome, Nick. I really love your videos!

  • @Denominus
    @Denominus Рік тому +3

    Fun side note. C# actually has quite a few of these "magic methods" that you can implement yourself. The LINQ query syntax is full of them, like being able to use the "from x in y select..." syntax on any type if you add a Select method with the correct signature to that type.
    I don't normally recommend it because its quite obscure and confusing to most people but its nice to know how the internals of some of these language features work.

    • @DryBones111
      @DryBones111 Рік тому +1

      Your specific example is pretty useful for implementing monadic code with an imperative syntax. I do like it, and it has its merits.

  • @pritishranjan
    @pritishranjan Рік тому +2

    This is the real beauty of C#. Its not coding mate...it's Art. 👏

  • @kylekeenan3485
    @kylekeenan3485 Рік тому +2

    It's a nice idea if it was implemented into C# for all to use, but not as a random thing added to a project. Last thing we need is rewriting the wheel because it looks slightly nicer. This sort of behaviour is what leads to technical debt over a long period of time.

  • @carldaniel6510
    @carldaniel6510 Рік тому +1

    Neat truck! I will absolutely use this.

  • @renatogolia211
    @renatogolia211 Рік тому +2

    Is there any specific advantage on not implementing IEnumerator in the example? I understand the advantages of duck typing for types that we don't own (like the methods extending Range and Index) but whenever possible I'd still prefer using interfaces when available.
    Also, this is something I'd like MS added to the BCL as it makes very much sense to iterate on a range.

  • @parkercrofts6210
    @parkercrofts6210 Рік тому

    Wow thank you so much that really helped

  • @maaadkat
    @maaadkat Рік тому

    Supporting descending without affecting performance is tough. You don't want an if statement in the middle of MoveNext. Branch Prediction might sort it out, but the generated ASM contains the cmp every time so there's no compiler optimisation breaking the method into two and preselecting which to use. I didn't run a performance test, though, so it might be OK.
    I tried swapping behaviours in with a Func behind MoveNext() which pointed to named methods (lambdas in structs can't reference instance members), but while the enumerator worked in that it iterated the right number of times, the value in the foreach loop remained 0 which is pretty odd. As if either the value was cached, or copied and different copies used inside and outside the enumerator.
    What did work was creating an interface with Current and MoveNext, and a static method (yes, interfaces can have static methods!) to get one of two specific implementations (as structs, not ref structs). Structs implementing interfaces can have performance implications with boxing if the structs are cast to and from the interface, but the fact that foreach loops only require Current and MoveNext to exist, and don't depend on IEnumerator, indicates that it's unlikely to be an issue.

  • @josephizang6187
    @josephizang6187 Рік тому

    OMG, Nick this is awesome. Thank you.

  • @ermancetn
    @ermancetn Рік тому

    Probably i will not use this technique, but i liked the way how you elegantly implemented it.

  • @KazLA
    @KazLA Рік тому

    thanks 🙏 Nick!

  • @alirezanet
    @alirezanet Рік тому +3

    Great trick! I think we should open an issue in c# repo to support this internally, would be great feature

  • @Kingside88
    @Kingside88 Рік тому +3

    Yes I like it and would love to see it in C# itself

  • @Kommentierer
    @Kommentierer Рік тому +1

    This is actually super cool. Greetings from kotlin, every language has its nice feature we miss elsewhere.

  • @KeithOlson
    @KeithOlson Рік тому

    I learned a trick in the '80s that I still use today: instead of using 'i'/'j'/etc. for your loops, use 'ii'/'jj'/etc. That way, any time you come across a double letter you *know* that it is a loop variable.

  • @TheMAZZTer
    @TheMAZZTer Рік тому +2

    Cool, though I wouldn't put a GetEnumerator on int. That seems a recipe for subtle bugs if you intend to iterate through an IEnumerable but accidentally grab a single int first. Normally you'd get a compiler error. So definitely should be careful with implied casts and similar tools like this.
    Plus if someone else looks at this code... for (var i in 10) ... they're not going to know wtf that is or why it even works. It is difficult to find the extension powering that. At least with the Range they can search the code for uses of the Range type to find it.
    Pretty cool but I find with foreach loops I don't tend to use normal for loops much. Even when I need the index or to put that index into a separate array, I can use LINQ .Select or .Zip to do that in a foreach (yes probably not efficient, my philosophy is to write nice code and only come back later if there's a performance need). That said I do avoid for because of the verboseness as you said so this does look tempting. Iterating over objects in a collection is usually what I am really wanting in most loops though.

  • @alfredoquintanalopez2265
    @alfredoquintanalopez2265 Рік тому

    Great!!! I will use it.

  • @Mazur_Family_Travel
    @Mazur_Family_Travel Рік тому

    I even haven’t known about syntax sugar. Nice videos, Nick! Great performance and work you are doing on your channel, thanks!

  • @beriu3512
    @beriu3512 Рік тому

    This is the type of thing that really makes me interested in C#

  • @ristopaasivirta9770
    @ristopaasivirta9770 Рік тому +1

    This looks like something Jon Skeet would have done, I love it :D

  • @chefbennyj
    @chefbennyj Рік тому

    Oh! that is just the best! Yes, let's see some numbers. Very cool

  • @matthewsheeran
    @matthewsheeran Рік тому +1

    Beautiful powerful C# that make it feel - almost - like Python! Great video Nick thankyou!!

  • @soverain
    @soverain Рік тому

    Very interesting! I'm sure there is more to do with this!

  • @sealsharp
    @sealsharp Рік тому

    Thats pretty sweet!

  • @grainfrizz
    @grainfrizz Рік тому

    This is so cool

  • @HalasterBlackmantle
    @HalasterBlackmantle Рік тому

    I loved this kind of syntax in Python. So I would use this without a second thought in C#.

  • @PhodexGames
    @PhodexGames Рік тому

    I didnt knew x..y was an actual operator in C#. Well done.

  • @hudsentech8663
    @hudsentech8663 Рік тому

    Tnx!

  • @EwertonSilveiraAuckland
    @EwertonSilveiraAuckland Рік тому

    Amazing.. mind blowing ❤👌🎉

  • @davidnguyen9065
    @davidnguyen9065 Рік тому

    Most of your us are still learning the crust of .NET, figuring out the ins and outs and the basics. But here u r extending the entire framework and diving deep into its internal source code and showing us how to rewrite parts of .NET to perform better. This is just a no-go zone for most of us

  • @figloalds
    @figloalds Рік тому +27

    6:16 I don't see any problem in going to infinity since it's an Enumerator, the user code can break out of it using some other condition, that's the user-code responsibility, it does make sense.
    Now if start is from start then maybe count from the end down would make more sense

    • @nickchapsas
      @nickchapsas  Рік тому +6

      It actually won't go into infinity the way its implemented. It will just instantly exit the loop

    • @ronsijm
      @ronsijm Рік тому +11

      @@nickchapsas I think what @Felype Rennan means is that it could make sense to make it loop infinity if no end is defined. You'd just have to write something like `foreach (var i in (5..).Where(x => x < 100))` so that a linq extension eventually breaks the looping

    • @nickchapsas
      @nickchapsas  Рік тому +7

      @@ronsijm Oh I see. Yeah it might make sense, butthere is no infinity technically since ints have a max value, so you'd need special handling for a feature that doesn't really make sense to me from a language design standpoint. It's why Kotlin itself doesn't allow it too

    • @AConversationOn
      @AConversationOn Рік тому +2

      @@nickchapsas An infinite iterator itself makes sense, so here you /could/ interpret `10..` as `10 forever`: 10,10,10...

    • @figloalds
      @figloalds Рік тому +5

      ​@@nickchapsas true. I would implement " is from end" as "Int32.MaxValue" and call it a day, because in practice no indexed loop realistically goes to infinity
      If the programmer needs something infinite then they'd be using while(true) instead, it's even faster to write and easier to read than foreach(var i in x..)
      At the same time I think it's useful for if you need (0..).Where(Predicate).Take(200)
      Where limiting the range to 200 first then applying a filter would produce an incorrect result
      This is more convenient than requiring the user code to explicitly say (0..Int32.MaxValue).Where....
      IMO

  • @joost00719
    @joost00719 Рік тому

    I used this feature to be able to await a cancellation token. Awesome stuff, feels like magic :D

  • @antonmartyniuk
    @antonmartyniuk Рік тому

    Looks interesting!

  • @SoumeshRanger111
    @SoumeshRanger111 Рік тому

    You're the most prominent C# instructor on UA-cam.

  • @stratosmav7993
    @stratosmav7993 Рік тому

    Nice!!!

  • @ziaulhasanhamim3931
    @ziaulhasanhamim3931 Рік тому +6

    If ref structs are used for enumerators foreach loops can't be used in async methods.

  • @adassko6091
    @adassko6091 Рік тому +2

    Loop like foreach (var i in 0..) actually may make sense in combination with break and yield. That's actually a cool way to write a loop from zero to "infinity" with a counter

    • @krccmsitp2884
      @krccmsitp2884 Рік тому

      I'd suggest "infinity" or "from end" would be int.MaxValue then.

  • @WillEhrendreich
    @WillEhrendreich Рік тому +2

    Nice, literally anything that's puts c# closer to f# is a win in my book.

    • @WillEhrendreich
      @WillEhrendreich Рік тому

      @@MiningForPies oh I agree, wholeheartedly, but the more c# looks and acts f#-ish, the more people will see that f# isn't intimidating, and maybe they will switch to the best dotnet language after that..

    • @Erlisch1337
      @Erlisch1337 Рік тому

      @@WillEhrendreich they already switched to C#....

  • @jonathanperis3600
    @jonathanperis3600 Рік тому +2

    Please add a PR for this be included on C# 12!

  • @dcuccia
    @dcuccia Рік тому

    I've wanted more duck typing for numerics for ages - this is an awesome capability. Replacing Enumerable.Range(...) will go a long way to having functional code look a lot more functional, and quite competitive with Python, Matlab and Ruby for expressiveness. And with the new static abstract interfaces, I'm actually looking forward to building custom Span iterators over large multi-dimensional datasets (across different axes). Thank you Nick!!

  • @WillFuqua1987
    @WillFuqua1987 Рік тому

    A similarly cool "language hack" that's been possible for ages is using the "Add" extension method to implement the JavaScript and Kotlin "spread" behavior for lists, to support syntax like: new List { "a", "b", nestedListOfString };

  • @davidjsutherland
    @davidjsutherland Рік тому

    That was fun.

  • @matsnord4092
    @matsnord4092 Рік тому

    I'm not a c# programmer, have been mostly working with perl, python, js and java. It feels like home for me.

  • @ChristopherSalisburySalz
    @ChristopherSalisburySalz Рік тому +2

    I would use it in a personal project for sure. I'm not sure about work. Probably be fine for work because we create extension methods for things from time to time so it's really not any different than that.

  • @CraigBoland
    @CraigBoland Рік тому +4

    I like the terse syntax and would use this. However, most of the looping in my applications is iterating over a collection, so 'foreach(var item in items)' is my typical pattern.

  • @user-nh8vd4nv5t
    @user-nh8vd4nv5t Рік тому +5

    Reminds me of overflowing c++ code with macros where everything looks cool but you don't understand how it works anymore without reverse engineering them back to normal code

    • @reecenoone3113
      @reecenoone3113 Рік тому

      I’m always in two minds about macros. Easy refactoring, terrible readability

    • @NoGamer256
      @NoGamer256 Рік тому +2

      So in Kotlin it is cool cause you can't find out how it works easily. In C# it is bad cause you have to write it yourself. Makes sense.

    • @user-nh8vd4nv5t
      @user-nh8vd4nv5t Рік тому +1

      @@NoGamer256 Its cool for Kotlin because its Kotlin syntax, its bad for C# because its Kotlin syntax.

  • @charles_kuperus
    @charles_kuperus Рік тому

    Wow. This is damn awesome.

  • @KerchumA222
    @KerchumA222 Рік тому

    Hey Nick, I would be interested to see if you know of any use cases for the other duck typings in c# (await for example).

  • @doge9203
    @doge9203 Рік тому

    bruh, this is magic

  • @0xfded
    @0xfded Рік тому +2

    Another slight drawback is Range does not support negative numbers, so you can't do -5..5 as you can in Kotlin. It should have been called IndexRange as it's designed to support index ranges rather than value ranges.
    Still a cool hack if you're ok with non-negative ranges.

    • @billy65bob
      @billy65bob Рік тому +2

      You actually can.
      e.g. foreach(var i in ^10..0) { } will go from -10 to 0.
      You'll need this version of the ref struct though.
      public ref struct RangeEnumerator
      {
      private int _current;
      private readonly int _end;
      private readonly bool _forward;
      public RangeEnumerator(Range range)
      {
      _current = range.Start.IsFromEnd ? -range.Start.Value : range.Start.Value;
      _end = range.End.IsFromEnd ? -range.End.Value : range.End.Value;
      _forward = _end >= _current;
      if (_forward) _current--;
      else _current++;
      }
      public readonly int Current => _current;
      public bool MoveNext() => _forward ? ((++_current) = _end);
      }

    • @0xfded
      @0xfded Рік тому

      @@billy65bob Thanks! I didn't think about the ^ operator. And that's some tight code, very impressive.

  • @ZeroSleap
    @ZeroSleap Рік тому

    I am a stickler for having the rigid syntax of a for loop usually.But i am in love with this extension,seriously thinking of adding it to my projects.But the only concern would be for other people to understand or even run my code if they dont have this extension method.

  • @diadetediotedio6918
    @diadetediotedio6918 Рік тому +1

    I really like this syntax. I had seen for some time that it was possible to make conventional arrays support destructuring through extension methods as well (to support a more functional way of dealing with arrays, without having to use Spans [which work very well for that too]), it's interesting see the breadth that you can take this.

  • @filipweisser2634
    @filipweisser2634 Рік тому +2

    Note that in func programing you can see even x.. (to infinity lazy) and its valid use case where you can stop the loop in the inner implementation.

    • @DryBones111
      @DryBones111 Рік тому

      Although if its lazy, you're not really stopping a loop, you're just finished grabbing values from the iterator :)

  • @jebarcha
    @jebarcha Рік тому

    Hi. Is there a coupon code for your courses? Thanks.

  • @CambleDCS
    @CambleDCS Рік тому

    Big fan of extension methods in general and this is really nice!

  • @Rovsau
    @Rovsau Рік тому

    I think testing would need to be done with multiple types and scenarios, to see if and when it makes sense to use it.
    If it is actually overall performant on large collections, it could at least be used to write faster and more readable code at the same time.
    Though, if a beginner adopts this, I imagine it may be difficult to receive help debugging.
    If readability is the primary goal, is there a way to make a Loop() method for all types of collections?

  • @Galakyllz
    @Galakyllz Рік тому

    I can imagine making extension methods for tuples of specific types.
    ex: Tuple contains my repository class (which implements a generic "get all" method) and the total number of records to return
    ex: Tuple contains my API endpoint (Uri) and JSON data (Object) which returns an array of JSON objects serialized to type T
    That said, it's probably best to just create custom classes for each of these and implement IEnumerable, but the possibilities are interesting to think about.

  • @QwDragon
    @QwDragon Рік тому +6

    It's very cool, but I think that the normal loop seems better.

  • @yuGesreveR
    @yuGesreveR Рік тому +2

    Actually, this is the first time when I see, that the duck typing in foreach loops can be really useful. I've never thought about ranges in such a context. This is really an elegant approach👍

    • @BillieJoe512
      @BillieJoe512 Рік тому

      I never knew this was possible! I always thought a class needs to implement IEnumerable to be used in a foreach loop. as for the feature itself, I think I feel about it similar to Unity's coroutine System: I'm not sure if it is a perversion of existing features or just brilliantly elegant.

  • @zacky7862
    @zacky7862 Рік тому

    Thank you for this great tips.
    Could you please tell me how about to return as IEnumerable instead of int?
    Because I wanna use this extension for converting range of integer to List
    var listLong = Enumerable.Range(0, 1000).Select(x => (long)x);
    How I can do that with your range method?
    I did a benchmark and this is the result:
    test1: Enumerable.Range(0, 1000).Select(x => (long)x)
    test2:
    var l = new List();
    foreach(var i in ..1000)
    l.Add(Convert.ToInt64(i));
    test1:
    mean: 68.50 ns
    allocated: 88 B
    test2:
    mean: 6,937.60 ns
    allocated: 16600 B

  • @jeanmartin3256
    @jeanmartin3256 Рік тому

    Nice, I just like to know in which version it's supported ! Thanks

  • @LukeVilent
    @LukeVilent Рік тому

    By necessity, I work on python for the last few years, and I'm kinda used to python loops and find them elegant. But I see languages converge on something that is just easy to write and read, and it's lovely to see C#, my most loved language, to go yet one more step in this direction.

  • @void_star_void
    @void_star_void Рік тому

    Hey Nick thanks for the video. You also coding in kotlin or just interested in other languages 😁

  • @kvloover
    @kvloover Рік тому

    doing things like this is one of the funnest things to do in programming, but all my coworkers hate me when I do :D

  • @TheSimonDavidson
    @TheSimonDavidson Рік тому +5

    I do really like the syntax but would you have any concern about a fresh developer coming onto a project that implements this? If the extensions do have custom implementations that may not be obvious, it would be very easy for a new developer to miss that for something that should just be a basic loop.

    • @nickchapsas
      @nickchapsas  Рік тому +8

      The same concern I have when senior developers get exposed to new C# features

    • @TheSimonDavidson
      @TheSimonDavidson Рік тому +1

      I think my concern is more that the implementation is in the extension. Depending on who has written it, it could be inclusive or exclusive. I still consider myself a relatively new developer and while this syntax is easily readable, hiding the actual mechanics of it away in an extension class could cause confusion down the line if they then try to use it elsewhere. I guess it's making sure there is decent onboarding to new devs to show them, this ISN'T standard functionality, this is how it works in OUR project.

  • @RamirodeSouza
    @RamirodeSouza Рік тому

    Is the WHILE loop still used/useful? Between the FOR and FOREACH it feels kind of dead.

  • @PierreGadea
    @PierreGadea 9 місяців тому

    I saw a benchmark where Exists was faster than Any. Do you know the reason? I can't find any material on the subject so might make for a good video.

  • @AndrewJonkers
    @AndrewJonkers Рік тому +1

    I would love this usage to be available, even as a C# feature. HOWEVER a big caveat for C#: Implementing anything other than what the current Range operator allows will just confuse code intent. That is start..end must be inclusive of start and exclusive of end. So 0..3 has indexes 0,1,2. This is just an implicit unchangeable fact of life for C#.

  • @jonasex3001
    @jonasex3001 Рік тому

    It could make sense to use till the end, the user can always exit the loop on whatever condition

  • @dennycrane2938
    @dennycrane2938 Рік тому

    Yeah you can do this type of duck typing to create custom Task classes too, to mimic how Java/Android used to do them. Same way middleware works in asp.

  • @Michal_Peterka
    @Michal_Peterka Рік тому

    Is it possible to implement "=>" for foreach loop?
    F.e.
    foreach(var element in elements) => element.doSomething();

  • @2947jasmine
    @2947jasmine Рік тому

    To avoid the conventional for loop, we are creating an extensions class & getenumerator method. Thus we are making our for loop more consize and readable/presentable. Please let me know what other benefits can we get through this method. I am learning, please correct me if I got this wrong

  • @andytroo
    @andytroo Рік тому

    how does that work with JIT optimization and bounds checking? - would the excess complexity stop some of the optimization potential?

    • @nickchapsas
      @nickchapsas  Рік тому

      As you can see in the benchmarks, which include JIT optimisation, there isn’t any meaningful difference

  • @RomainLagrange1
    @RomainLagrange1 Рік тому +2

    Why MS didn't make Range enumerable in the first place ?

  • @lyrion0815
    @lyrion0815 Рік тому

    Thats an creative way of implementing it. I somewhere saw how you can implement an extension that makes it possible to write "await TimeSpan.FromSeconds(3)" or even "await 3" by making an extension method on int like this
    public static TaskAwaiter GetAwaiter(this int millis)
    => return Task.Delay(millis*1000).GetAwaiter();

  • @TheDiggidee
    @TheDiggidee Рік тому

    What library do you use for the Benchmarks please buddy?

  • @ianrussell877
    @ianrussell877 Рік тому

    F# has had this functionality in the core language for many years.

  • @stevepettifer4896
    @stevepettifer4896 Рік тому

    Elegant? Yes, and a very cool experiment. But would I use it? Probably not. It doesn't really save anything except a few keystrokes and unless your loops routinely deal with larger ranges then there is a performance penalty, albeit a very small one which may or may not add up to something more significant (YMMV of course). And even if you use larger ranges all the time, it's performance neutral and still confers no tangible benefit. Someone else made the point about it being 'unexpected' code and needing maintaining and documenting, and not being junior friendly and I think those are very valid and underrated points. If you are prepared to invest that time and effort and don't mind the extra cognitive load for juniors, albeit a small one but again these things add up, then I guess you could go for it for the sake of elegance but it feels like this is better held up as a practical explanation/example of duck typing than something to use generally.

  • @xlerb2286
    @xlerb2286 Рік тому

    I'd perhaps use it in code I owned if I had a lot of for() loops I was dealing with. But I'd be cautious about using it in a team setting. The team would have to agree that it was an extension with a value that exceeded the potential cost of requiring the knowledge that this extension was present, how it worked, and any limitations the implementation may have. For example are the ranges inclusive or exclusive, are descending ranges supported, does it just work with ints or can you use enums, etc. Is usage of this required, recommended, or developer preference? Who maintains that code and how is the team notified if there are any changes made to it that affect behavior? So another words, the same as any other component you consider taking on as a dependency 🙂