# Non-constructor functions inside struct

**URL:** <https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078>\
**Category:** General Usage\
**Tags:** question\
**Created:** [August 26, 2018, 10:34am UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078 "2018-08-26T10:34:07Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 26, 2018, 10:34am UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/1 "2018-08-26T10:34:07Z")

</div>

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

```julia
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?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 26, 2018, 10:43am UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/2 "2018-08-26T10:43:19Z")

</div>

BTW, I think the correct way of doing this is

```julia
function bar end

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

```

---

<div class="post-metadata">

**Author:** ![RaulDurand](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rauldurand/32/2044_2.png) [@RaulDurand](https://discourse.julialang.org/u/RaulDurand)\
**Post date:** [August 26, 2018, 1:05pm UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/3 "2018-08-26T13:05:24Z")

</div>

Interesting. How is this useful?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 26, 2018, 1:10pm UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/4 "2018-08-26T13:10:32Z")

</div>

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.

```julia
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

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 26, 2018, 1:11pm UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/5 "2018-08-26T13:11:43Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [August 26, 2018, 2:37pm UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/6 "2018-08-26T14:37:53Z")

</div>

Here is a use cases in base:

> <https://github.com/JuliaLang/julia/blob/master/base/mpfr.jl#L62>

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [January 16, 2024, 4:08am UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/7 "2024-01-16T04:08:56Z")

</div>

I have another situation where being able to define a function (the `isvalid` function below) inside the struct definition would be helpful. I want to create a parametric struct `S` but I want all constructors to explicitly specify parameters (so no `S(x)` and no inferring parameters from arguments).

```julia
struct S{T}
isvalid(a)::Bool = ... # imagine lots and lots of checks. too much to repeat for each constructor.
S{a}() where {a} = isvalid(a) ? new{a}() : error("S{$(a)} cannot be created")
S{b}() where {b} = isvalid(b) ? new{b}() : error("S{$(b)} cannot be created")
end

```

I think it would be nice to not have to define `function isvalid end` outside the struct. And would certainly be nice for the code above to give an error if `function isvalid end` is not already created. (It does not as of Julia 1.9.0)

I am curious to hear people’s thoughts on this.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 16, 2024, 5:45am UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/8 "2024-01-16T05:45:19Z")

</div>

> [@sadish-d](#):
>
> I have another situation where being able to define a function (the `isvalid` function below) inside the struct definition would be helpful.

You can, you just can’t affect the global scope from a struct scope by default, you need a `global` declaration. In the original example and your case, `isvalid` should be defined in the global scope. After all, if you need to add a method to a global function, you should generally do it in the global scope. The original examples had an exception because `global valid_or_nothing` needed to access `new` for instantiation. It was probably better to refactor so that instantiation never skips a `Foo` call; a `Foo` method itself can optionally skip validation steps to `new`.

Example of a function isolated to a `struct`’s local scope:

```julia
julia> begin
       foo() = 1 # global foo
       struct X
         foo() = new() # struct-local foo
         X() = foo() # uses local foo
       end
       X(), foo()
       end
(X(), 1)

```

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [January 16, 2024, 3:10pm UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/9 "2024-01-16T15:10:35Z")

</div>

I see. So I was trying to access/test my `_isvalid` function from outside the struct. But If I want that, I need to declare it a `global`. That make sense.

```julia
struct A
global _isvalid() = true
end
@assert _isvalid()

```

But yeah, being able to access `new` from non-constructor functions would save me repetition:

```julia
_isvalid(x) = ...
struct S{T}
    _S(a) = _isvalid(a) ? new{a}() : error("S{$(a)} cannot be created")
    S{x}() where {x} = _S(x)
end

```

This is if I really want to not have an `S` constructor and only `S{T}`.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [January 16, 2024, 4:20pm UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/10 "2024-01-16T16:20:45Z")

</div>

I read the above posts again, and I see that it is possible to do the following (adding the global declaration)

```julia
_isvalid(x) = ...
struct S{T}
    global _S(a) = _isvalid(a) ? new{a}() : error("S{$(a)} cannot be created")
    S{x}() where {x} = _S(x)
end

```

But again, that means there is now a `_S` function in the global scope that constructs `S{T}`. So if we’re obsessed with limiting the constructors to `S{T}` (maybe not a justifiable obsession), this is not a solution.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 17, 2024, 6:39am UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/11 "2024-01-17T06:39:18Z")

</div>

> [@sadish-d](#):
>
> But again, that means there is now a `_S` function in the global scope that constructs `S{T}`.

I agree that is a problem. But a local `_S` can already access `new`, so your example without the `global` declaration should work as well. `_isvalid` is global so you can test it as you need. I’ll amend my earlier example to demonstrate.

I would still prefer making constructors that rely only on each other and `new` because fewer functions is simpler. For example if I had a struct `X{A,B,C}` but only want to expose `X{A}` and `X{A,B}`, I would likely make outer `X{A}` forward to inner `X{A,B}` which uses `new{A,B,C}`. Of course, your real use case is probably more complicated than your examples, so if inner constructors using a local non-constructor function make things simpler, then go for it.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [January 17, 2024, 1:52pm UTC](https://discourse.julialang.org/t/non-constructor-functions-inside-struct/14078/12 "2024-01-17T13:52:49Z")

</div>

You’re right. You’d already given me a solution. I was confusing myself. I guess in the original post the author did want something in the global scope.

I’m going off topic now just to share a bit about what you’ve been helping me out with: I have these different functions to take some input and do transformations. The parameters of these functions are experimentally determined. I basically want to store the parameters as fields of a struct create functors out of them. So I don’t want users to be able to create new types, just make instances of the ones available.

Basically I have `Transformer{T}`, and want to restrict what `T`s are allowable. I can check that `T` is of acceptable values inside the constructor before returning. That would be the typical way to do it. But I wanted to see if I can do it with dispatch rather than if/else.
