Hello everybody,

I have a bunch of questions concerning parametric constructors for structs.

Some background: I was writing a toy code to compute a Newton fractal. For that it makes sense to bundle the function of which the roots are computed, its derivative and the locations of the roots (and some more parameters) into a struct.

After reading this discourse thread and then by trial-and-error I came up with the following (reduced for this thread) code:

```
struct fractal{F<:Function,G<:Function}
xx
yy
myfunction::F
derivative::G
number_of_roots::Int
roots
end
function make_fractal(xx,yy)
function myfunction(z::Complex{Float64})
return z^3-1.0
end
function derivative(z::Complex{Float64})
return 3.0*z^2
end
roots = (complex(1.0,0.0),
complex(-0.5,0.5*sqrt(3)),
complex(-0.5,-0.5*sqrt(3)) )
return fractal(xx,yy,myfunction,derivative,3,roots)
end
xx=range(-3.5, stop=2.0, length=2000)
yy=range(-2.5, stop=2.5, length=2000)
Fractal=make_fractal(xx,yy)
function iterationstep(Fractal::fractal,z)
return z-Fractal.myfunction(z)/Fractal.derivative(z)
end
zz=complex(1.0,2.0)
zz=iterationstep(Fractal,zz)
```

This works nicely in the sense that `@code_warntype`

is completely happy and myfunction() and derivative() get inlined:

```
julia> @code_warntype iterationstep(Fractal,zz)
Body::Complex{Float64}
31 1 ─ %1 = (Base.getfield)(z, :re)::Float64 │╻╷╷╷╷╷ myfunction
│ %2 = (Base.getfield)(z, :re)::Float64 ││╻ literal_pow
│ %3 = (Base.mul_float)(%1, %2)::Float64 │││╻ *
│ %4 = (Base.getfield)(z, :im)::Float64 ││││╻ *
│ %5 = (Base.getfield)(z, :im)::Float64 │││││╻ imag
...
...
```

(Remark: having `myfunction::Function`

and `derivative::Function`

, i.e. unparametrized fields, in the struct above and calling `iterationstep(Fractal,zz)`

as above disables type inference as alrady noted in the mentioned discourse thread).

Unfortunately I have only a vague understanding what I did and why this works. Reading the manual section gives me the impression that I should have specified parametric types for all fields in the struct ? But I have untyped fields in there. How does julia decide what fields in the constructor call

```
fractal(xx,yy,myfunction,derivative,3,roots)
```

are `F`

and `G`

? By position ? Then what about multiple `Float64`

or `Int`

or `Vector{Float64}`

fields ? Or is this abstract versus concrete types ?

Also, changing the struct to

```
struct fractal{F<:Function}
xx
yy
myfunction::F
derivative::F
number_of_roots::Int
roots
end
```

which would appear to be reasonable as `myfunction()`

and `derivative()`

have the same argument and return type throws an error

```
julia> include("mwe.jl")
ERROR: LoadError: MethodError: no method matching fractal(::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}, ::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}, ::getfield(Main, Symbol("#myfunction#3")), ::getfield(Main, Symbol("#derivative#4")), ::Int64, ::Tuple{Complex{Float64},Complex{Float64},Complex{Float64}})
Closest candidates are:
fractal(::Any, ::Any, ::F<:Function, ::F<:Function, ::Int64, ::Any) where F<:Function at /mnt/ramfs/mwe.jl:2
Stacktrace:
[1] make_fractal(::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}, ::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}) at /mnt/ramfs/mwe.jl:21
[2] top-level scope at none:0
```

which I do not understand.

On top, would it be advisable to actually type the un-typed fields ? How would I do that for `fractal.xx`

and `fractal.roots`

(one could switch `fractal.roots`

to a vector from a tuple), please note that a different `myfunction()`

might of course a different number of roots ?

I am aware that in the already mentioned thread the suggestion was to use something like

```
struct fractal
xx
yy
myfunction::Function
derivative::Function
number_of_roots::Int
roots
end
...
...
function iterationstep(f,d,z)
return z-f(z)/d(z)
end
zz=iterationstep(Fractal.myfunction,Fractal.derivative,zz)
```

which of course works fine and infers type/ inlines correctly.

Still, I would appreciate any help to understand the parametric constructors better.

Thank you very much for reading this far !

Best Regards