I just came across a (to me, inexplicable) case of mutual infinite 
recursion in my code. It was pretty well hidden among lots of cruft, so 
I've tried to minimize it. The minimal example still exhibits the behavior, 
but there are a couple of differences (I'll get back to some). Also, I'm 
sure I could have shrunk it even more, but obvious attempts all seemed to 
remove the problem (and give me a more obviously correct error message). 
Anyway, here's the code:

type B

end


type X{T}

    baz::Vector{T}

end


function foo(a, c)

    bar(b, c)

end


function bar{T}(d::(X{T}, Int), val::T)

    foo("err", d[1].baz)

end


b = B()


function test()

    bar(b, "wat")

end


test()

When run, this seems to get into an infinite recursion between foo and bar, 
where I would have (with this minimized version) have expected an error 
message of the type

*ERROR: no method bar(B, ASCIIString)*

After all, as far as I can see, no such method exists, and the call inside 
foo ought not somehow create it…?

This is what you get if you, for example, comment out the bar(b, c) call or 
replace its b argument with a local B. Note that in the original, that call 
did *not* (as far as I can tell) refer to a global variable in this way. 
Indeed, the call was inside a loop, and its first argument was the iterator 
variable. But I guess if the dispatch somehow ended up using the same 
function anyway, it doesn't matter.

Also, the test part was originally in a FactCheck context environment, and 
the currently global variable was in the enlosing facts environment. This 
worked, but if I put the call inside a for loop (which was originally, in 
fact, in a different function, in a different module), I once again got the 
same problem.

So I guess I'm asking two things: First, what am I missing here? And 
second, how can I more effectively debug stuff like this in Julia?-) (I.e., 
figure out why my methods are instantiated in ways I didn't intend, like 
here.)

Reply via email to