Finding MinMax values and returning a tuple as a result

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
5
down vote

favorite












I was coding some tooling stuff when I started to ponder whether the best return type for a Range / MinMax method applied on a IEnumerable method.



I am using the value the C# 7 Tuples like below, but tempted to create my own class with readonly fields.



 public static (TSource Min, TSource Max) MinMax<TSource>(this IEnumerable<TSource> source, IComparer<TSource> comparer)

using (var sourceIterator = source.GetEnumerator())

if (!sourceIterator.MoveNext())

throw new InvalidOperationException("Sequence contains no elements");


var max = sourceIterator.Current;
var min = sourceIterator.Current;

while (sourceIterator.MoveNext())

var candidate = sourceIterator.Current;

if (comparer.LeftStrictlyLesserThanRight(candidate, min))

min = candidate;


if (comparer.LeftStrictlyGreaterThanRight(candidate, max))

max = candidate;



return (min, max);




Utilities are defined as below:



internal static class ComparerExtensions

public static bool LeftStrictlyGreaterThanRight<T>(this IComparer<T> comparer, T left, T right)

return comparer.Compare(left, right) > 0;

public static bool LeftStrictlyLesserThanRight<T>(this IComparer<T> comparer, T left, T right)

return comparer.Compare(left, right) < 0;




