What's so mutable about `Symbol`s?

May someone explain the rationale behind making Symbols mutable? They seem to have no fields to mutate!

Where did you see something that said Symbols are mutable?
They are very much immutable, and (as an implementation detail) are interned as well, so that you can compare for equality simply by checking the pointers, instead of doing an O(n) comparison.

julia> isimmutable(:x)
false

That’s really strange!

Maybe you should raise an issue about that. isimmutable returns true for a String pre-v0.6, but false after, and other things that also are immutable by convention and in the documentation that are implemented with a mutable struct (BigInt, BigFloat), also return false.

Symbols are fairly special. They are one of the few types defined in C and have special representation and special handling pretty much everywhere in the compiler, so whether the runtime thinks it’s mutable or not doesn’t really matter. That said, returning true here would be more accurate. I’ll try flipping it and see what happens.

6 Likes

isbits also returns false btw.

That’s fine, it’s not. In particular, Symbols have an identity independent of their contents (the identities are linked, because Symbols are interned, but if you somehow had a different Symbol with identical contents, you’d have a problem). In particular this means that Symbols are always referenced by pointer.

1 Like

Any particular reason that String (which used to return true in v0.5) should return false?
Same thing for BigInt and BigFloat, which (at least by convention, same as String) are considered immutable?

https://github.com/JuliaLang/julia/pull/25349

3 Likes

Well, the reflection functions answer questions about the system, not convention. It is in fact possible to mutate a BigInt and there’s valid reasons to want to do so. Regarding String, I hope that with https://github.com/JuliaLang/julia/pull/25241 we can truthfully answer true here.

1 Like

I am aware of those reasons, but I think though that there are better ways of wrapping the underlying GMP (BigInt) and MPFR (BigFloat)'s structures, such that you would have faster, truly immutable types for those, with all the benefits that entails (like with the decimals in DecFP.jl), and have a separate clean wrapper for those cases where you really do want a reference to a mutable BigInt or BigFloat (for example, to be able to sum up a vector of BigFloat values.

I really like that, and I’ll add an extension to isimmutable now for my Strs package that returns true, as I’d already made sure those could not be aliased to a mutable vector.