In one of my packages i get the following warning:
┌ GraphMakie
│ WARNING: Constructor for type "Pointf" was extended in `GraphMakie` without explicit qualification or import.
│ NOTE: Assumed "Pointf" refers to `GeometryBasics.Pointf`. This behavior is deprecated and may differ in future versions.`
│ NOTE: This behavior may have differed in Julia versions prior to 1.12.
│ Hint: If you intended to create a new generic function of the same name, use `function Pointf end`.
│ Hint: To silence the warning, qualify `Pointf` as `GeometryBasics.Pointf` in the method signature or explicitly `import GeometryBasics: Pointf`.
└
I am a bit confused by that. I think I introduced that function Pointf before it was exported from GeometryBasics. So I is (was) actually introduced as a module local binding. That behavior should not change when GeometryBasics introduced and exported a Pointf binding, because the docs are pretty clear about the fact that in order to extend a method you have to explicitly import it.
The warning however implies, that the code
Pointf(p::StaticVector{N, T}) where {N,T} = Point{N, Float32}(p)
now extends GeometryBasics.Pointf, which would be type piracy.
What happend here? Also, the warning explicitly calls the method a “Constructor”, is the behavior different for functions which happens to have the same name as a struct and functions which don’t? I allways assumed that outer “constructors” are not special in any way.
To make a MWE separate from your packages, this is what happens for typical functions:
julia> module A
export f
function f end
end
Main.A
julia> module B
using ..A
f() = "B"
end
Main.B
julia> A.f === B.f
false
and this is what happens for typical types:
julia> module A
export f
struct f end
end
Main.A
julia> module B
using ..A
f() = "B"
end
WARNING: Constructor for type "f" was extended in `B` without explicit qualification or import.
NOTE: Assumed "f" refers to `A.f`. This behavior is deprecated and may differ in future versions.`
NOTE: This behavior may have differed in Julia versions prior to 1.12.
Hint: If you intended to create a new generic function of the same name, use `function f end`.
Hint: To silence the warning, qualify `f` as `A.f` in the method signature or explicitly `import A: f`.
Main.B
julia> A.f === B.f
[ Warning: f is defined in Main.A and is not public in Main.B
true
B.f does not extend or “refer to” A.f either way in 1.11.7, so it’s strange it occurs now only to be “deprecated”.
Oh wow so it is actually both, a breaking change in 1.12 and a special handling of “constructor”-type functions.
Well, yet another reason to never use implicit imports. In new packages I already use ExplicitImports.jl, but I guess we should be really updating all our packages..
Issue #25744 implies, that “constructor” type methods could have been overwritten before without implicit import. But the MWE said otherwise:
module A
export Foo
struct Foo
x
end
end
module B
using ..A
Foo(x::String) = "🏴☠️"
end
using ..A
using ..B
Foo("are you pirated?") # yes in 1.12, no in 1.11
Yeah it’s bizarre. One thing with method definitions scattered across modules is already unusual, and it didn’t help that the import system and practices weren’t fully thought out by v1. It really bothers me that “all case 2” wasn’t chosen, but that’s the consequence of complexity and ambiguity.
This isn’t the only weird practical change with the const redefinition era. Although it being involved in world age was wanted forever, it also means that implicitly imported names via using are now reassigned by a local function definition instead of erroring:
| | |_| | | | (_| | | Version 1.11.7 (2025-09-08)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia> module B
export g
g(x) = 1
end; using .B
julia> g(0)
1
julia> g(x) = 10
ERROR: invalid method definition in Main: function B.g must be explicitly imported to be extended
| | |_| | | | (_| | | Version 1.12.1 (2025-10-17)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org release
|__/ |
julia> module B
export g
g(x) = 1
end; using .B
julia> g(0)
1
julia> g(x) = 10
g (generic function with 1 method)
julia> g(0), B.g(0) # changes to const variables are allowed now
(10, 1)
Explicit import via using still errors. Implicit imports are pretty necessary for end-users’ interactive work, but I can’t really justify method extensions or reassignments via imported names without qualifying the module object anymore, even interactively or with distinct renames. This was a common principle before to prevent unintended interference of local method definitions and an imported name, introduced in either order, but it just seems too dangerous now. Hopefully that makes it somehow into 2.0: just one import keyword · Issue #39235 · JuliaLang/julia, even if that stays hypothetical.