1

I'm writing a Julia package for testing the behaviour of floating point addition.

module TestModule


const base_add = Base.:+

# used for storing information when addition is done
mutable struct Tracking
    info::String

    Tracking() = new("default message")
end

# overloading of addition, t has default argument in case of none provided
function +(in1::Float64, in2::Float64, t::Tracking = Nothing)
    t.info = "writing a string to t.info when addition is performed"

    return base_add(in1, in2)
end

# run f() and track information in t
function execute(f::Function, t::Tracking)
    +(a, b) = TestModule.:+(a, b, t)
    f()
end

function report(t::Tracking)
    println("final value = ", t.lastResult)
    println(t.info)
end


end

My current plan is that the user writes a function for whatever they want to test, creates an instance of the Tracking data structure, and runs execute() on those in order to perform the instructions and record data. Here is an example script.

using TestModule

# user-defined function with no arguments
function myExperiment()
    x = 1.0
    y = 2.0
    
    println(x + y)
end

# Create tracker and run
t = TestModule.Tracking()
TestModule.execute(myExperiment, t)
TestModule.report(t)

However my problem is that execute() seems to not integrate TestModule.:+ into the function it is testing. On return, the elements of t are unchanged from construction.

final value = 0.0
info: default message

I have looked into this and I am looking for the most appropriate and standard way to achieve what I am attempting.

I have decided with this design after first trying to directly overload Base.:+ at the start of the script, this made it difficult to distinguish and directly interfered with base functionality. With execute(), my goal is to make it as easy for the user as possible to perform testing and get results, and for the library to have no interference on behaviour. However execute() does not do what I want it to, being replacing any instances of Base.:+ in the provided function f() with TestModule.:+.

How can I achieve this? I want to keep it intuitive if possible, I was considering that f() could take a function to replace addition as an argument, but this kind of approach makes it less accessible so I would prefer to avoid it. I want to avoid modifying anything other than execute() but I'm not sure this is possible. Thank you.

1 Answer 1

1

The short answer is that this isn't possible because + is already compiled into the definition of myExperiment — it's not looked up in the local scope at runtime. You could try to do something crazy like get the CodeInfo of myExperiment and swap out + for TestModule.+, but this seems like a lot of effort compared to just passing in the symbols to myExperiment. Unfortunately this does require slightly modifying the signature of myExperiment.

module TestModule

const base_add = Base.:+

# used for storing information when addition is done
mutable struct Tracking
    info::String
    lastResult::Float64

    Tracking() = new("default message", 0)
end

# overloading of addition, t has default argument in case of none provided
function +(in1::Float64, in2::Float64, t::Tracking=nothing)
    result = base_add(in1, in2)
    if t !== nothing
        t.info = "writing a string to t.info when addition is performed"
        t.lastResult = result
    end

    return result
end

const OVERLOADS = Dict(:+ => +)

# run f() and track information in t
function execute(f::Function, t::Tracking)
    return f(t)
end

function report(t::Tracking)
    println(t.info)
    println("final value = ", t.lastResult)
    return nothing
end

end

module X

using ..TestModule

# user-defined function with no arguments
function myExperiment(
    t::TestModule.Tracking, overloads::Dict{Symbol,<:Function}=TestModule.OVERLOADS
)
    + = overloads[:+]

    x = 1.0
    y = 2.0

    println(+(x, y, t))
    return nothing
end

# Create tracker and run
t = TestModule.Tracking()
TestModule.execute(myExperiment, t)
TestModule.report(t)

end
3.0
writing a string to t.info when addition is performed
final value = 3.0
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.