Use module function instead of Base function Julia - julia

Lets say I have a Julia module, MyModule, that defines a function called conv() for 1D convolution. I would like to be able to call this function via MyModule.conv() in a file that imports or uses the file. Example:
import MyModule.conv
MyModule.conv()
However, I cannot get this syntax to work; Julia still calls Base.conv() instead of MyModule.conv(). I have tried all the different styles of using and import but cannot get this syntax to work.
Is this functionality available in Julia? I feel like I have seen this be implemented in other Julia packages but cannot find an example that works.
EDIT
Current setup is as follows; there is no reference to conv() anywhere in ModA outside of the definition.
module ModA
function conv(a, b)
println("ModA.conv")
end
end
Then, in another file,
import ModA
conv(x, y) #still calls Base.conv()
SOLVED
This was entirely my fault. The import wasn't working because of an incorrect LOAD_PATH calling a different version of the file than I thought was being called (finding the first one in the LOAD_PATH, which was not the one that I was editing). Entirely my fault...

Do you mean something like this?
module ModA
conv() = println("Calling ModA.conv")
end
module ModB # Import just conv from ModA
using ..ModA.conv # Could have used import ..ModA.conv instead
conv() # if we want to be able to extend ModA.conv
end
module ModC # Import ModA and use qualified access to access ModA.conv
import ..ModA
ModA.conv()
end
You must make sure not to make any reference to conv inside ModA before you have defined your own function, or it will already have looked up Base.conv and associated the name conv with that.

Related

Selectively import functions using regex

I am looking to import only a few functions from a package. Based on this issue, I can use #rawNamespace to import except.
However, what I would like to do is close to this answer. I would like to define a regular expression to only import certain functions automatically. I would like to avoid importing an entire package just for a couple of functions.
Example
#' My fancy function
#' #rawNamespace import(ggplot2, except = scale_fill_manual)
#' #export
hello_world <- function(){
print("Hello World!")
}
In the above example, I would like to do something like:
#' My fancy function
#' #rawNamespace import(ggplot2, include = scale_*)
#' #export
hello_world <- function(){
print("Hello World!")
}
The above example is super basic but I will actually use the imported functions somewhere else. I cannot simply use :: accessors as I am programmatically getting the functions from the namespace.
Based on this answer, my current workaround is:
lapply(Filter(function(x) grepl("scale_", x), getNamespaceExports("ggplot2")),
utils::getFromNamespace, "ggplot2")
The above will allow me to import all ggplot2 scale functions while only necessitating that I specify a utils import in the Description. However, I think that this may be less ideal since perhaps it requires ggplot2 or whatever package to be on the search path.
This also is flawed because then I need to add names to the list to be able to figure out which function is which.

How can I source specific functions in an R script?

I have a script with my most commonly used functions which I source at the top of most scripts. Sometimes I only want to get one of the functions in that script, but I don't know how to indicate that I only want one specific function. I'm looking for a function that is similar to the :: used to get a function inside a package. A reproducible example:
# file a.R
foo <- function() cat("Hello!\n")
bar <- function() cat("Goodbye!\n")
# End of file a.R
# file b.R
# Can't just delete all functions
fun <- function(x) print(x)
fun("It's so late!")
source("a.R")
foo()
fun("See you next time")
# End of file
I read the "source" help and it was unhelpful to me. The solution I currently have is to assign a variable at the start of the script with the functions loaded before, then set the difference with what was there after:
list_before <- lsf.str()
# content of file b.R
new_funcs <- setdiff(lsf.str(),list_before)
Then I can use rm(list=new_funcs[-1]) to keep only the function I wanted. This is, however a very convoluted way of doing this and I was hoping to find an easier solution.
A good way would be to write a package but it requires more knowledge (not there myself).
A good alternative I found is to use the package box that always you to import functions from an R script as a module.
You can import all functions or specific functions.
To set up a function as a module, you would use the roxygen2 documentation syntax as such:
#' This is a function to calculate a sum
#' #export
my_sum <- function(x, y){
x + y
}
#' This is a function to calculate a difference
#' #export
my_diff <- function(x, y){
x - y
}
Save the file as an R script "my_module.R"
The export parameter in the documentation tells box that what follows is a module. Then you can call box to reach a specific function in the module named "my_module".
Let's say your project directory has a script folder that contains your scripts and modules, you would import functions as such:
box::use(script/my_module)
my_module$my_sum(x, y)
box::use() creates an environment that contains all the functions found inside the module.
You can also import single functions like as follows. Let's assume your directory is a bit more complex as well where modules are inside a box folder inside script.
box::use(./script/box/my_module[my_sum])
my_sum(x, y)
You can use box to fetch functions from packages as well. In a sense, it is better than calling library() that would import all the functions in the package.
Using box, you can organize script by objectives or whatever organization you have in place.
I have a script to deal with strings from which I fetch function that work with strings.
I have a script for plot functions that I use in my projects...etc
insertSource() would help.
In your example, let's presume we need to import foo() from a.R :
# file b.R
foo <- function(){}
insertSource("a.R", functions = "foo", force=T)
foo <- foo#.Data

Externally set default argument of a function from a package

