Adding a BETTER way to loop in C#

Поделиться
HTML-код
  • Опубликовано: 16 янв 2025

Комментарии • 294

  • @nickchapsas
    @nickchapsas  2 года назад +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 2 года назад +6

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

    • @mau-nguyen-van
      @mau-nguyen-van 2 года назад

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

    • @vincentjacquet2927
      @vincentjacquet2927 2 года назад +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 2 года назад +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 2 года назад +13

      @@mau-nguyen-van 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))"

  • @DryBones111
    @DryBones111 2 года назад +34

    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.

  • @11r3start11
    @11r3start11 2 года назад +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.

    •  2 года назад +19

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

    • @neociber24
      @neociber24 2 года назад +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 2 года назад +7

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

    • @phizc
      @phizc 2 года назад

      @@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 2 года назад

      @@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 2 года назад +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.

  • @KevinInPhoenix
    @KevinInPhoenix 2 года назад +61

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

    • @42069_
      @42069_ 2 года назад +1

      hahahahahhaahaa

    • @cheebadigga4092
      @cheebadigga4092 2 года назад +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 2 года назад

      This is what we call a programmer move :^)

    • @Dimich1993
      @Dimich1993 2 года назад

      true

  • @thinker2273
    @thinker2273 2 года назад +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 2 года назад

      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.

  • @Jacobhay09
    @Jacobhay09 2 года назад +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 2 года назад +1

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

  • @ignaziomessina69
    @ignaziomessina69 2 года назад +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

  • @dimasveliz6745
    @dimasveliz6745 2 года назад +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!

  • @R.Daneel
    @R.Daneel 2 года назад +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.

  • @Denominus
    @Denominus 2 года назад +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 2 года назад +1

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

  • @TheSilent333
    @TheSilent333 2 года назад

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

  • @pw.70
    @pw.70 2 года назад

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

  • @TheMAZZTer
    @TheMAZZTer 2 года назад +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.

  • @Kommentierer
    @Kommentierer 2 года назад +1

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

  • @maskettaman1488
    @maskettaman1488 2 года назад +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

  • @figloalds
    @figloalds 2 года назад +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  2 года назад +6

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

    • @ronsijm
      @ronsijm 2 года назад +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  2 года назад +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 года назад +2

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

    • @figloalds
      @figloalds 2 года назад +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

  • @carldaniel6510
    @carldaniel6510 2 года назад +1

    Neat truck! I will absolutely use this.

  • @maaadkat
    @maaadkat 2 года назад

    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.

  • @Spherous
    @Spherous 2 года назад

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

  • @anaselhassani2545
    @anaselhassani2545 2 года назад

    Worked , thanks a lot!

  • @alisonhj
    @alisonhj 2 года назад

    I would use it, very elegant, congrats!

  • @owns3
    @owns3 2 года назад

    power of extensions - love it

  • @Kingside88
    @Kingside88 2 года назад +3

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

  • @davidnguyen9065
    @davidnguyen9065 2 года назад

    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

  • @alirezanet
    @alirezanet 2 года назад +3

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

  • @pritishranjan
    @pritishranjan 2 года назад +2

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

  • @matthewsheeran
    @matthewsheeran 2 года назад +1

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

  • @KazLA
    @KazLA 2 года назад

    thanks 🙏 Nick!

  • @0xfded
    @0xfded 2 года назад +3

    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 года назад +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 2 года назад

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

  • @renatogolia211
    @renatogolia211 2 года назад +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.

  • @adassko6091
    @adassko6091 2 года назад +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 2 года назад

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

  • @vuquy711
    @vuquy711 2 года назад

    Awesome, Nick. I really love your videos!

  • @josephizang6187
    @josephizang6187 2 года назад

    OMG, Nick this is awesome. Thank you.

  • @KeithOlson
    @KeithOlson 2 года назад

    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.

  • @parkercrofts6210
    @parkercrofts6210 2 года назад

    Wow thank you so much that really helped

  • @kylekeenan3485
    @kylekeenan3485 2 года назад +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.

  • @gui.ferreira
    @gui.ferreira 2 года назад

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

  • @alfredoquintanalopez2265
    @alfredoquintanalopez2265 2 года назад

    Great!!! I will use it.

  • @WillFuqua1987
    @WillFuqua1987 2 года назад

    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 };

  • @nekuskus5218
    @nekuskus5218 2 года назад

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

  • @zhh174
    @zhh174 2 года назад +6

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

  • @RomainLagrange1
    @RomainLagrange1 2 года назад +2

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

  • @Galakyllz
    @Galakyllz 2 года назад

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

  • @ermancetn
    @ermancetn 2 года назад

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

  • @SoumeshRanger111
    @SoumeshRanger111 2 года назад

    You're the most prominent C# instructor on RUclips.

  • @joost00719
    @joost00719 2 года назад

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

  • @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.

  • @sealsharp
    @sealsharp 2 года назад

    Thats pretty sweet!

  • @chefbennyj
    @chefbennyj 2 года назад

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

  • @Mazur_Family_Travel
    @Mazur_Family_Travel 2 года назад

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

  • @CraigBoland
    @CraigBoland 2 года назад +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.

  • @filipweisser2634
    @filipweisser2634 2 года назад +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 2 года назад

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

  • @antonmartyniuk
    @antonmartyniuk 2 года назад

    Looks interesting!

  • @TheSimonDavidson
    @TheSimonDavidson 2 года назад +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  2 года назад +8

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

    • @TheSimonDavidson
      @TheSimonDavidson 2 года назад +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.

  • @EwertonSilveiraAuckland
    @EwertonSilveiraAuckland 2 года назад

    Amazing.. mind blowing ❤👌🎉

  • @ВасилийКабанчиков
    @ВасилийКабанчиков 2 года назад +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

    • @NoGamer256
      @NoGamer256 2 года назад +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.

    • @ВасилийКабанчиков
      @ВасилийКабанчиков 2 года назад +1

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

  • @ristopaasivirta9770
    @ristopaasivirta9770 2 года назад +1

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

  • @LeMustache
    @LeMustache 2 года назад +10

    I wonder why ranges don't implement IEnumerable by default. Are they planning on adding that?

    • @lordicemaniac
      @lordicemaniac 2 года назад

      but what would be increment?

    • @LeMustache
      @LeMustache 2 года назад

      @@lordicemaniac I'm not sure what you're asking

    • @lordicemaniac
      @lordicemaniac 2 года назад

      @@LeMustache range 1..10, should it increment by 1, 2, 5, 10?

    • @LeMustache
      @LeMustache 2 года назад

      @@lordicemaniac I think it's pretty obvious I'm talking about an implementation that's very close to what Nick shows in this video

  • @ZeroSleap
    @ZeroSleap 2 года назад

    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.

  • @ChristopherSalisburySalz
    @ChristopherSalisburySalz 2 года назад +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.

  • @beriu3512
    @beriu3512 2 года назад

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

  • @jebarcha
    @jebarcha 2 года назад

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

  • @jonathanperis3600
    @jonathanperis3600 2 года назад +2

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

  • @jeanmartin3256
    @jeanmartin3256 2 года назад

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

  • @davidjsutherland
    @davidjsutherland 2 года назад

    That was fun.

  • @WillEhrendreich
    @WillEhrendreich 2 года назад +1

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

    • @WillEhrendreich
      @WillEhrendreich 2 года назад

      @@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 2 года назад

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

  • @grainfrizz
    @grainfrizz 2 года назад

    This is so cool

  • @matsnord4092
    @matsnord4092 2 года назад

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

  • @dcuccia
    @dcuccia 2 года назад

    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!!

  • @AndreaLanfranchi
    @AndreaLanfranchi 4 месяца назад

    What if the iterating var is unsigned ? It needs a bit of knob polishing to check next on first iter.

  • @HalasterBlackmantle
    @HalasterBlackmantle 2 года назад

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

  • @2947jasmine
    @2947jasmine 2 года назад

    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

  • @soverain
    @soverain 2 года назад

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

  • @zacky7862
    @zacky7862 2 года назад

    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

  • @void_star_void
    @void_star_void 2 года назад

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

  • @PhodexGames
    @PhodexGames 2 года назад

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

  • @Galakyllz
    @Galakyllz 2 года назад

    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.

  • @KerchumA222
    @KerchumA222 2 года назад

    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).

  • @RamirodeSouza
    @RamirodeSouza 2 года назад

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

  • @doge9203
    @doge9203 2 года назад

    bruh, this is magic

  • @zORg_alex
    @zORg_alex 2 года назад

    Awesome. Not sure though if unity supports ranges.

  • @TheDiggidee
    @TheDiggidee 2 года назад

    What library do you use for the Benchmarks please buddy?

  • @yuGesreveR
    @yuGesreveR 2 года назад +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 2 года назад

      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.

  • @PierreGadea
    @PierreGadea Год назад

    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.

  • @dennycrane2938
    @dennycrane2938 2 года назад

    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.

  • @hudsentech8663
    @hudsentech8663 2 года назад

    Tnx!

  • @andytroo
    @andytroo 2 года назад

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

    • @nickchapsas
      @nickchapsas  2 года назад

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

  • @Rovsau
    @Rovsau 2 года назад

    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?

  • @charles_kuperus
    @charles_kuperus 2 года назад

    Wow. This is damn awesome.

  • @Neonalig
    @Neonalig 2 года назад +1

    You mentioned that C# supports Duck Typing, and showed that you only need to implement the methods for the struct to be considered a valid enumerator. However, is there any downfall to actually implementing IEnumerable/IEnumerator on the struct if it helps increase general readability? (At least for me, implementing from those interfaces shows intent, if nothing else).
    Edit: For those wondering the reason why, as highlighted by the helpful people in the comments, it's because Nick used a *ref* struct, which doesn't allow for implementation of interfaces.

    • @phizc
      @phizc 2 года назад +2

      He was using a ref struct, and those can't implement interfaces. With a normal struct you're probably right.. though I'm not 100% sure it wouldn't get boxed.
      In any case, it wouldn't make any sense to use the CustomRangeEnumerator anywhere but in a foreach, and there you wouldn't even see the type since it isn't exposed anywhere.

    • @Neonalig
      @Neonalig 2 года назад +2

      @@phizc Ah I see, that makes sense! Apologies, I've used structs before, but never ref structs.

    • @billy65bob
      @billy65bob 2 года назад +1

      It's a ref struct, and ref structs don't support inheritance of any sort, even of interfaces.

  • @ianrussell877
    @ianrussell877 2 года назад

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

  • @Michal_Peterka
    @Michal_Peterka 2 года назад

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

  • @stratosmav7993
    @stratosmav7993 2 года назад

    Nice!!!

  • @QwDragon
    @QwDragon 2 года назад +6

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

  • @lyrion0815
    @lyrion0815 2 года назад

    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();

  • @LordErnie
    @LordErnie 2 года назад +1

    Ah yes, the old C# 1.1 when we didn't have generics yet. God I love these relics from the past.

  • @kvloover
    @kvloover 2 года назад

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

  • @vincentjacquet2927
    @vincentjacquet2927 2 года назад +1

    This is a nice trick but this is it, just a trick. Compared to a regular for loop, there are many shortcomings: it does not support negative indexes nor stride other than 1 (or -1 if you support decreasing ranges). Also, in c#, a range 0..10 stops at 9. With the .. syntax, Kotlin ranges are closed whereas c# ranges are open-ended.
    And BTW, instead of throwing an exception, you could support "From End" indexes if you get the offset with a length of int.MaxValue, instead of getting the value.

    • @billy65bob
      @billy65bob 2 года назад

      You could also use 'from end' to fix one of the shortcomings; specifically the lack of negatives. :)

  • @AndrewJonkers
    @AndrewJonkers 2 года назад +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#.