# Let typeof(::Type{T}) where T = Type{T}

**URL:** <https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938>\
**Category:** Internals & Design\
**Tags:** question\
**Created:** [July 12, 2020, 12:14pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938 "2020-07-12T12:14:22Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [July 12, 2020, 12:14pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/1 "2020-07-12T12:14:22Z")

</div>

dispatching on function-like things can be quite tedious, as `typeof` as of now forgets information.  
While `typeof(::Function)` gives the function singleton type, `typeof(::Type{T}) where T`, i.e. typeof a Type-constructor, will return `DataType` or a respective other higher type, and as such looses the information about the type.

I want to discuss whether it makes sense to change this in general such that

```julia
typeof(::Type{T}) where T = Type{T}
supertype(::Type{Type{T}}) where T = ... # the same as now ``typeof(::Type{T}) where T``, i.e. DataType, UnionAll, etc.

```

For an example let’s choose `T = Some`, then I would suggest to have the following

```julia
typeof(Some) # Type{Some}
supertype(typeof(Some)) # UnionAll

```

I am curious about other perspectives.

---

<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:** [July 12, 2020, 2:20pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/2 "2020-07-12T14:20:44Z")

</div>

It is generally not recommended to operate in type space in Julia (this is not spelled out very explicitly, but cf [this faq](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-confusion-about-whether-something-is-an-instance-or-a-type-1)). This can easily lead to overly specialized code in cases where it may not be needed.

`Type`s ending up as `DataType` is kind of an escape valve so that the compiler gets a break. If necessary, you can sharpen things up to get a `Type`, like the method you define. But generally it is an anti-pattern in Julia.

It would be interesting to see a use case though if you have an MWE.

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [July 12, 2020, 2:25pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/3 "2020-07-12T14:25:43Z")

</div>

My usecase is better type-inference 😉 and I truly hope that to achieve typeinference it is not an anti-pattern to use Type{T}.

I build a package called [IsDef.jl](https://github.com/schlichtanders/IsDef.jl) which provides some type-inference helpers which are very handy for me. I was just in the process of fixing the `apply` thing (there was another issue for this where you already helped me considering function-type vs function-value. It works now, but was more difficult than expected)

---

<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:** [July 12, 2020, 2:44pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/4 "2020-07-12T14:44:27Z")

</div>

Yes, I think that

> dispatching on whether certain methods are implemented or not

is an anti-pattern in Julia, and so is relying too much on inferred return types (if I understand correctly, these are the two things your package does).

Again, an MWE / use case would be interesting and may result in suggestions for better solutions.

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [July 12, 2020, 2:52pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/5 "2020-07-12T14:52:46Z")

</div>

Understood. Thanks for the generalized phrasing 😉 helped.

I am soon going to publish a package I call `TypeClasses` which makes use of `IsDef` and leads at least for me very clean code. I am currently in the process of adding CI, Docs, Codecov and all this, so should soon be ready hopefully. As you for sure know, TypeClasses themselves are more like a Tool, but at least there are many commonly known examples for the abstraction power of TypeClasses. Actually I myself build a package `ExtensibleEffects` which builds upon `TypeClasses` and makes use of a couple of them. Also this is in the same process and soon going to be officially registered hopefully.

* * *

The [faq](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-confusion-about-whether-something-is-an-instance-or-a-type-1) does not explain why something like `IsDef` would be discouraged. The faq rather recommends a style, but does not discourage the use of inference in general.  
To add, my experiments so far, as well as my understanding of what is going on, is that something like `IsDef.isdef` is indeed stable enough to be used and recommended.

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [July 12, 2020, 3:02pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/6 "2020-07-12T15:02:45Z")

</div>

Now I actually thought of a concrete simple example.

I from time to time use a simple Type I call ContextManager (in analog to python’s contextmanagers). You can find one implementation in my package [DataTypesBasic.jl](https://github.com/schlichtanders/DataTypesBasic.jl) (that package will definitely be released this upcoming week ;-)).

Here the type, it’s super simple

```julia
struct ContextManager{F}
  func::F
end

```

and an example would be

```julia
ContextManager(function (cont)
    println("do some initialization to get 42")
    returnme = cont(42)
    println("do some cleanup for 42")
    return returnme
end)

```

I hope that also clarifies the idea of this construct. It is like a container with initilization and destruction.

Now the usecase: How to define `Base.eltype` for this container? You can do it with type-inference, which may fail in certain complex cases, but fail in being broader, if I understood it correctly, i.e. returning Any. Which is totally fine here.

So we can define

```julia
apply(f, args...) = f(args...)
function Base.eltype(::Type{<:ContextManager{F}}) where F
    Core.Compiler.return_type(apply, Tuple{F, typeof(identity)})
end

```

or using `IsDef` (which is what I actually do currently)

```julia
using IsDef
function Base.eltype(::Type{<:ContextManager{F}}) where F
  Out(apply, F, typeof(identity))
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:** [July 13, 2020, 8:47am UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/7 "2020-07-13T08:47:38Z")

</div>

I still lack context for the use case (your library is about _how_ to do something you consider useful, but I don’t understand _why_ one would want to do this), but generally I would just try to avoid defining `eltype` when the information is not readily available. Eg I am not sure why a “container” is the best abstraction for something that will be calculated on demand.

Eg if you are `collect`ing resuls from calling that closure, Julia’s type inference may figure out the type just fine if everything is type stable. There is a mechanism for iterables not knowing their `eltype` and it can still compile to efficient code, you don’t have to go out of your way to do the job of the compiler (that’s the anti-pattern here).

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 13, 2020, 1:26pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/8 "2020-07-13T13:26:39Z")

</div>

You can use `Core.Typeof` in limited cases, but I agree with Tamas — this isn’t something you should really need to do often.

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [July 13, 2020, 2:10pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/9 "2020-07-13T14:10:26Z")

</div>

Why you would like to define something like ContextManager: You want to bind an initialization together with a destruction into a unified abstraction (a Monad, or a “Container”, or how you would want to call it).  
The issue however is more general and applies to any “container” which is build upon functions. It is similar to empty containers as such, and hence would allow for a use of `Base.promote_op`/`Core.Compiler.return_type`

The question seems to be whether you would rather leave `eltype(...) = Any` or provide it with the custom-type-inference fallback. I understood that you better don’t use `eltype` at all, but look at the concrete elements and take `typeof`. But sometimes you may still want to use it and then it is better to have something possibly better than `Any`.

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [July 13, 2020, 2:22pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/10 "2020-07-13T14:22:07Z")

</div>

@mbauman I never heard about `Core.Typeof` and also couldn’t find any documentation on a quick search. Can you link me to further details?

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 13, 2020, 3:14pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/11 "2020-07-13T15:14:38Z")

</div>

Not really — it’s an internal function that shouldn’t be needed in user code. It’s just `Typeof(x) = isa(x,Type) ? Type{x} : typeof(x)`.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [July 13, 2020, 3:39pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/12 "2020-07-13T15:39:19Z")

</div>

I have a feeling it’s another X Y problem… for starter, `eltype` means elements type and your struct is not a collection at all, you might as well just give it another field.

---

<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:** [July 13, 2020, 5:01pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/13 "2020-07-13T17:01:28Z")

</div>

> [@schlichtanders](#):
>
> You want to bind an initialization together with a destruction into a unified abstraction (a Monad, or a “Container”, or how you would want to call it).

A monad is _how_ you want to do something in certain languages (eg Haskell). It is almost certainly not _what_ you want to do (ie the actual problem you want to solve, eg parse something). Monads fit perfectly into Haskell, but not Julia’s type system, which has no first class representation for monads (and arrows in general).

I agree with @jling that this may be an [XY problem](https://en.wikipedia.org/wiki/XY_problem). I think that this discussion is going in circles because of this.

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [July 13, 2020, 6:33pm UTC](https://discourse.julialang.org/t/let-typeof-type-t-where-t-type-t/42938/14 "2020-07-13T18:33:24Z")

</div>

> [@Tamas\_Papp](#):
>
> Monads fit perfectly into Haskell, but not Julia’s type system, which has no first class representation for monads (and arrows in general).

I disagree 😉 Monads very well fit into Julia from my perspective. I will soon release a couple of packages which I hope can convince others too.

* * *

Anyhow, this discussion indeed went far off. I originally just wanted to discuss the precise proposal I made about `typeof` and `supertype`, but then found the type-inference discussions too interesting. Thanks for all your inputs!

`Core.Typeof` seems to be half of an answer to my original question, but missing on the `supertype` relationship I suggested (obviously, as this hardly can be redefined in existing julia without breaking anything). Hence I mark @Tamas_Papp very first general answer as the answer. Thanks again
