Non-constructor functions inside struct

I was trying to define a function which has access to new, but is different from the constructor. Consider this MnWE:

julia> struct Foo
       x::Int
       bar(x::Int) = new(x)
       end

julia> methods(bar)
ERROR: UndefVarError: bar not defined
Stacktrace:
 [1] top-level scope at none:0

julia> VERSION
v"1.0.0"

I was surprised that bar is just silently ignored. Is there an issue for this?

BTW, I think the correct way of doing this is

function bar end

struct Foo
    x::Int
    global bar(x::Int) = new(x)
end

Interesting. How is this useful?

I have a type for which I want to validate the fields, and also provide a function that just returns nothing for invalid input.

Assume that

  1. isvalid below is costly, so I don’t want to call it superflously,
  2. I don’t want to provide an argument to the constructor that tells not to validate (this is a standard approach I have seen, but I have seen it get abused),
  3. I always want the constructor Foo to return a ::Foo, so I need a separate function.
function valid_or_nothing end

struct Foo
    x                           # validated
    function Foo(x)
        @assert isvalid(x)      # this is assumed to be costly
        new(x)
    end
    global valid_or_nothing(::Type{Foo}, x) = isvalid(x) ? new(x) : nothing
end

I would appreciate more input on whether is approach (non-constructor functions inside the type) is OK, then if there is interest, it would make a PR to the documentation.

Here is a use cases in base:

2 Likes