Creating a function with the same name as given to a struct

I’m trying to follow a programming exercise in Python (2.x) which follows these steps to make a simple test for building a test runner:

test= WasRun("testMethod")
print test.wasRun
test.testMethod()
print test.wasRun

Notice how “testMethod”, the string, defines a function with the same name which acts on the “WasRun” object

So far, my adaptation attempt goes like this

test = WasRun("testMethod") #<- mutable Julia struct
println(test.wasRun)
run(test) # not exactly the same meaning
println(test.wasRun)

And defining run separately like

run(wr::WasRun) = wr.wasRun = true

but it seems the closest adaptation would be either

testMethod(wr::WasRun) = wr.wasRun = true

or

test.testMethod() # <- testMethod() being defined during the constructor call from 'test'

by itself. This last solution seems weird for Julia, because it would mean the struct would have testMethod() being defined in the constructor and being part of the structure.

I don’t have to follow the example 1:1, but I was wondering if there is a viable solution to adapt this behavior.

Thanks a lot in advance

this is the Julian way to do it.

but note that in Julia a struct named WasRun is by itself a little bit weird, because structures do not contain methods/functions, such that the struct cannot be “run”.

testMethod(wr::WasRun) = wr.wasRun = true

In order to do this solution, I would have to probably do some metaprogramming similar to (notice that the code will note be correct:)

Symbol(test.name)(wr::WasRun) = wr.wasRun = true

I should probably turn this line of code into an expression and @eval it, but it’s something I’m not even sure I should be investing on. This may possibly become a macro which creates a test and a function with a given name using simple string substitution, which sounds like a way better idea than having the struct hold its own test function.

The name WasRun wasn’t picked by me and I agree it’s a bit confusing.

The intention of the code, from what I understand, is that when run(test) is called, it will run test.testMethod(), which is simply the test object holding all its test environment (required variables, setUp(), tearDown(), and the test routine itself).

I think I’m getting closer to a fair Julia adaptation

You have to define the testMethod function, that’s for sure, but the only difference is that in the object-oriented syntax you call it with object.testMethod() and the function is defined “inside” the object, and in the multiple-dispatch syntax you call it with testMethod(object) and the function is defined “outside” the object, with the dispatch defined by the argument type.

edit: It is not clear to me why you need a string anywhere (either in Python or in Julia). Here, if you have many different structs and want to test if testMethod works on them, you could do:

using Test
for obj in [ Obj1(), Obj2(), Obj3() ]
    @test testMethod(obj) # assuming it returns true or false
end

where each ObjX can be a of a different type.

Thanks for your input!

I think I didn’t make the step-by-step clear in the first question, sorry! testMethod is a function named defined once the object is created. Later, the original author changes the code to

test= WasRun("testMethod")
print test.wasRun
test.run() # This will call testMethod defined in the 'test' instannce
print test.wasRun

I don’t have to translate the code 1:1, but I like to first replicate any other language’s code as accurately as I can, then write as I think is reasonable (not to miss any step suggested by the original authors of some tutorial/class/exercise)

I think your solution is the most reasonable in Julia, so I’m pretty sure I’ll adapt to it

I guess this is a complication that is not really what you want, but you can do this:

julia> struct Func{F}
         f::F
       end

julia> (x::Func)(pars...) = x.f(pars...)

julia> twox = Func(x -> 2x)
Func{var"#1#2"}(var"#1#2"())

julia> twox(4)
8

(these are called “functors” - function-like objects, meaning you create an object that is callable).

1 Like