Is it possible to "precompile" a method with a set of argument types?

I swear i saw a macro at some point that allowed you to precompile methods. However I haven’t been able to google for it. I do find lots on compileing my whole application or compiling to an executable.

I’m trying to figure out a compilation error, but it’s inside a channel inside a callback from a 3rd party module. And to make it even better, it’s function pointer. I’ve been staring at the code and cannot figure out what the issue is and I’m hoping that compiling it outside of all the other stuff will make the error clearer.

For more details, the error is:

┌ Error: error handling request
│   exception =
│    MethodError: Cannot `convert` an object of type Array{UInt8,1} to an object of type Bool
│    Closest candidates are:
│      convert(::Type{T}, ::T) where T<:Number at number.jl:6
│      convert(::Type{T}, ::Number) where T<:Number at number.jl:7
│      convert(::Type{T}, ::Ptr) where T<:Integer at pointer.jl:23
│      ...
│    Stacktrace:
│     [1] take_unbuffered(::Channel{Union{Array{UInt8,1}, Array{String,1}}}) at ./channels.jl:418
│     [2] take! at ./channels.jl:394 [inlined]
│     [3] iterate(::Channel{Union{Array{UInt8,1}, Array{String,1}}}, ::Nothing) at ./channels.jl:460
│     [4] test(::Main.ms.var"#22#25"{Main.ms.NS,Main.ms.var"#inc_a#23",Main.ms.var"#inc_b#24"}, ::HTTP.Streams.Stream{HTTP.Messages.Request,HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}}) at /home/pixel27/julia/ms/src/test.jl:86

Line 4 is where we finally end up in my code. An example of what I’m trying to do, which works where as the real code does not is:


function queue()
    Channel{Union{Vector{String}, Vector{UInt8}}}() do ch
        put!(ch, ["a"])
        put!(ch, Vector{UInt8}([1, 2]))
        put!(ch, Vector{UInt8}([3, 4]))
        put!(ch, ["b", "c"])
        put!(ch, Vector{UInt8}([100, 200]))
        put!(ch, Vector{UInt8}([101, 201]))
    end
end

function execute(f)
    local c = nothing

    for val in queue()
        if typeof(val) == Vector{String}
            c = f(val)
        else
            if c(val) == false
                println("error")
            end
        end
    end
end

function test()
    local a = 0
    local b = 0

    function inc_a(arr::Vector{UInt8})::Bool
        for i in arr
            a += i
        end
        return a < 1000
    end

    function inc_b(arr::Vector{UInt8})::Bool
        for i in arr
            b += i
        end
        return b < 1000
    end

    execute() do names
        if names[1] == "a"
            return inc_a
        elseif names[1] == "b"
            return inc_b
        else
            return nothing
        end
    end

    println("a = $a")
    println("b = $b")
end

Translating the error to the simplified code, the error would be at line 21 which is println("error"). So my best bet is the error is the function pointer assigned to “c”. However since it appears to fail at compilation it makes it hard to figure out what “c” was pointing to and why it would be trying to convert an array to a boolean…

In my real code inc_a and inc_b are both defined to take a Vector{Uint8} and return a Bool.

It’s not. It’s a runtime error.

1 Like

But if I put a print message before that function call, it never prints.

Well, then either that function call is not where it happens (in fact, from the backtrace it is clear that it isn’t) or the output is somehow redirected (or otherwise) and you didn’t see it.

Put it another way, if this was a compilation error, which doesn’t really exist in julia, then what you are trying to figure out here, which is strictly runtime information, won’t matter at all.

Okay, then the line number reported by the stack trace is a red herring…I’m assuming the convert is happening somewhere along the stack to where it’s called. I will widen my search.

No. The error happens before the first call in the backtrace, i.e. in take_unbuffered. That’s the definition of the stack trace.

And no. The entry point from your test to the error is shown to you in the backtrace. It’s

or the iteration (loop) on the channel.

Now how other part of the code not directly in the backtrace interacts with the channel is something you need to figure out. (i.e. the producer could be what’s generating the error)

Well I “found” it…but not really. My main loop had a error check at the beginning. Basically if an error was tripped it would just empty the channel and no do anything. However the check was incorrect and always returned true. So the body of the loop would always be skipped.

Basically:

    local e = false

    for val in queue()

        if e == false
            continue
        end

        if typeof(val) == Vector{String}
            c = f(val)
        else
            if c(val) == false
                println("error")
            end
        end
    end

I found that if I commented out the body of the loop I would get the same basic stack trace. Unfortunately I haven’t been able to reproduce the stacktrace with a short example :confused:.

As I said, the error happens on the iteration, it did not happen on the loop body. (Also see updated comment) you mostly need to figure out what’s going on in queue().

1 Like