What do you think is the best, knowing that creating a reference type would bring some additional allocations and GC work (I mean that was the whole point to have struct-like tuples in C# 7). What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.



I don't know maybe it's just me and my over-defensive coding style and bad experience using Python where coders are considered as "adults"?







share|improve this question

















  • 3




    LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.
    – t3chb0t
    Apr 14 at 22:23










  • I'm not sure why you're only considering (value) tuples and classes? An immutable result without extra allocations sounds like a struct with readonly fields to me.
    – Pieter Witvoet
    Apr 14 at 22:47










  • @PieterWitvoet agreed, always wondering why MS didn't vote for a read-only (value type) tuples
    – Ehouarn Perret
    Apr 14 at 22:49










  • @t3chb0t hm alright will change that, thanks!
    – Ehouarn Perret
    Apr 14 at 22:49
















up vote
5
down vote

favorite












I was coding some tooling stuff when I started to ponder whether the best return type for a Range / MinMax method applied on a IEnumerable method.



I am using the value the C# 7 Tuples like below, but tempted to create my own class with readonly fields.



 public static (TSource Min, TSource Max) MinMax<TSource>(this IEnumerable<TSource> source, IComparer<TSource> comparer)

using (var sourceIterator = source.GetEnumerator())

if (!sourceIterator.MoveNext())

throw new InvalidOperationException("Sequence contains no elements");


var max = sourceIterator.Current;
var min = sourceIterator.Current;

while (sourceIterator.MoveNext())

var candidate = sourceIterator.Current;

if (comparer.LeftStrictlyLesserThanRight(candidate, min))

min = candidate;


if (comparer.LeftStrictlyGreaterThanRight(candidate, max))

max = candidate;



return (min, max);




Utilities are defined as below:



internal static class ComparerExtensions

public static bool LeftStrictlyGreaterThanRight<T>(this IComparer<T> comparer, T left, T right)

return comparer.Compare(left, right) > 0;

public static bool LeftStrictlyLesserThanRight<T>(this IComparer<T> comparer, T left, T right)

return comparer.Compare(left, right) < 0;




What do you think is the best, knowing that creating a reference type would bring some additional allocations and GC work (I mean that was the whole point to have struct-like tuples in C# 7). What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.



I don't know maybe it's just me and my over-defensive coding style and bad experience using Python where coders are considered as "adults"?







share|improve this question

















  • 3




    LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.
    – t3chb0t
    Apr 14 at 22:23










  • I'm not sure why you're only considering (value) tuples and classes? An immutable result without extra allocations sounds like a struct with readonly fields to me.
    – Pieter Witvoet
    Apr 14 at 22:47










  • @PieterWitvoet agreed, always wondering why MS didn't vote for a read-only (value type) tuples
    – Ehouarn Perret
    Apr 14 at 22:49










  • @t3chb0t hm alright will change that, thanks!
    – Ehouarn Perret
    Apr 14 at 22:49












up vote
5
down vote

favorite









up vote
5
down vote

favorite











I was coding some tooling stuff when I started to ponder whether the best return type for a Range / MinMax method applied on a IEnumerable method.



I am using the value the C# 7 Tuples like below, but tempted to create my own class with readonly fields.



 public static (TSource Min, TSource Max) MinMax<TSource>(this IEnumerable<TSource> source, IComparer<TSource> comparer)

using (var sourceIterator = source.GetEnumerator())

if (!sourceIterator.MoveNext())

throw new InvalidOperationException("Sequence contains no elements");


var max = sourceIterator.Current;
var min = sourceIterator.Current;

while (sourceIterator.MoveNext())

var candidate = sourceIterator.Current;

if (comparer.LeftStrictlyLesserThanRight(candidate, min))

min = candidate;


if (comparer.LeftStrictlyGreaterThanRight(candidate, max))

max = candidate;



return (min, max);




Utilities are defined as below:



internal static class ComparerExtensions

public static bool LeftStrictlyGreaterThanRight<T>(this IComparer<T> comparer, T left, T right)

return comparer.Compare(left, right) > 0;

public static bool LeftStrictlyLesserThanRight<T>(this IComparer<T> comparer, T left, T right)

return comparer.Compare(left, right) < 0;




What do you think is the best, knowing that creating a reference type would bring some additional allocations and GC work (I mean that was the whole point to have struct-like tuples in C# 7). What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.



I don't know maybe it's just me and my over-defensive coding style and bad experience using Python where coders are considered as "adults"?







share|improve this question













I was coding some tooling stuff when I started to ponder whether the best return type for a Range / MinMax method applied on a IEnumerable method.



I am using the value the C# 7 Tuples like below, but tempted to create my own class with readonly fields.



 public static (TSource Min, TSource Max) MinMax<TSource>(this IEnumerable<TSource> source, IComparer<TSource> comparer)

using (var sourceIterator = source.GetEnumerator())

if (!sourceIterator.MoveNext())

throw new InvalidOperationException("Sequence contains no elements");


var max = sourceIterator.Current;
var min = sourceIterator.Current;

while (sourceIterator.MoveNext())

var candidate = sourceIterator.Current;

if (comparer.LeftStrictlyLesserThanRight(candidate, min))

min = candidate;


if (comparer.LeftStrictlyGreaterThanRight(candidate, max))

max = candidate;



return (min, max);




Utilities are defined as below:



internal static class ComparerExtensions

public static bool LeftStrictlyGreaterThanRight<T>(this IComparer<T> comparer, T left, T right)

return comparer.Compare(left, right) > 0;

public static bool LeftStrictlyLesserThanRight<T>(this IComparer<T> comparer, T left, T right)

return comparer.Compare(left, right) < 0;




What do you think is the best, knowing that creating a reference type would bring some additional allocations and GC work (I mean that was the whole point to have struct-like tuples in C# 7). What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.



I don't know maybe it's just me and my over-defensive coding style and bad experience using Python where coders are considered as "adults"?









share|improve this question












share|improve this question




share|improve this question








edited Apr 15 at 10:18









t3chb0t

32k54195




32k54195









asked Apr 14 at 21:47









Ehouarn Perret

1857




1857







  • 3




    LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.
    – t3chb0t
    Apr 14 at 22:23










  • I'm not sure why you're only considering (value) tuples and classes? An immutable result without extra allocations sounds like a struct with readonly fields to me.
    – Pieter Witvoet
    Apr 14 at 22:47










  • @PieterWitvoet agreed, always wondering why MS didn't vote for a read-only (value type) tuples
    – Ehouarn Perret
    Apr 14 at 22:49










  • @t3chb0t hm alright will change that, thanks!
    – Ehouarn Perret
    Apr 14 at 22:49












  • 3




    LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.
    – t3chb0t
    Apr 14 at 22:23










  • I'm not sure why you're only considering (value) tuples and classes? An immutable result without extra allocations sounds like a struct with readonly fields to me.
    – Pieter Witvoet
    Apr 14 at 22:47










  • @PieterWitvoet agreed, always wondering why MS didn't vote for a read-only (value type) tuples
    – Ehouarn Perret
    Apr 14 at 22:49










  • @t3chb0t hm alright will change that, thanks!
    – Ehouarn Perret
    Apr 14 at 22:49







3




3




LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.
– t3chb0t
Apr 14 at 22:23




LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.
– t3chb0t
Apr 14 at 22:23












I'm not sure why you're only considering (value) tuples and classes? An immutable result without extra allocations sounds like a struct with readonly fields to me.
– Pieter Witvoet
Apr 14 at 22:47




I'm not sure why you're only considering (value) tuples and classes? An immutable result without extra allocations sounds like a struct with readonly fields to me.
– Pieter Witvoet
Apr 14 at 22:47












@PieterWitvoet agreed, always wondering why MS didn't vote for a read-only (value type) tuples
– Ehouarn Perret
Apr 14 at 22:49




@PieterWitvoet agreed, always wondering why MS didn't vote for a read-only (value type) tuples
– Ehouarn Perret
Apr 14 at 22:49












@t3chb0t hm alright will change that, thanks!
– Ehouarn Perret
Apr 14 at 22:49




@t3chb0t hm alright will change that, thanks!
– Ehouarn Perret
Apr 14 at 22:49










2 Answers
2






active

oldest

votes

















up vote
4
down vote



accepted











What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.




We cannot prevent everything and sometimes it's just easier and quicker to use the simplest solution like tuples in this case. You can always switch to something more complex if necessary but it's good to start by following the YAGNI principle.





I was coding some tooling stuff




It depnds on what kind of tooling stuff your are coding. If this is some tiny helper then I'd go with tuples. If I was creatng a general purpose library then and big type would be better. You could validate the parameters and make sure that min <= max etc.



As an example you can take a look at my generic Range.cs that is supported by expressions to be able to work with any comparable type BinaryOperation.cs.




Regarding your ComparerExtensions I start with what I already said in my comment: LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.



I also find the extensions are not intuitive. They should be extensions on the T and not on the comparer like that:



x.LessThen(y)


and/or



x.LessThen(y, comparer)


It's more natural (and shorter) to write than




comparer.LeftLessThenRight(x, y)




This means you can create two pairs of these extensions for each operation.



public static bool LessThen<T>(this T x, T y) where T : IComparable<T>
public static bool LessThen<T>(this T x, T y, IComparer<T> comparer)


one that uses the interface IComparable implemented by T and the other one that uses a custom comparer.






share|improve this answer























  • Thanks for the guidelines, really well appreciated! I thought about that too, I mean switching to an extension method for <T> and putting the comparer as the last parameter, more natural as you said. Funny that you mentioned the Range class even though in my case I already have one with iteration options and intersection check with others ranges but I got the gist. Thanks again!
    – Ehouarn Perret
    Apr 15 at 14:29


















up vote
1
down vote













Can use else if on the second



I do not like the name LeftStrictlyLesserThanRight but you could just use that and flop the candidate, max for LeftStrictlyLesserThanRight.






share|improve this answer























    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192068%2ffinding-minmax-values-and-returning-a-tuple-as-a-result%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    4
    down vote



    accepted











    What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.




    We cannot prevent everything and sometimes it's just easier and quicker to use the simplest solution like tuples in this case. You can always switch to something more complex if necessary but it's good to start by following the YAGNI principle.





    I was coding some tooling stuff




    It depnds on what kind of tooling stuff your are coding. If this is some tiny helper then I'd go with tuples. If I was creatng a general purpose library then and big type would be better. You could validate the parameters and make sure that min <= max etc.



    As an example you can take a look at my generic Range.cs that is supported by expressions to be able to work with any comparable type BinaryOperation.cs.




    Regarding your ComparerExtensions I start with what I already said in my comment: LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.



    I also find the extensions are not intuitive. They should be extensions on the T and not on the comparer like that:



    x.LessThen(y)


    and/or



    x.LessThen(y, comparer)


    It's more natural (and shorter) to write than




    comparer.LeftLessThenRight(x, y)




    This means you can create two pairs of these extensions for each operation.



    public static bool LessThen<T>(this T x, T y) where T : IComparable<T>
    public static bool LessThen<T>(this T x, T y, IComparer<T> comparer)


    one that uses the interface IComparable implemented by T and the other one that uses a custom comparer.






    share|improve this answer























    • Thanks for the guidelines, really well appreciated! I thought about that too, I mean switching to an extension method for <T> and putting the comparer as the last parameter, more natural as you said. Funny that you mentioned the Range class even though in my case I already have one with iteration options and intersection check with others ranges but I got the gist. Thanks again!
      – Ehouarn Perret
      Apr 15 at 14:29















    up vote
    4
    down vote



    accepted











    What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.




    We cannot prevent everything and sometimes it's just easier and quicker to use the simplest solution like tuples in this case. You can always switch to something more complex if necessary but it's good to start by following the YAGNI principle.





    I was coding some tooling stuff




    It depnds on what kind of tooling stuff your are coding. If this is some tiny helper then I'd go with tuples. If I was creatng a general purpose library then and big type would be better. You could validate the parameters and make sure that min <= max etc.



    As an example you can take a look at my generic Range.cs that is supported by expressions to be able to work with any comparable type BinaryOperation.cs.




    Regarding your ComparerExtensions I start with what I already said in my comment: LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.



    I also find the extensions are not intuitive. They should be extensions on the T and not on the comparer like that:



    x.LessThen(y)


    and/or



    x.LessThen(y, comparer)


    It's more natural (and shorter) to write than




    comparer.LeftLessThenRight(x, y)




    This means you can create two pairs of these extensions for each operation.



    public static bool LessThen<T>(this T x, T y) where T : IComparable<T>
    public static bool LessThen<T>(this T x, T y, IComparer<T> comparer)


    one that uses the interface IComparable implemented by T and the other one that uses a custom comparer.






    share|improve this answer























    • Thanks for the guidelines, really well appreciated! I thought about that too, I mean switching to an extension method for <T> and putting the comparer as the last parameter, more natural as you said. Funny that you mentioned the Range class even though in my case I already have one with iteration options and intersection check with others ranges but I got the gist. Thanks again!
      – Ehouarn Perret
      Apr 15 at 14:29













    up vote
    4
    down vote



    accepted







    up vote
    4
    down vote



    accepted







    What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.




    We cannot prevent everything and sometimes it's just easier and quicker to use the simplest solution like tuples in this case. You can always switch to something more complex if necessary but it's good to start by following the YAGNI principle.





    I was coding some tooling stuff




    It depnds on what kind of tooling stuff your are coding. If this is some tiny helper then I'd go with tuples. If I was creatng a general purpose library then and big type would be better. You could validate the parameters and make sure that min <= max etc.



    As an example you can take a look at my generic Range.cs that is supported by expressions to be able to work with any comparable type BinaryOperation.cs.




    Regarding your ComparerExtensions I start with what I already said in my comment: LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.



    I also find the extensions are not intuitive. They should be extensions on the T and not on the comparer like that:



    x.LessThen(y)


    and/or



    x.LessThen(y, comparer)


    It's more natural (and shorter) to write than




    comparer.LeftLessThenRight(x, y)




    This means you can create two pairs of these extensions for each operation.



    public static bool LessThen<T>(this T x, T y) where T : IComparable<T>
    public static bool LessThen<T>(this T x, T y, IComparer<T> comparer)


    one that uses the interface IComparable implemented by T and the other one that uses a custom comparer.






    share|improve this answer
















    What bothers me with the tuple is that fields are not readonly and we cannot prevent users of the method to mess up and break flow.




    We cannot prevent everything and sometimes it's just easier and quicker to use the simplest solution like tuples in this case. You can always switch to something more complex if necessary but it's good to start by following the YAGNI principle.





    I was coding some tooling stuff




    It depnds on what kind of tooling stuff your are coding. If this is some tiny helper then I'd go with tuples. If I was creatng a general purpose library then and big type would be better. You could validate the parameters and make sure that min <= max etc.



    As an example you can take a look at my generic Range.cs that is supported by expressions to be able to work with any comparable type BinaryOperation.cs.




    Regarding your ComparerExtensions I start with what I already said in my comment: LeftStrictlyLesserThanRight - I think virtually all programming languages call this just less-than and its counterpart less-than-or-equal.



    I also find the extensions are not intuitive. They should be extensions on the T and not on the comparer like that:



    x.LessThen(y)


    and/or



    x.LessThen(y, comparer)


    It's more natural (and shorter) to write than




    comparer.LeftLessThenRight(x, y)




    This means you can create two pairs of these extensions for each operation.



    public static bool LessThen<T>(this T x, T y) where T : IComparable<T>
    public static bool LessThen<T>(this T x, T y, IComparer<T> comparer)


    one that uses the interface IComparable implemented by T and the other one that uses a custom comparer.







    share|improve this answer















    share|improve this answer



    share|improve this answer








    edited Apr 15 at 10:18


























    answered Apr 15 at 10:13









    t3chb0t

    32k54195




    32k54195











    • Thanks for the guidelines, really well appreciated! I thought about that too, I mean switching to an extension method for <T> and putting the comparer as the last parameter, more natural as you said. Funny that you mentioned the Range class even though in my case I already have one with iteration options and intersection check with others ranges but I got the gist. Thanks again!
      – Ehouarn Perret
      Apr 15 at 14:29

















    • Thanks for the guidelines, really well appreciated! I thought about that too, I mean switching to an extension method for <T> and putting the comparer as the last parameter, more natural as you said. Funny that you mentioned the Range class even though in my case I already have one with iteration options and intersection check with others ranges but I got the gist. Thanks again!
      – Ehouarn Perret
      Apr 15 at 14:29
















    Thanks for the guidelines, really well appreciated! I thought about that too, I mean switching to an extension method for <T> and putting the comparer as the last parameter, more natural as you said. Funny that you mentioned the Range class even though in my case I already have one with iteration options and intersection check with others ranges but I got the gist. Thanks again!
    – Ehouarn Perret
    Apr 15 at 14:29





    Thanks for the guidelines, really well appreciated! I thought about that too, I mean switching to an extension method for <T> and putting the comparer as the last parameter, more natural as you said. Funny that you mentioned the Range class even though in my case I already have one with iteration options and intersection check with others ranges but I got the gist. Thanks again!
    – Ehouarn Perret
    Apr 15 at 14:29













    up vote
    1
    down vote













    Can use else if on the second



    I do not like the name LeftStrictlyLesserThanRight but you could just use that and flop the candidate, max for LeftStrictlyLesserThanRight.






    share|improve this answer



























      up vote
      1
      down vote













      Can use else if on the second



      I do not like the name LeftStrictlyLesserThanRight but you could just use that and flop the candidate, max for LeftStrictlyLesserThanRight.






      share|improve this answer

























        up vote
        1
        down vote










        up vote
        1
        down vote









        Can use else if on the second



        I do not like the name LeftStrictlyLesserThanRight but you could just use that and flop the candidate, max for LeftStrictlyLesserThanRight.






        share|improve this answer















        Can use else if on the second



        I do not like the name LeftStrictlyLesserThanRight but you could just use that and flop the candidate, max for LeftStrictlyLesserThanRight.







        share|improve this answer















        share|improve this answer



        share|improve this answer








        edited Apr 15 at 8:48


























        answered Apr 14 at 23:32









        paparazzo

        4,8131730




        4,8131730






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192068%2ffinding-minmax-values-and-returning-a-tuple-as-a-result%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Greedy Best First Search implementation in Rust

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            C++11 CLH Lock Implementation