Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two Modules, both exporting the same name

There are two packages I want to use: CorpusLoaders.jl, and WordNet.jl

  • CorpusLoaders.SemCor exports sensekey(::SenseTaggedWord)
  • WordNet exports sensekey(::DB, ::Synset, ::Lemma)

I want to use both sensekey methods.

Eg

for some mixed list of items: mixedlist::Vector{Union{Tuple{SenseTaggedWord},Tuple{DB, Synset,Lemma}}. Ie the items in the list are a mixture of 1-tuples of SenseTaggedWord, and3 tuples of DB, Synset, and Lemma.

for item in mixedlist
    println(sensekey(item...)
end

should work. This example is a little facetious, since why would I be mixing them like this. But, hopefully it serves for illustrating the problem in the general case.

Trying to using CorpusLoaders.SemCor, WordNet to bring in both results in WARNING: both WordNet and Semcor export "sensekey"; uses of it in module Main must be qualified.

Manually importing both: import CorpusLoaders.SemCor.sensekey; import WordNet.sensekey results in WARNING: ignoring conflicting import of Semcor.sensekey into Main

What can be done? I want them both, and they don't really conflict, due to multiple-dispatch.


Given that CorpusLoaders.jl is a package I am writing I do have a few more options, since I could make my CorpusLoaders.jl depend on WordNet.jl. If I did do than then I could say in CorpusLoaders.jl

 import WordNet
 function WordNet.sensekey(s::SenseTaggedWord)...

and that would make them both work. But it would mean requiring WordNet as a dependency of CorpusLoaders.

And I want to know how to solve the problem for a consumer of the packages -- not as the creator of the packages.

like image 811
Lyndon White Avatar asked Dec 01 '22 16:12

Lyndon White


2 Answers

tl;dr qualify the functions when using them in your script via their module namespace, i.e. CorpusLoader.sensekey() and WordNet.sensekey()


Explanation

My understanding of your question after the edits (thank you for clarifying) is that:

  • You have written a package called CorpusLoaders.jl, which exports the function sensekey(::SenseTaggedWord)
  • There is an external package called WordNet.jl, which exports the function sensekey(::DB, ::Synset, ::Lemma)
  • You have a script that makes use of both modules.

and you are worried that using the modules or "importing" the functions directly could potentially create ambiguity and / or errors in your script, asking

  1. how can I write my CorpusLoaders package to prevent potential clashes with other packages, and
  2. how can I write my script to clearly disambiguate between the two functions while still allowing their use?

I think this stems from a slight confusion how using and import are different from each other, and how modules create a namespace. This is very nicely explained in the docs here.

In essence, the answers are:

  1. You should not worry about exporting things from your module that will clash with other modules. This is what modules are for: you're creating a namespace, which will "qualify" all exported variables, e.g. CorpusLoaders.sensekey(::SenseTaggedWord).

  2. When you type using CorpusLoaders, what you're saying to julia is "import the module itself, and all the exported variables stripped from their namespace qualifier, and bring them into Main". Note that this means you now have access to sensekey as a function directly from Main without a namespace qualifier, and as CorpusLoaders.sensekey(), since you've also imported the module as a variable you can use.

If you then try using the module WordNet as well, julia very reasonably issues a warning, which essentially says:

"You've imported two functions that have the same name. I can't just strip their namespace off because that could create problems in some scenarios (even though in your case it wouldn't because they have different signatures, but I couldn't possibly know this in general). If you want to use either of these functions, please do so using their appropriate namespace qualifier".

So, the solution for 2. is:

  • you either do

    using CorpusLoaders;
    using WordNet;
    

    , disregarding the warning, to import all other exported variables as usual in your Main namespace, and access those particular functions directly via their modules as CorpusLoaders.sensekey() and WordNet.sensekey() each time you need to use them in your script, or

  • you keep both modules clearly disambiguated at all times by doing

    import CorpusLoaders;
    import WordNet;
    

    and qualify all variables appropriately, or

  • in this particular case where the function signatures don't clash, if you'd really like to be able to use the function without a namespace qualifier, relying on multiple dispatch instead, you can do something like what FengYang suggested:

     import CorpusLoaders;
     import WordNet;
     sensekey(a::SenseTaggedWord) = CorpusLoader.sensekey(a);
     sensekey(a::DB, b::Synset, c::Lemma) = WordNet.sensekey(a, b, c);
    

    which is essentially a new function, defined on module Main, acting as a wrapper for the two namespace-qualified functions.

In the end, it all comes down to using using vs import and namespaces appropriately for your particular code. :)


As an addendum, code can get very unwieldy with long namespace qualifiers like CorpusLoader and WordNet. julia doesn't have something like python's import numpy as np, but at the same time modules become simple variables on your workspace, so it's trivial to create an alias for them. So you can do:
import CorpusLoaders; const cl = CorpusLoaders;
import Wordnet;       const wn = WordNet;
# ... code using both cl.sensekey() and wn.sensekey()
like image 114
Tasos Papastylianou Avatar answered Dec 05 '22 20:12

Tasos Papastylianou


In this case, the functions do not conflict, but in general that is impossible to guarantee. It could be the case that a package loaded later will add methods to one of the functions that will conflict. So to be able to use the sensekey for both packages requires some additional guarantees and restrictions.

One way to do this is to ignore both package's sensekey, and instead provide your own, dispatching to the correct package:

sensekey(x) = CorpusLoaders.sensekey(x)
sensekey(x, y, z) = WordNet.sensekey(x,y,z)
like image 28
Fengyang Wang Avatar answered Dec 05 '22 20:12

Fengyang Wang