Julia modules


#1

Hi,

I 'm having troubles understanding how to package my functionality into modules. I have a general algorithm which is expressed using number of generic functions (which different types will later provide implementation for). I wanted to put this algo into a separate module. Here’s an example:

module General
export algo
algo(x) = internals(x)
end

module Specific
export internals
internals(x) = x
end

module Test
using Main.General
using Main.Specific
algo(2)
end

algo is expressed in terms of a generic function internals.

However , when executing Test I’m getting:

ERROR: UndefVarError: internals not defined
Stacktrace:
 [1] algo(::Int64) at ./REPL[111]:3
 [2] top-level scope at none:0

I must be missing something embarrassingly simple and fundamental. What am I doing wrong?

Thanks


#2

You need to tell General where to find internals:

       module General
       using ..Specific
       export algo
       algo(x) = internals(x)
       end                                                                                                                                                              

PS: read PSA: how to quote code with backticks


#3

Thanks. Now I get a conflict when I try to include a second implementation of internals for a different type.

I changed my example I hope to be more clear of what I want to achieve:

module Play
using ..Game1Module
using ..Game2Module
export playgame
function playgame(x)
    if not(isfinished(x))
        nextmove(x)
    end
end
end

module Game1Module
export isfinished
struct Game1 end
isfinished(x::Game1) = true
nextmove(x::Game1) = printnl("Making a move in game 1")
end

module Game2Module
export isfinished
struct Game2 end
isfinished(x::Game2) = false
nextmove(x::Game2) = printnl("Making a move in game 2")
end

module Test
using Main.Play
using Main.Game1Module: Game1
game1 = Game1()
playgame(game1)
end

which is to have a few different games each of which implements the same set of functions which will allow me to know if the game has finished, what are the possible next moves etc, whose move it is now etc. And then I wanted to have an small engine which will use those functions to play the actual game, irrespective of whether it’s a Game1 or Game2. Hope it makes sense.

And the error is:

ERROR: UndefVarError: isfinished not defined
Stacktrace:
 [1] playgame(::Main.Game1Module.Game1) at ./REPL[166]:6
 [2] top-level scope at none:0

#4

I got your code to work by defining a “base” copy of isfinished and nextmove that all the other modules then overload.

EDIT: Just to clarify, the rule in Julia is that defining a name like isfinished at global scope in two different modules creates two different functions, not two methods of the same function, and hence the rules of multiple dispatch do not distinguish/relate them. In order to take advantage of multiple dispatch for a name spanning several modules, it is necessary for one module to own a master copy and for the others to import it before extending it.

By the way, instead of qualifying with Main, it is better to use .. (see below) to improve portability. Also printnl should be println and not should be !.

module GameBase
isfinished() = nothing
nextmove() = nothing
export isfinished
end


module Game1Module
struct Game1 end
import ..GameBase.isfinished
import ..GameBase.nextmove
isfinished(x::Game1) = true
nextmove(x::Game1) = println("Making a move in game 1")
end

module Game2Module
struct Game2 end
import ..GameBase.isfinished
import ..GameBase.nextmove
isfinished(x::Game2) = false
nextmove(x::Game2) = println("Making a move in game 2")
end

module Play
import ..GameBase.isfinished
import ..GameBase.nextmove
using ..Game1Module
using ..Game2Module
export playgame
function playgame(x)
    if !(isfinished(x))
        nextmove(x)
    end
end
end


module Test
using ..Play
using ..Game2Module: Game2
game1 = Game2()
playgame(game1)
end