# Outer-only constructors and concrete types

**URL:** <https://discourse.julialang.org/t/outer-only-constructors-and-concrete-types/87036>\
**Category:** Performance\
**Created:** [September 10, 2022, 11:15am UTC](https://discourse.julialang.org/t/outer-only-constructors-and-concrete-types/87036 "2022-09-10T11:15:48Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![pgoulart](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pgoulart/32/17514_2.png) [@pgoulart](https://discourse.julialang.org/u/pgoulart)\
**Post date:** [September 10, 2022, 11:15am UTC](https://discourse.julialang.org/t/outer-only-constructors-and-concrete-types/87036/1 "2022-09-10T11:15:48Z")

</div>

Suppose I have a type like this, taken from the docs on outer-only constructors:

```julia
struct Foo{T<:Number,S<:Number} <: SuperType{T}
    data::Vector{T}
    sum::S
    function Foo(a::Vector{T}) where T
        S = widen(T)
        new{T,S}(a, sum(S, a))
    end
end

```

The type `S` in the above is not independent of `T`, in the sense that there is no way to make a `Foo{Float32,Int32}` or whatever. If I call the constructor using

```julia
foo32 = Foo(zeros(Float32,2))

```

I will always get a `Foo{Float32, Float64}`.

However, `Foo{Float32}` is itself not a concrete type, even though `T = Float32` is enough to fully determine what type `foo32` will be above.

Is there a way to make some parametric subtype or alias such that `Foo{Float32}`, or some variation thereof, becomes concrete?

I want to do something sort of like this (which doesn’t work):  
`ConcreteFoo{T} = Foo{T,widen{T}}`

---

<div class="post-metadata">

**Author:** ![lferrant](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lferrant/32/22751_2.png) [@lferrant](https://discourse.julialang.org/u/lferrant)\
**Post date:** [September 10, 2022, 12:50pm UTC](https://discourse.julialang.org/t/outer-only-constructors-and-concrete-types/87036/2 "2022-09-10T12:50:39Z")

</div>

I think the following could help achieve your goal

```julia
julia> footype(::Type{T}) where {T<:Number} = Foo{T,widen(T)}
footype (generic function with 1 method)

julia> footype(Int)
Foo{Int64, Int128}

julia> isconcretetype(footype(Int))
true

```

---

<div class="post-metadata">

**Author:** ![pgoulart](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pgoulart/32/17514_2.png) [@pgoulart](https://discourse.julialang.org/u/pgoulart)\
**Post date:** [September 10, 2022, 1:41pm UTC](https://discourse.julialang.org/t/outer-only-constructors-and-concrete-types/87036/3 "2022-09-10T13:41:44Z")

</div>

Thanks. I agree that that will return the fully specified type to me based on only `T`. What I’m after though is a completely new type, not a function returning the existing type.

---

<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:** [September 11, 2022, 11:36am UTC](https://discourse.julialang.org/t/outer-only-constructors-and-concrete-types/87036/4 "2022-09-11T11:36:56Z")

</div>

I don’t think there’s a way to do what you’re asking for. Type aliases with fewer type parameters must make the removed type parameters constant e.g. `Vector = Array{T, 1} where T`. In your case, both `T` and `S` vary, even if `S` is intended to entirely depend on `T`. There is a good reason for this: `S` can’t be specified or proven in the type to entirely depend on `T`. For one, the intended dependence is done by a constructor method that is separate from, albeit related to, the type. For another, the dependence requires the constructor method to be pure, which can’t be guaranteed. For example, I could define a `widen` method that returns various types depending on a global variable or a random selection, so the same `T` could result in different `S` across instances. So for guaranteed precision, the type _does_ need both `T` and `S` as parameters.

Still, you can make assumptions about `S`’s dependency on `T` to make things easier to read and write. lferrant’s `footype(Int)` is the straightforward way to make `Foo{Int, widen(Int)}` easier to write (forget the `{}` syntax, that’s for writing the precise types). You can overload `Base.show` to change how the type is printed. I haven’t actually done this before so I can’t claim this is best practice, but:

```julia
# changes how the instance foo32 is printed
function Base.show(io::IO, me::Foo{T,S}) where {T,S}
    print(io, "Foo{", T, "~}(", me.data, ", ", me.sum, ")")
end

# changes how the type typeof(foo32) is printed
# I read this is unadvisable but I'm not sure exactly why
# this does prevent printing of S in the precise type
function Base.show(io::IO, me::Type{Foo{T,S}}) where {T,S}
    print(io, "Foo{", T, "~}")
end

```

```julia
julia> foo32
Foo{Float32~}(Float32[0.0, 0.0], 0.0)

julia> typeof(foo32)
Foo{Float32~}

julia> Foo{Float32} # this is still abstract, and S is obscured
Foo{Float32~} where S<:Number

```

---

<div class="post-metadata">

**Author:** ![pgoulart](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pgoulart/32/17514_2.png) [@pgoulart](https://discourse.julialang.org/u/pgoulart)\
**Post date:** [September 12, 2022, 1:26pm UTC](https://discourse.julialang.org/t/outer-only-constructors-and-concrete-types/87036/5 "2022-09-12T13:26:25Z")

</div>

Thanks both.
