This proposal is a combination of two proposals to evolve Golang towards a capabilties-based language.
1. Modify the const keyword to allow holding mutable (and new immutable) types. 2. Implement faster immutable struct assignment. In Rust, immutability is deep, so you can't modify the internals of any object if your reference is not Mut. From https://doc.rust-lang.org/book/first-edition/mutability.html: Mutability is a property of either a borrow (&mut) or a binding (let mut). This means that, for example, you cannot have a struct with some fields mutable and some immutable: The mutability of a struct is in its binding. In Go, the design philosophy includes embeddable encapsulation. We can leverage the language rules to create a capabilities-based language. The addressable (mutable) vs non-addressable (immutable) struct semantics takes us 90% of the way there. What's missing I think are 2 things: 1. Secure modules w/ the const-mutable type 2. Compiler optimizations for immutable struct copying. <https://gist.github.com/jaekwon/fc0e700f0cb09ea95fe9d6655f98b57e#1-secure-modules-w-the-const-mutable-type>1. Secure modules w/ the const-mutable type The prososal is to allow what would otherwise be assignable to a var, to const (but disallow function calls). // These are all OK const MyArray = make([]byte, 10) // const mutable (slice) type (all slices are mutable) const MyStruct = MyStruct{} // const immutable (struct) type const MyStructP = &MyStruct{} // const mutable (struct) type const MyStruct MyInterface = MyStruct{} // const immutable (interface) type w/ struct value const MyStructP MyInterface = &MyStruct{} // const mutable (interface) type w/ pointer value const MyFunc = func(){...} // const immutable func type (all funcs are immutable) Here, const doesn't mean immutable. It just means you can't change the shallow value. There is already a distinction between typed and untyped consts. This only works for typed consts, and further introduces a distinction between const-mutable const-immutable types. While the procedural behavior of const func types are always "immutable", they may have side effects. The right hand side expression of a const declaration may not include a function *call*. This limits the scope of these new const-mutable and const-immutable to those that won't cause a const initialization fiasco (see https://groups.google.com/forum/m/#!topic/golang-nuts/BnjG3N77Ico). The type of values you can assign to a const are more expressive, so we now have no excuse to declare module-level var variables which can be (maliciously or not) modified by anyone who imports the module. (Of course we can declare a global function func GetMyStructP() *MyStruct { ... }) that more or less does the same thing, but nobody does that because it's easier to use var, and what's the point of doing the right thing unless there's a commitment to evolve the language toward a capabilities-based system?). Go linters can start tagging exported global vars that aren't annotated to be safe to mutate by anyone. <https://gist.github.com/jaekwon/fc0e700f0cb09ea95fe9d6655f98b57e#compiler-optimizations-for-immutable-struct-copying>Compiler optimizations for immutable struct copying. You might have seen the rule of thumb for values-vs-pointers: if your struct has few fields, and you don’t need to mutate it, then you don’t need to use pointers. On the other hand, if the struct has too many fields, then you might want to use pointers. I find it difficult to always tell ahead of time whether structs ought to be pointers or not, but recently I discovered a nice way to work around the performance problem: type BigStructWrapper interface {} type BigStruct struct { ... } // cpy is immutable but this is slow. // I've tested this w/ benchmarks and very large // structs that are nested many levels. { var str BigStruct = BigStruct{...} var cpy BigStruct = str } // cpy is still immutable and this is fast. { var str BigStructWrapper = BigStruct{...} var cpy BigStructWrapper = str } Interface values are like pointers, but the value of an interface is not addressable so you can't mutate an interface value's shallow fields unless it's a pointer. But a non-pointer struct is immutable, so I suspect it's possible for Golang to optimize the copying/assignment of these structs by allocating them somewhere outside the stack with ref counting. Then we have a complete capabilities-based security model for Golang. (1) Forget the old rule about using pointers when the struct has too many fields. Always use non-pointer values if you don't want others to mutate your copy. (2) Do not expose anything that can be mutated by a malicious party, even the users of your module. My hope is that Golang can evolve in this way, and even evolve the plugin system, such that we can allow the plugging-in of relatively untrusted (e.g. after filtering the AST for bad imports etc) code (see https://golang.org/pkg/plugin/). This is already useful but if we also allow for plugins to become released, then I think that's everything we need to create safe runtime extensibility of Golang services. We'd certainly use it for [Tendermint](https://github.com/tendermint/tendermint). -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.