# Are these type functors the same as Outer Constructors?

**URL:** <https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598>\
**Category:** General Usage\
**Tags:** question\
**Created:** [February 22, 2024, 6:19pm UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598 "2024-02-22T18:19:27Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [February 22, 2024, 6:19pm UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598/1 "2024-02-22T18:19:27Z")

</div>

I found this approach in Rotations.jl. Why code it this way? Note that AngleAxis is a concrete type, so AA can only be one type.

```julia
@inline function (::Type{AA})(q::QuatRotation) where AA <: AngleAxis
    w = real(q.q)
    x, y, z = imag_part(q.q)
    s2 = x * x + y * y + z * z
    sin_t2 = sqrt(s2)
    theta = 2 * atan(sin_t2, w)
    num_pert = eps(typeof(theta))^4
    inv_sin_t2 = 1 / (sin_t2 + num_pert)
    return principal_value(AA(theta, inv_sin_t2 * (x + num_pert), inv_sin_t2 * y, inv_sin_t2 * z, false))
end

# Trivial type conversions for RotX, RotY and RotZ
@inline function (::Type{AA})(r::RotX) where AA <: AngleAxis
    return AA(r.theta, 1, 0, 0)
end
@inline function (::Type{AA})(r::RotY) where AA <: AngleAxis
    return AA(r.theta, 0, 1, 0)
end
@inline function (::Type{AA})(r::RotZ) where AA <: AngleAxis
    return AA(r.theta, 0, 0, 1)
end

```

The full code can be found here:

> <https://github.com/JuliaGeometry/Rotations.jl/blob/master/src/angleaxis_types.jl>

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [February 22, 2024, 6:53pm UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598/2 "2024-02-22T18:53:31Z")

</div>

No. These are callable structs (see [Function factories or callable structs?](https://discourse.julialang.org/t/function-factories-or-callable-structs/52987))

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [February 22, 2024, 7:04pm UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598/3 "2024-02-22T19:04:32Z")

</div>

I understand they are callable structs, but how are these three functions

> [@prittjam](#):
>
> ```julia
> # Trivial type conversions for RotX, RotY and RotZ
> @inline function (::Type{AA})(r::RotX) where AA <: AngleAxis
> return AA(r.theta, 1, 0, 0)
> end
> @inline function (::Type{AA})(r::RotY) where AA <: AngleAxis
> return AA(r.theta, 0, 1, 0)
> end
> @inline function (::Type{AA})(r::RotZ) where AA <: AngleAxis
> return AA(r.theta, 0, 0, 1)
> end
> 
> ```

different than an outer constructor for AngleAxis? Would an outer constructor have a different type signature?

---

<div class="post-metadata">

**Author:** ![rayegun](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rayegun/32/26729_2.png) [@rayegun](https://discourse.julialang.org/u/rayegun)\
**Post date:** [February 22, 2024, 8:27pm UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598/4 "2024-02-22T20:27:42Z")

</div>

No the signatures look the same AFAICT. These aren’t really callable structs.

It is a strange way to write a constructor, but I can’t seem to find a difference. This _can_ be used to do certain “Abstract” constructors but AngleAxis is a struct so I’m not sure the purpose.

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [February 23, 2024, 7:18pm UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598/5 "2024-02-23T19:18:53Z")

</div>

So I did some basic tests with these two idioms:

outer constructor and  
type functor

and indeed I can see no difference in how they are working in the context cited above. So I will mark it as correct, but maybe someone will see this and explain the use case more. Thanks!

---

<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:** [February 24, 2024, 1:59am UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598/6 "2024-02-24T01:59:38Z")

</div>

I’ve seen this around and never found out why people write `::Type{X}` in the callable position, it doesn’t seem to make a difference:

```julia
julia> abstract type Y end

julia> struct X<:Y end

julia> (::Type{X})(::Int) = 1

julia> (::Type{blah})(::Float64) where blah<:X = 1.2

julia> (::Type{blah})(::Float64) where blah<:Y = 2.1 # potentially useful

julia> methods(X)
# 4 methods for type constructor:
 [1] X(::Int64)
     @ REPL[3]:1
 [2] X()
     @ REPL[2]:1
 [3] (::Type{blah})(::Float64) where blah<:X
     @ REPL[4]:1
 [4] (::Type{blah})(::Float64) where blah<:Y
     @ REPL[5]:1

```

Julia sees all of these as type constructor methods, and only the one subtyping the supertype seems to do something beyond the 1 type, and that is indeed a pattern that shows up frequently, check `methods(Int)`.

PS also found out that Julia doesn’t disallow `::DataType` and `::Type` in the callable position like it disallows `::Function` and `::Any`, but those are just as bad.

---

<div class="post-metadata">

**Author:** ![rayegun](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rayegun/32/26729_2.png) [@rayegun](https://discourse.julialang.org/u/rayegun)\
**Post date:** [February 29, 2024, 4:14am UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598/7 "2024-02-29T04:14:19Z")

</div>

One possible reason is just ergonomically defining constructors with all concrete parameters? It gives you access to the constructor you need within the function obviously. If parameters are added you don’t need to worry about changing constructor signatures.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [March 1, 2024, 2:26pm UTC](https://discourse.julialang.org/t/are-these-type-functors-the-same-as-outer-constructors/110598/8 "2024-03-01T14:26:02Z")

</div>

The in-development version of the Manual mentions this: [Constructors are just callable objects](https://docs.julialang.org/en/v1.12-dev/manual/constructors/#Constructors-are-just-callable-objects). This was the PR: [doc: manual: constructors: note the correspondence with callable objs by nsajko · Pull Request #53051 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/53051)
