Reuse parts of a module but rewrite others?

90 views
Skip to first unread message

Robert Feldt

unread,
Feb 6, 2016, 6:39:49 AM2/6/16
to julia-users
My feeling is that am missing something very basic here or that this has been asked/misunderstood many times before. ;) But since I could find an answer in my searches here goes:

How can I reuse some parts of another module while re-implementing some of it's lower-level functions (it uses internally)? In the example code below I want to create a new module M2 which reuses (via import and then export) a macro from another module M1 but re-implements a lower level f1 function that is used in the implementation of m1.

module M1
  export @m1
  macro m1(ex)
    @show(ex)
    @show f1(ex)
  end
  function f1(ex)
    "M1.f1: $ex"
  end
end

a = 1
M1.@m1 a + 1   # prints: f1(ex) = "M1.f1: a + 1"

# I want to reuse @m1 but redefine the f1 it uses.
module M2
  import M1: @m1
  function f1(ex)
    "M2.f1: $ex"
  end
end

M2.@m1 a + 1 # Not what I want, it still uses M1.f1

module M3
  import M1: @m1, f1
  function f1(ex)
    "M3.f1: $ex"
  end
end

M3.@m1 a + 1 # What I want but gives warning that f1 in module M1 overwritten
M1.@m1 a + 1 # and M1.@m1 is affected which can affect others...

Is there a way I can import @m1 from M1 into my new module but force it to call my newly defined f1?
Am I totally on the wrong track here and another "design" is better?

I'd rather not fall back to copy-paste solutions here...

Thanks, Robert

Cedric St-Jean

unread,
Feb 6, 2016, 10:37:54 AM2/6/16
to julia-users
Could you give some context and a more concrete description of what you're trying to do?


 macro m1(ex)
   @show(ex)
   @show f1(ex)
 end
 function f1(ex)
   "M1.f1: $ex"
 end

Do you want the macro m1 to expand into code that calls `M2.f1`? Or do you literally want the code in `m1` to call `M2.f1`, as in the example you gave? That would be an unusual request, but it could be done with multiple dispatch...

Robert Feldt

unread,
Feb 6, 2016, 10:57:51 AM2/6/16
to julia-users
One concrete example:

I want to reuse the @testset macro in base/test.jl but change the two utility functions it calls out to (testset_beginend, testset_forloop) to have a richer interface to the AbstractTestSet values used during testing.

But the question is a general one and I tried to simplify the code to the essentials. The macro m1 might be very large and complex and I do not want to rewrite it or copy-paste it in another module but simply want to re-implement some of its utility functions etc.

Hope this helps clarify,

Robert

Cedric St-Jean

unread,
Feb 6, 2016, 5:03:45 PM2/6/16
to julia...@googlegroups.com
You can use multiple dispatch and a "wrapper" type to modify the behaviour of a function. For instance, given this function

function foo(x)
   
return x+x
end

foo
(11)    # 22

You can write:

type Pumpkin
    nhorse
end
import Base.(+)
(+)(p1::Pumpkin, p2::Pumpkin) = "2 pumpkins and $(p1.nhorse+p2.nhorse) horses"

foo
(Pumpkin(11))   # 2 pumpkins and 22 horses

In the same way, you could define `testset_beginend` for your wrapper type... That's IMO a bad idea in this case, because @testset was not written to be extended, and the definition might change in future versions of Julia. I personally would copy-paste (or fork) those functions I need to change.

HTH,

Cédric

Robert Feldt

unread,
Feb 6, 2016, 5:46:52 PM2/6/16
to julia-users
Yeah, you're probably right. For that specific case copy-paste is probably better. Maybe I'm so used to the flexibility and power that Julia gives that it felt weird not finding a clean way to mix-and-match pieces of code from another module...

Thanks for taking the time to answer, Robert
Reply all
Reply to author
Forward
0 new messages