There are some objections to immut because of its semantics and because it is not a common word/abbreviation (“ugly”).
The proposal with the least deviation from the status quo and the shortest names would then be:
read/mut, ReadOrigin/MutOrigin
I like that this proposal keeps the well established mut naming that is not only used as an argument convention but also in inferred refs/origins and parametrized types (mut = true). Implementing this proposal would not break most code while deviating from mut would be quite disruptive.
One minor objection I have to this proposal is that “read” has so many contexts/usages that you can’t simply search for it in the documentation while “immut”/“immutable” is more specific and therefore easier to search for.
When you put trait bounds on a type parameter, you list all the behaviours that you need the type to support. If you don’t list something, then you can’t use it. That’s why you can’t mutate an argument or origin for which you did not request mutability.
I agree that traits should be named after what they do, not what they don‘t. But we are discussing an argument convention and not a trait. Additionally the one thing that is special about this convention is that the callee can‘t mutate the argument and not that the argument can be read.
I suspect that whatever this convention is named, it will still be called an „immutable reference“ because that is what is important about it. Therefore I still thinkimmut or imm are viable proposals.
Hi, i like Origin.Readable and Origin.Writable,
the reason is that by having both share the same path,
it is possible to learn the other when only know one !
Dont know for Immut or Mut (have to think),
the main point is just how people can list the options, and how many are there
Here my personal favorites based on what has been discussed so far:
immut/mut, ImmutOrigin/MutOrigin
=> a clear distinction: “immutable“ vs. "mutable“
read/mut, ReadableOrigin/MutableOrigin
=> states what it does (like a trait): provides a “readable“ reference
imm/mut, ImmOrigin/MutOrigin
=> just three letters: imm, mut, ref, out, var, deinit
I for my part would rule out proposals that change mut to write because this would be quite disruptive and beyond the scope of this “clean up” proposal. But I think read/write is viable to consider if such a change is in scope from the viewpoint of the Modular team.
To jump on the bikeshedding, I am in favour of read/mut ReadableOrigin/MutableOrigin
I always disliked mut as a keyword because it looks like the English word mutt and I don’t see the point of the brevity. But in this case read(able) and mut(able) have direct and hopefully obvious parallels.
I also agree with the idea of traits needing to be“positive“ attributes. And in the base case of the trait names, we write things out for clarity. After years of writing Swift I prefer clarity over brevity. We all read much more code than we write after all.
As a newcomer here, I just wanted to share my first impressions. I am personally in favor of keeping read and mut as they are, especially since read will be the default. It feels important that the default be something you can understand instantly, without needing to decode an abbreviation.
From what I have seen in Rust and ML style languages like OCaml, bindings and function parameters are immutable by default, and you have to opt in to mutation explicitly. That lines up with Mojo, so I like that the default convention is called read. It is easy to explain in one sentence: you can read, you cannot write. It matches phrases people already know, like “read only reference,” and it pairs nicely with mut as “read vs mutate.”
immut makes sense in terms of consistency with ImmutOrigin and MutOrigin, but to me it reads more like a logical negation of mut than its own clear mode. I would rather see argument conventions read like a small list of distinct modes, each describing what you are allowed to do.
Overall, mut and read already seem pretty easy to understand. Even if read is not a standard keyword across ecosystems, its meaning feels very easy to guess from context.
Thank you for this example. Sometimes an example is worth more than many words. It illustrates well the trait-like nature of read/mut when parametrizing over the origins.
Looking again through all what has been discussed including the recent posts there seems to be quite some support and few opposition to this proposal:
read/mut, ReadableOrigin/MutableOrigin
It is sound from the viewpoint of the trait-like nature of the read/mut argument conventions. By renaming ImmutOrigin to ReadableOrigin the read argument convention is aligned with its corresponding origin.
We haven’t fully discussed this internally yet. I think we’d be open to keeping the read/mut argument convention but I would strongly be in favor of not adding the -able suffix to some of these helper aliases. As the -able suffix is mostly reserved for traits and these are not traits - they’re either values or comptime type values.
Simply having ReadOrigin/MutOrigin to maintain parity with the read/mut argument convention.
There are a few things that have still not been looked at yet.
This includes
<prefix>UnsafePointer
Currently this is ImmutUnsafePointer and MutUnsafePointer
the .as_<prefix>() casting function
We have as_immut() and as_immutable() inconsistently across the codebase
and lastly a few instance of comptime type values such as StringSlice.<prefix>.
Currently StringSlice.Mutable and StringSlice.Immutable
These ideally should all follow the same naming scheme for consistency.
In terms of opening a PR - it would likely be a good first step to make a [proposal] before modifying the codebase. So if/when a big-ish change like this is made, we have some documents and justifications to refer back to in a changelog.
Hi Nate,
Thank you for the explanation.
I think this is the main point why some in the community advocate against changing read to immut: Argument conventions should be considered trait-like.
If not, then I think we should rename read to immut like I proposed when starting this discussion.
I‘m ready to start writing a proposal but need direction on which way to go with the proposal: The consistent immut way or the consistent read way.
I‘m also fine with just keeping the slightly inconsistent status quo for now (read/mut, ImmutOrigin, MutOrigin).
Maybe the community gets accustomed to all the Immut… prefixed names (Immut*Origin, Immut*Pointer, StringSlice.Immutable, as_immut, …). Then, renaming read to immut becomes the no-brainer easy to implement consistency quick fix I proposed.
Writing a proposal to change read to immut would be easy and implementing it is an almost non-breaking change. I am ready to write this proposal.
Writing a proposal to change all the current Immut… names is much more demanding as immut/immutable is already such a widespread term in the Mojo stdlib and the Mojo documentation. There is not much support for ReadOrigin in the discussion too as read is a word on its own and therefore ReadOrigin is not easily recognizable as „readable origin“ while MutOrigin is recognized as „mutable origin“ because „mut“ is not a word but just an abbreviation. Maybe someone else is ready to write this proposal as I am not totally convinced that it is the way to go and that such a big change is worth it.
One question: Is read the default in unified? So that read values can be omitted in the unified declaration.
unified {read} → unified {}
unified {mut a, read b} → unified {mut a}
Answer:
there is no default capture convention planned, it is meant to be explicit. We can easily change this and we want to add even more convenience to users through ‘partial’ capture all syntax like {read justOneSpecificVariable, mut *} . Today it is either specify all explicitly or specify one convention for all captures
For now „capture conventions“ do require the read convention to be written out.
With the status quo (read/ImmutOrigin) we will have many read conventions written out in „capture contexts“ and many ImmutOrigin usage throughout the source code.
Any name change to one of those might require a lot of code to be changed in the future.