I am building a package with functions that have default arguments. I would like to find a clean way to set the values of the default arguments once the function has been imported.
My first attempt was to set the default values to unknown objects (within the package). Then when I load the package, I would have a external script that would assign a value to the unknown objects.
But it does not seem very clean since I am compiling a function with an unknown object.
My issue is that I will need other people to use the functions, and since they have many arguments I want to keep the code as concise as possible. And many arguments can be set by a configuration script before running the program.
So, for instance, I define in my package:
function_try <- function(x = VAL){
return(x)
}
I compile the package and load it, and then I have an external script that does (or reading from a config file)
VAL <- "hello"
And then a user of the function can just run
function_try()
I would use options for that. So your function looks like:
function_try <- function(x = getOption("mypackage.default.value")) x
In your external script you make sure that the option value is set:
options(mypackage.default.value = "hello")
IMHO that is a clean solution, because anybody reading your function will see at first sight that a certain options value is used as a default and has also a clear understanding of how to overwrite this value if needed.
I would also define a fall back value in your library onLoad to make sure that the value is defined in the first place. You can then even react in your functions to this fallback value and issue a meaningful warning if the function realizes that the the external script did for whatever reason not provide a new value.

Using 'as'/coerce method from another package in my package

I'm writing an R package, and want to internally use an 'as' function from another package to coerce an an object. But I can't figure out how to import it in the package (with either importFrom or ::) like you would an normally exported function.
How can I import a particular flavour of the 'as' method into my package from another package? Or all 'as' methods from another package?
Specifically: The 'contrast_each_group_to_the_rest' function in my package (celaref) that uses that will only work if you call library(MAST) alongside library(celaref).
The 'as' method I want it to use shows up in showMethods("coerce") as from="SingleCellExperiment", to="SingleCellAssay", when I import the 'MAST' package.
E.g. using demo data
library(celaref) # my package, uses MAST internally
library(SingleCellExperiment) # a dependancy
# library(MAST) # Uncomment this and it works
contrast_each_group_to_the_rest(demo_ref_se, num_cores=1)
Yeilds error:
Error in as(sca, "SingleCellAssay") :
no method or default for coercing “SingleCellExperiment” to “SingleCellAssay”
Thanks.
As suggested by Neal Fultz:
You might try adding importFrom("methods", as) - github.com/cran/Matrix
/blob/master/NAMESPACE#L24 this makes me think that MAST may need to add that
to their NAMESPACE.
This works:
#' #importFrom "methods" as in function header
or
importFrom("methods",as) in NAMESPACE
CORRECTION - actually, this doesn't seem to work as I thought it did. Any further tips appreciated.
Fix - importing MAST in the function header (oops) and using a weird looking 'as' format that I don't quite understand. (Probably dependent on the actual (very similar) data objects in these packages)
#' #import SummarizedExperiment
#' #import MAST
sca <- new("SingleCellAssay")
as(sca, "SingleCellExperiment") <- sce.in

What is the difference between `using` and `import` in Julia when building a module?

Question: What is the difference between using and import in Julia when I'm building my own module?
My guess based on reading the docs: using is used to bring another module into the name-space of the current module. import is used to bring specific types/functions/variables from other modules into the name-space of the current module.
So, how wrong am I?
The Julia Modules documentation states:
The import keyword [...] only
operates on a single name at a time. It does not add modules to be
searched the way using does. import also differs from using in that
functions must be imported using import to be extended with new
methods. [...] Functions whose names are only visible via using cannot be extended.
(Emphasis mine.)
For example, you can use import to add methods to Base.show to pretty-print your own types, but not with using.
There is also importall that imports all exported names of a module.
(This answer refers to Julia 0.6; the documentation was reworded for 1.0.)
The documentation (updated link for Julia 1.4) about this is excellent. Here's the excerpt which I find to be the most succinct summary:
(a demo module to make the examples below specific)
module MyModule
export x, y
x() = "x"
y() = "y"
p() = "p"
end
(this is a table in the documentation, but StackOverflow still won't add support for tables so... reformatted)
Command
using MyModule
in-scope: All exported names (x and y), MyModule.x, MyModule.y, and MyModule.p
extensible: MyModule.x, MyModule.y, and MyModule.p
using MyModule: x, p
in-scope: x and p
extensible: (nothing)
import MyModule
in-scope: MyModule.x, MyModule.y, and MyModule.p
extensible: MyModule.x, MyModule.y, and MyModule.p
import MyModule.x, MyModule.p
in-scope: x and p
extensible: x and p
import MyModule: x, p
in-scope: x and p
extensible: x and p
A summary of the main difference, in a way that I find easy to remember:
using NiceStuff allows usage access to exported names without the module qualifier, which import NiceStuff doesn't; and
import NiceStuff: nice allows extension access (adding methods) to the specified function without the module qualifier, which using NiceStuff: nice doesn't.
And a minor difference:
X as Y syntax is allowed for individual identifiers with both using and import (using Random: randstring as rstr, import Random: randstring as rstr) but for the module name itself, import Random as Rnd is allowed while using Random as Rnd is an error.
Some other points I found useful from the Modules docs page
using ModuleName is the only form for which export lists matter at all.
import NiceStuff is equivalent to using NiceStuff: NiceStuff.

Resources