"LoadError: invalid redefinition of constant" when creating new Distribution

I am trying to create a new distribution (bivariate Projected Normal) using skellam.jl as an example, however I am getting this error:

push!(LOAD_PATH, ".")

using Revise
using ProjectedNormal

┌ Info: Precompiling ProjectedNormal [top-level]
└ @ Base loading.jl:1273
ERROR: LoadError: invalid redefinition of constant ProjectedNormal

This is the code in the module:

module ProjectedNormal

using Distributions
using SpecialFunctions

struct ProjectedNormal{T<:Real} <: ContinuousUnivariateDistribution
	μ::T
	ξ::T
	
    function ProjectedNormal{T}(μ::T, ξ::T) where {T <: Real}
        return new{T}(μ, ξ)
    end
end

#### Parameters
params(d::ProjectedNormal) = (d.μ, d.ξ)
partype(::ProjectedNormal{T}) where {T} = T

function pdf(d::ProjectedNormal, θ::Real)
    μ, ξ = params(d)
    1/2π*exp(-ξ^2/2*(1+sqrt(π/2)*ξ*cos(θ-μ)*exp(ξ^2*cos(θ-μ)^2/2)*(1+erf(ξ*cos(θ-μ)/sqrt(2)))))	
end

#### Sampling
function rand(d::ProjectedNormal)
	μ, ξ = params(d)
	atan(cos(μ)+randn(),sin(μ)+randn())
end

function rand(rng::AbstractRNG, d::ProjectedNormal)
	μ, ξ = params(d)
	atan(cos(μ)+randn(rng),sin(μ)+randn(rng))
end

end

Any ideas? Thanks!

It looks like the module name is available as a global variable within the module, so when you define your ProjectedNormal struct, it’s trying to redefine the constant module reference. Here’s a minimal example of this problem:

julia> module A

       struct A end

       end
ERROR: invalid redefinition of constant A

By the way, this is unrelated to your question, but you can leverage multiple dispatch to reduce the code duplication in your rand methods:

using Random

function rand(d::ProjectedNormal)
	rand(Random.GLOBAL_RNG, d)
end

function rand(rng::AbstractRNG, d::ProjectedNormal)
	μ, ξ = params(d)
	atan(cos(μ)+randn(rng),sin(μ)+randn(rng))
end
2 Likes

Just to add, the usual solution is to pluralize the module, e.g. ProjectedNormals in this case.

1 Like

Yes, that fixed it. Thanks!