# Redefining structs without restart?

**URL:** https://discourse.julialang.org/t/redefining-structs-without-restart/50826
**Category:** Internals & Design
**Created:** [November 24, 2020, 5:08pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826 "2020-11-24T17:08:10Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)
#### Post date: [November 24, 2020, 5:08pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/1 "2020-11-24T17:08:10Z")

</div>

> [@Will Julia ever fix its "using ..." latency problems?](https://discourse.julialang.org/t/will-julia-ever-fix-its-using-latency-problems/50659/25):
>
> For that, Revise is not enough and I keep having to restart the session whenever I touch a `struct` or a global constant. I don’t even know why they are treated differently from functions; it seems to me that it should be more difficult to update/delete functions.

One reason is that we don’t keep backedges to type constructors, and consequently Julia doesn’t know what code it needs to invalidate if you change a type definition. There’s good reason to avoid backedges for type constructors: can you imagine if every `Int(x)` was tracked in the codebase? Bloat-city.

> [@Will Julia ever fix its "using ..." latency problems?](https://discourse.julialang.org/t/will-julia-ever-fix-its-using-latency-problems/50659/25):
>
> When working on a script, `Revise.includet` is pretty useless: it doesn’t redefine any data, it only updates functions, so you have to use `include` anyway.

That’s intentional, because there’s no good solution to the problem of “what do I need to recalculate if my definitions change?” If you want to recalculate everything, just put your function definitions in one file that you `includet` and then your calculations in another file that you `include`. If you just need selective re-calculation (a few lines here and there), use inline evaluation from VSCode.

The Revise workflow is indeed not ideal, for the very reasons you cite. But from what I understand it is much better than Python _if_ you’re developing Python libraries (which you may not).

---

<div class="post-metadata">

### Author: ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)
#### Post date: [November 24, 2020, 6:35pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/2 "2020-11-24T18:35:54Z")

</div>

> [@tim.holy](#):
>
> There’s good reason to avoid backedges for type constructors: can you imagine if every `Int(x)` was tracked in the codebase? Bloat-city.

Is tracking `+(a::Int, b::Int)` and others much less demanding?

---

<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: [November 24, 2020, 6:37pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/3 "2020-11-24T18:37:21Z")

</div>

Yes. The number of numbers in a program can easily be in the billions, but the number of functions is probably \<10000.

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [November 24, 2020, 6:42pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/4 "2020-11-24T18:42:19Z")

</div>

This is really a curiosity I have: Some people say that they simply rename all their structs and continue coding with Revise, and that that is a working workaround. Could that be a workaround implemented in Revise directly, like it renaming all user-defined structs under the hood to something like `MyStruct_rev1`, each time? Could that be an optional parameter for revise?

---

<div class="post-metadata">

### Author: ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)
#### Post date: [November 24, 2020, 6:53pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/5 "2020-11-24T18:53:08Z")

</div>

Or why not just shadow the old structure, as is done in Python, where if you execute twice

```python
class MyAwesomeClass:
    pass

```

you create a new class, and the old one still exists but is inaccessible?

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [November 24, 2020, 6:56pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/6 "2020-11-24T18:56:56Z")

</div>

I think there the problem is that every method that specialized to the previous type would break. If the type is changed, the methods need to specialize again, and for that they must know that the type changed. Thus the name change is required.

---

<div class="post-metadata">

### Author: ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)
#### Post date: [November 24, 2020, 6:59pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/7 "2020-11-24T18:59:31Z")

</div>

Hmm… Actually, the old specializations would apply to the old structure, if you still have some objects of that type lying around, but the function would have to specialize anew for the redefined structure. And moreover, isn’t this issue similar to updating specializations when you redefine a function that you depend on? Also in that case you have to detect somehow that you must update the specializations.

---

<div class="post-metadata">

### Author: ![Volker\_Weissmann](https://avatars.discourse-cdn.com/v4/letter/v/c2a13f/32.png) [@Volker\_Weissmann](https://discourse.julialang.org/u/Volker_Weissmann)
#### Post date: [November 24, 2020, 7:03pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/8 "2020-11-24T19:03:46Z")

</div>

> [@Will Julia ever fix its "using ..." latency problems?](https://discourse.julialang.org/t/will-julia-ever-fix-its-using-latency-problems/50659/42):
>
> This may be viable when working with scripts (it is still ugly, and the history in the REPL becomes a useless mess), but it’s definitely not an option while developing modules. I’m mostly concerned with that. I find that working on modules is very tiresome because of the constant restartings required. And testing incurs the loading penalty every time too. To be completely honest, my workflow seems to me slower than with a compiled language such as Rust.

Same here.  
I wish you could redefine structures. The only workaround I know of is putting it inside a module:

```julia
module Data
    mutable struct MyStruct
        x::Int
    end
end

```

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [November 24, 2020, 7:05pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/9 "2020-11-24T19:05:59Z")

</div>

As I understand, for a new specialization to occur, the object type must change its “name”, that is why the renaming is a possible workaround.

Redefining a function is different, because while the types are constant, either the function recognizes that it is been called by with a new type and must specialize again, or the method is already defined. The old specialized method continues around, and that is not an issue.

The bottom line seems to be which information is needed for function specialization. If it is the type names, than the names must change.

---

<div class="post-metadata">

### Author: ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)
#### Post date: [November 24, 2020, 7:06pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/10 "2020-11-24T19:06:49Z")

</div>

Well, yes and no. Again, this works fine for scripts and without using Revise, by exploiting the fact that in the REPL you are allowed to replace modules (you still get a reprimand `WARNING: replacing module Data.`, but who cares?). This however doesn’t help much when developing packages imported with Revise.

---

<div class="post-metadata">

### Author: ![Volker\_Weissmann](https://avatars.discourse-cdn.com/v4/letter/v/c2a13f/32.png) [@Volker\_Weissmann](https://discourse.julialang.org/u/Volker_Weissmann)
#### Post date: [November 24, 2020, 7:09pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/11 "2020-11-24T19:09:24Z")

</div>

My “module Data” usecase was about not using Revise.

---

<div class="post-metadata">

### Author: ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)
#### Post date: [November 24, 2020, 7:21pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/12 "2020-11-24T19:21:37Z")

</div>

> [@lmiq](#):
>
> Redefining a function is different, because while the types are constant, either the function recognizes that it is been called by with a new type and must specialize again, or the method is already defined. The old specialized method continues around, and that is not an issue.

Sorry maybe I expressed myself badly. What I meant is, if you have

```julia
g(x) = ...
f(x) = g(x)

```

specialize `f` and then redefine `g`, then `f` must detect that the specialization it already has is old and must be updated. I think this is something that wasn’t present from the beginning and got implemented around 0.6. So there is already a mechanism to detect when a specialization has to be updated.

Now, regarding structures, I imagine that every structure has a representation somewhere in the internals of Julia. When I do `struct S ... end`, something is allocated somewhere to keep track of this structure. What I’m suggesting is that if I execute `struct S ... end` again, then a new structure is created, which happens to have the same name (but is still a different entity internally). This is similar to what Python does:

```python
class C:
    pass
print(id(C))
class C:
    pass
print(id(C))

```

prints two different identities, because two classes with the same name are created, and the latter shadows the former in the current namespace (but the old still exists).

Then, functions could respond with the specializations they already have to arguments of the old type (if you happen to still have some around), and would produce a fresh specialization if you pass objects of the new type. Internally the two types are distinguishable, you just lose a “handle” to refer to the old type.

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [November 24, 2020, 7:40pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/13 "2020-11-24T19:40:33Z")

</div>

> **[GitHub - BeastyBlacksmith/ProtoStructs.jl: Easy prototyping of structs](https://github.com/BeastyBlacksmith/ProtoStructs.jl)**
>
> Easy prototyping of structs. Contribute to BeastyBlacksmith/ProtoStructs.jl development by creating an account on GitHub.

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [November 24, 2020, 7:42pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/14 "2020-11-24T19:42:00Z")

</div>

Probably for an in-depth discussion on this you should refer to:

[https://github.com/timholy/Revise.jl/issues/18](https://github.com/timholy/Revise.jl/issues/18)

The take-away from there, it seems, is that there might be a solution. We just need more timholys in the community.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [November 24, 2020, 8:09pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/15 "2020-11-24T20:09:24Z")

</div>

> [@FedericoStra](#):
>
> Now, regarding structures, I imagine that every structure has a representation somewhere in the internals of Julia. When I do `struct S ... end` , something is allocated somewhere to keep track of this structure. What I’m suggesting is that if I execute `struct S ... end` again, then a new structure is created, which happens to have the same name (but is still a different entity internally). This is similar to what Python does:

I’ll just be so bold as to quote myself (though I’m fairly certain I’ve read something along those lines from other people as well 🤔)

> [@Objects whose structure can be redefined](https://discourse.julialang.org/t/objects-whose-structure-can-be-redefined/47733/4):
>
> The problem with redefining structs is that all existing code using that struct would have to be recompiled, as the new number of fields necessarily means a different memory layout as well. Doing this on-the-fly would mean potentially having to recompile the very code you’re running right now while it’s running, and since that’s not allowed, struct redefinition at runtime isn’t either.

To expand on that (and not make this shameless self promotion):

Julia has `eval` (and its macro companion, `@eval`), which evaluates an Expression at runtime in global scope. Now imagine the following:

```julia
struct IntWrapper
   a::Int
end

function increment(a::IntWrapper)
    a.a= + 1
end

function f()
    a = IntWrapper(1)

    # no wait, actually, I want IntWrapper to wrap Floats as well
    @eval struct IntWrapper
        a::Union{Int,Float64}
    end

    b = IntWrapper(5.0) # wait, which Constructor will be called now? And which type will `b.a` have?

   increment(a) # wait, do we print here as well..?
   increment(b)
end

```

Julia is a compiled language, not interpreted. This means that, when I call `f()`, the function `f` _as a whole_ is compiled to machine code. But I have `eval` code in there that changes the behaviour of the code afterwards while staying in the same function! That’s impossible, so it’s disallowed.

There are more details here, but that’s the gist of it. You could of course change all function calls to make a dynamic lookup in case the definition of the types or the function has changed… but then you lose all benefit of compiling functions in the first place and you’re back to interpreted speeds (which, I’m sure, you also don’t want).

It’s easy to say “why not just do x” and of course you _could_ do x, but that often comes at the cost of things we really want to have, like fast, native, compiled code that can run everywhere. If you insert dynamic lookups at any point that you call a function, writing e.g. GPU kernels is right out (without resorting to a second compiler). There are a lot of design decisions like this, and often there sadly isn’t a straightforward, compact answer why it is that way.

* * *

In any case, there have been _A LOT_ of topics on this forum about this and similar things already - you’re not the first to encounter them and won’t be the last. There’s also a lot of issues on the issue tracker, so please do a little more research before pointing to feature X from Y and ask why julia doesn’t do that and that it’ll be just so easy to do.

---

<div class="post-metadata">

### Author: ![Volker\_Weissmann](https://avatars.discourse-cdn.com/v4/letter/v/c2a13f/32.png) [@Volker\_Weissmann](https://discourse.julialang.org/u/Volker_Weissmann)
#### Post date: [November 24, 2020, 8:31pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/16 "2020-11-24T20:31:00Z")

</div>

Would this problem still exist if there would be no `eval` and `@eval` command?  
(I’m not proposing to remove these commands, I just want to understand how Julia works.)

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [November 24, 2020, 10:00pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/17 "2020-11-24T22:00:22Z")

</div>

> [@Will Julia ever fix its "using ..." latency problems?](https://discourse.julialang.org/t/will-julia-ever-fix-its-using-latency-problems/50659/69):
>
> Thank you for your explanation.

You’re welcome! Thank you for reading it 🙂

If there’s anything that’s confusing or seems unintuitive to you, please don’t hesitate to open a new topic and ask about what’s weird to you.

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [November 24, 2020, 11:47pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/18 "2020-11-24T23:47:25Z")

</div>

This section of the manual also provides some insight on the difficulties of what you propose:

The types [`Bool`](https://docs.julialang.org/en/v1/base/numbers/#Core.Bool), [`Int8`](https://docs.julialang.org/en/v1/base/numbers/#Core.Int8) and [`UInt8`](https://docs.julialang.org/en/v1/base/numbers/#Core.UInt8) all have identical representations: they are eight-bit chunks of memory. Since Julia’s type system is nominative, however, they are not interchangeable despite having identical structure. A fundamental difference between them is that they have different supertypes: [`Bool`](https://docs.julialang.org/en/v1/base/numbers/#Core.Bool)'s direct supertype is [`Integer`](https://docs.julialang.org/en/v1/base/numbers/#Core.Integer), [`Int8`](https://docs.julialang.org/en/v1/base/numbers/#Core.Int8)'s is [`Signed`](https://docs.julialang.org/en/v1/base/numbers/#Core.Signed), and [`UInt8`](https://docs.julialang.org/en/v1/base/numbers/#Core.UInt8)'s is [`Unsigned`](https://docs.julialang.org/en/v1/base/numbers/#Core.Unsigned). All other differences between [`Bool`](https://docs.julialang.org/en/v1/base/numbers/#Core.Bool), [`Int8`](https://docs.julialang.org/en/v1/base/numbers/#Core.Int8), and [`UInt8`](https://docs.julialang.org/en/v1/base/numbers/#Core.UInt8) are matters of behavior – the way functions are defined to act when given objects of these types as arguments. This is why a nominative type system is necessary: if structure determined type, which in turn dictates behavior, then it would be impossible to make [`Bool`](https://docs.julialang.org/en/v1/base/numbers/#Core.Bool) behave any differently than [`Int8`](https://docs.julialang.org/en/v1/base/numbers/#Core.Int8) or [`UInt8`](https://docs.julialang.org/en/v1/base/numbers/#Core.UInt8).

---

<div class="post-metadata">

### Author: ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)
#### Post date: [November 25, 2020, 5:29pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/19 "2020-11-25T17:29:34Z")

</div>

@Sukera  
Nothing in [your answer](https://discourse.julialang.org/t/will-julia-ever-fix-its-using-performance-problems/50659/58) is a good argument of why it shouldn’t be possible to redefine structures. The example you give with `@eval` can be flipped around and used to argue that redefining functions is bad too. Consider

```julia
h() = "old"
g() = println(h())
function f()
    g()
    @eval h() = "new"
    g()
end
f()

```

What should it print? `"old"` and `"old"`, or `"old"` and `"new"`? It turns out that the answer is the former, so we could decide that your example should have a similar semantic and the redefinition of `IntWrapper` comes into effect only after the execution of `f`, not during. This however is not an argument against redefining structures.

Moreover, consider the following code too:

```julia
function foo end

module M
  struct S end
  Main.foo(::S) = print("old")
end

s1 = M.S()

module M
  struct S
    x::Int
  end
  Main.foo(s::S) = print("new $(s.x)")
end

s2 = M.S(42)

foo(s1) # prints "old"
foo(s2) # prints "new 42"

```

Here, we can play the trick of redefining the module `M`, so we end up with two indipendent types both called `M.S`. The function `foo` is still able to distinguish them and specializes accordingly. Where is the problem?

What I’m suggesting is an extension of the current semantic of the language. I propose that we should be able to do the same as in the last example, without putting `S` inside a module. The following code

```julia
function foo end

struct S end
foo(::S) = print("old")

s1 = S()

struct S
  x::Int
end
foo(s::S) = print("new $(s.x)")

s2 = S(42)

foo(s1) # prints "old"
foo(s2) # prints "new 42"

```

should have the same behavior. Namely, two distinct types `S` are created, both named `Main.S`, and the function `foo` specializes separately for the two types.

This doesn’t look at all impossible to do to me. When you “redefine” a structure, in reality you actually define a _new_ structure which happens to have the same name. The old structure still exists, you simply lose the possibility to refer to it by the same name in the current namespace, because that name now refers to the new structure.

* * *

> [@Sukera](#):
>
> In any case, there have been _A LOT_ of topics on this forum about this and similar things already - you’re not the first to encounter them and won’t be the last. There’s also a lot of issues on the issue tracker, **so please do a little more research before** pointing to feature X from Y and ask why julia doesn’t do that and that it’ll be just so easy to do.

I don’t like much the implication of what you are trying to say here. I’m not being lazy and just complaining _“Oh Julia is so crappy compared to COBOL!”_. I’m exploring outside the current semantic of the language and proposing options for possible extensions.

---

<div class="post-metadata">

### Author: ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)
#### Post date: [November 25, 2020, 5:38pm UTC](https://discourse.julialang.org/t/redefining-structs-without-restart/50826/20 "2020-11-25T17:38:52Z")

</div>

Yes, I understand what a [nominative type system](https://en.wikipedia.org/wiki/Nominal_type_system) is. But could you elaborate on how this implies that redefining structures should be impossible?

[Next page](https://discourse.julialang.org/t/redefining-structs-without-restart/50826.md?page=2)
