0

I'm trying to understand why implicit conversion in the following code causes StackOverflowException. I think it is a covariance/contravariance issue, but I cannot explain why at the moment.

Crashes NUnit:

private List<T[]> _NodesContent = new List<T[]>(); private UnrolledLinkedListBuilder<T> AddNodes(IEnumerable<T[]> nodes) { _NodesContent.AddRange(nodes); return this; } public UnrolledLinkedListBuilder<T> AddNodes(params T[][] nodes) { return AddNodes(nodes); } 

Works:

private List<T[]> _NodesContent = new List<T[]>(); private UnrolledLinkedListBuilder<T> AddNodes(IEnumerable<T[]> nodes) { _NodesContent.AddRange(nodes); return this; } public UnrolledLinkedListBuilder<T> AddNodes(params T[][] nodes) { return AddNodes((IEnumerable<T[])nodes); } 

As I understand from this answer https://stackoverflow.com/a/275107/761755 conversion should be performed implicitly. Moreover, if in the first example you directly call _NodesContent.AddRange(nodes) from AddNodes(T[][]) there will be no exception.

4
  • 1
    Because when you call AddNodes passing T[][] - best fitting overload is of course one that accepts T[][], not one that accepts IEnumerable<T[]>. It doesn't matter if it's possible to convert T[][] to IEnumerable<T[]> or not. Commented Feb 15, 2018 at 10:50
  • 1
    Why you expect that you don't get a StackOverflowException? You are passing the argument directly to the method in which you are. It would be a compiler bug if you would call a different method (overload) then. Commented Feb 15, 2018 at 10:50
  • 1
    "As I understand conversion should be performed implicitly." Sure, but a conversion will only happen if a conversion is necessary. But a conversion is not necessary. nodes is a T[][]. There is a method overload that takes a T[][] as parameter, so that one will be chosen, resulting in a stack overflow. Commented Feb 15, 2018 at 10:53
  • @Evk Thanks a lot. Now I see my mistake. Commented Feb 15, 2018 at 11:03

1 Answer 1

1

I'm trying to understand why implicit conversion in the following code causes StackOverflowException.

Well, there is no implicit conversion necessary. But isn't it obvious? Your first method calls itself because you pass the argument as it is:

public UnrolledLinkedListBuilder<T> AddNodes(params T[][] nodes) { return AddNodes(nodes); } 

It was a compiler bug if that would not cause a StackOverflowException in any case:

public SomeReturnType AnyMethod(AnyType x) { return AnyMethod(x); // StackOverflowException } 

It doesn't matter that the parameter is using params because it's not possible to have another method with the same parameter type without params because that was ambiguous. So this will always be the best candidate.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. I see my mistake now.
It was a compiler bug if that would not cause a StackOverflowException in any case Are you saying that compiler do not allowed to do tail call optimization here?
@PetSerAl: no, i just meant that it's not possible that a different method-overload is called from within a method when you pass the argument as it is(without casting). Otherwise the question arises why this method was called in the first place.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.