# Revise type annotations without edits?

**URL:** https://discourse.julialang.org/t/revise-type-annotations-without-edits/128700
**Category:** General Usage
**Tags:** type, revise, struct
**Created:** [May 5, 2025, 4:16am UTC](https://discourse.julialang.org/t/revise-type-annotations-without-edits/128700 "2025-05-05T04:16:03Z")
**Posts on this page:** 1
**Page:** 1

<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: [May 5, 2025, 4:16am UTC](https://discourse.julialang.org/t/revise-type-annotations-without-edits/128700/1 "2025-05-05T04:16:03Z")

</div>

Because of the upcoming world age-partitioned semantics ([PR #57253](https://github.com/JuliaLang/julia/pull/57253)), Revise can pull off type redefinitions by reassigning the `const` name ([Issue #18](https://github.com/timholy/Revise.jl/issues/18)).

Let’s say we start with:

```julia
julia> begin
       struct X{T} x::T end;
       unwrap(a::X) = a.x; # argument annotation, body uses field
       square(a::X) = unwrap(a) ^ 2; # argument annotation
       struct Y{T} y::X{T} end; # field annotation, uses a parameter
       wrap(x) = X(x); # const X name in body
       wrap(1)
       end
X{Int64}(1)

```

Now we’re allowed to re-evaluate the struct definition (in Revise we’d just edit the source file):

```julia
julia> struct X end; # removes parameter and field

```

The obsolete type object still exists, which makes sense considering that there may still be instances around. Let’s look at the consequences for everything else:

```julia
julia> methods(unwrap) # not reevaluated, good because body needs change
# 1 method for generic function "unwrap" from Main:
 [1] unwrap(a::@world(X, 38433:38439))
     @ REPL[2]:1

julia> methods(square) # not reevaluated, could be because it fits new type
# 1 method for generic function "square" from Main:
 [1] square(a::@world(X, 38433:38439))
     @ REPL[3]:1

julia> dump(Y) # not reevaluated, good to avoid TypeError
UnionAll
  var: TypeVar
    name: Symbol T
    lb: Union{}
    ub: abstract type Any
  body: struct Y{T} <: Any
    y::@world(X, 38433:38439){T}

julia> wrap(1) # invalidated but fails, good because needs change
ERROR: MethodError: no method matching X(::Int64)
...

```

So besides invalidating methods like `wrap` that use the name `X`, the type redefinition doesn’t change annotations because the definitions used the type object at the time, not the name itself. In the case of `unwrap` and `Y`, that’s fine because we need to edit and reevaluate to make things work anyway. However, `square` happens to not need edits for its reevaluation, which makes things difficult for Revise’s file-editing design. It’d be strange to add useless lines just to trigger a change, what will be the course of action there?

Separately tracking variables used at definition-time and annotation structure to automatically reevaluate suitable definitions is not a solution because we’re allowed to reassign `const X = 1` or anything that isn’t a type, which will throw errors upon any annotations. That’s a lot of overhead for nothing. However, it does seem nice when we’re just changing types and have many definitions like `square` that happen to fit the newer type.
