Yes, the converse applies: if something is genuinely variable, make it a variable. At which point it’s certainly not bad behavior for a user to modify it, that’s expected behavior, and a dot-syntax on modules is coherent with the rest of the language.
What isn’t good is mutable global state which isn’t resilient to mutation from outside the module. I’m trying to avoid being doctrinaire here, but that combination very often means that changing that global state will modify behavior from “upstream” of the change, and that’s a bad problem to have. The user setting that global to the wrong value is merely a special case of the problems which might arise.
public and private don’t have to carry the same semantics they carry in languages which get them from C++. Julia’s upcoming public is documentation, as I understand it, a way of marking something explicitly as part of the API without exporting it. It wouldn’t be needed if Julia didn’t have the using keyword, but it does, and in my opinion the convenience of using makes up for the problems it can cause.
private, if it’s ever added, can serve to prevent access to a variable outside of the defining module. The compiler could use that directive to eliminate the symbol entirely, so there’s no variable left to access, just compiled references to the memory it’s using. Whether this is philosophically compatible with Julia isn’t something I have an opinion on, but it’s definitely possible to add a feature like that.
I wish ImmutableDict were called something else, actually, like AList, because that’s what they are: a linked list of key/value pairs. Plenty of times that such a thing is useful, but it isn’t useful for my case, because adding a second definition of a key shadows the first. What I’d like is a Dict where redefining a key has no effect, Base doesn’t have one of those, and it’s not quite worth writing my own wrapper struct over Dict to provide that behavior. At the end of the day, it’s the user’s code once they load it, if they want to break it, I’m not strongly motivated to prevent them from doing so.
I would make it private as well as const if it were possible to do that, fwiw. it’s intended to be an append-only cache, which is only added to using a particular function, and if I could enforce that as an invariant, I would, it’s good practice.