Hide default constructor for a struct

Is there a way to hide a default constructor for a struct so that it is not callable?

Thanks.

You can certainly replace the default constructor by a custom one. But dropping it without any replacement isn’t particularly useful, is it? If there is no constructor at all, what do you need the struct for (you will never be able to create objects)?

julia> struct A
           x::Float64
           A() = new(1.23)
       end

julia> A() # custom constructor
A(1.23)

julia> A(3.141) # default constructor isn't defined
ERROR: MethodError: no method matching A(::Float64)
Closest candidates are:
  A() at REPL[1]:3
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1

FWIW, you can also delete the constructor methods after defining the struct.

julia> struct A
           x::Float64
       end

julia> Base.delete_method.(methods(A));

julia> methods(A)
# 0 methods for type constructor

julia> A()
ERROR: MethodError: no method matching A()

But again, I don’t get the point and wouldn’t recommend it :slight_smile:

2 Likes

You can also disable the default constructor by making struct dependent on another (arbitrary) type:

struct A{T}
      x::Float64
end
A(3.1) # error
A{Any}(3.1) # works

You can also just do this:

julia> struct A
           f() = nothing
       end

julia> methods(A)
# 0 methods for type constructor

Is this behavior to be considered a bug or a feature?

No idea. It certainly looks buggy and arguably it should error out - but it doesn’t.

That was also my impression…

julia> struct A{F}
           f() = println("Hello world")
           x::F
           A() = new{typeof(f)}(f)
       end

julia> A().x()
Hello world

julia> A()
A{var"#f#4"}(var"#f#4"())

julia> f()
ERROR: UndefVarError: `f` not defined
Stacktrace:
 [1] top-level scope
   @ REPL[10]:1

Still not sure :D: Wrongly named inner constructor doesn't error · Issue #52580 · JuliaLang/julia · GitHub

1 Like

Not a bug. The struct has local scope and you can evaluate arbitrary code inside to define ways to construct objects of the type. The most common way to do this is to add methods to the type object itself, but you can do other things as well, eg define a single globally bound instance or a global function by another name that constructs them. If there is any code in a strict you don’t get a default constructor.

3 Likes

No variable assignments in the struct’s outermost scope, right, it throws a syntax error?

These could’ve been done in the global scope without global declarations or evals. Is there anything that must be done in the struct’s local scope besides the inner constructors?

Yes, there are some syntax restrictions—it can’t clash with field declaration or the reserved syntax for defining default values for them.

The point of doing these things inside the struct is that it’s easy to prove that they are the only ways that an object of the type can be constructed since the new pseudo-function is only available inside there. If you do it outside then you had to make some constructor method available and anyone could call that so there’s no such guarantee.

Just note this is not 100% true… in ConstructionBase.jl we actually do construct objects without constructors! (like anonymous function functors)