Mojo proposal: renaming `read` to `immut`

Hello Mojicians,

I propose to rename the read argument convention to immut.

This is inspired by recent activities to rename and clean up some naming before “Phase 1” of the Mojo roadmap is finished like Mojo change: renaming `alias` to `comptime` and renaming ImmutableOrigin/ MutableOrigin to ImmutOrigin/ MutOrigin.

Before:

fn foo(x, mut y):
    """ `x` is read only inside `foo` (default argument convention)"""
    ...

fn bar(read x, mut y):
    """ `x` is read only inside `bar`  (explicit argument convention)"""
    ...

After:

fn foo(x, mut y):
    """ `x` is immutable inside `foo` (default argument convention)"""
    ...

fn bar(immut x, mut y):
    """ `x` is immutable inside `bar` (explicit argument convention)"""
    ...

Reasons for this change:

  • It better aligns with the mojo documentation on immutable arguments, references and origins. A search for “read” or “read only” does not lead to relevant documentation while a search for “immut” or “immutable” directly leads to Ownership | Modular.
  • It aligns nicely with the mut argument convention, ImmutOrigin and MutOrigin. Therefore it reduces the conceptual burden of different names for the same concept.
  • It would be an “almost” non-breaking change because read is the default argument convention and quite never written out in the source code.

Alternatives:

  • Keep it like it is:
    It is not a big issue as the read argument convention is quite never written out. Maybe the reasons for the proposed change are not convincing or not worth it.
  • Rename other things to better align with read:
    For example renaming ImmutOrigin to ReadOrigin etc. This would be a big breaking change as immut and immutable is already used in many places throughout the Mojo documentation and stdlib source code.

What do you think?

2 Likes

Makes sense for me. It is symmetrical and also easier to guess for newbies.

1 Like

Hi

I know this might be bike-shedding, but my 2 cents are:

’read’ is overall easy to parse as meaning ‘read-only‘.
I agree that there should be a more intuitive association between ‘read‘ and ‘mut‘, but ‘immut‘ feels strange.

‘immut‘ feels like the inverse of ‘mut‘, as apposed to specifically indicating read-only arguments.
For example, ‘const‘ is independent (linguistically) from ‘mut‘, so it is can more easily be internalized by programmers as its own concept, as apposed to ‘immut‘ being the inverse of ‘mut‘ due to the ‘im‘-prefix.

If I needed to explain what ‘immut‘ means, I have to explain it relative to the meaning of ‘mut‘.

Whereas, ‘read‘ (or a keyword not related to mutate) can be explained as : “You can only read this value“, and ‘mut‘ as : “You can mutate this value.“ Both conventions can be explained independently.

I know ‘immut‘ will be written less because it is the implicit default, but the keyword should still feel natural.

The above is just an opinion - if someone could explain why ‘immut‘ is still the better way to go, I’d be keen to hear why

Hi,

To better understand your opinion, which is your preferred option?

  • read/mut, ImmutOrigin/MutOrigin (status quo)
  • read/mut, ReadOrigin/MutOrigin

To clarify :slightly_smiling_face:

Naming things is hard.

I honestly prefer read/mut – I like the simplicity and clarity of ‘read‘.
But I can also see why immute/mut is compelling.

I preferred ImmutableOrigin/MutableOrigin because it is explicit what their intended purposes are, although I can also understand why they were shortened.
ReadOrigin/MutOrigin seem like a mismatch.

I’ve spent the last while trying to think of something better than immut/mut and ImmutOrigin/MutOrigin, but I can’t.
Fair enough, I concede that immut/mut is a reasonable approach, given the aim is to have a consistent naming convention between immut/mut => ImmutOrigin/MutOrigin.

1 Like

I honestly prefer read/mut – I like the simplicity and clarity of ‘read‘.
But I can also see why immute/mut is compelling.

I preferred ImmutableOrigin/MutableOrigin because it is explicit what their intended purposes are, although I can also understand why they were shortened.
ReadOrigin/MutOrigin seem like a mismatch.

I mostly agree with the sentiment from @monte

But in the original (very long) keyword naming discussion thread where read and mut were decided, I actually wanted us to go for read and write. I don’t think it’s too hard to explain that write arguments can also be read since we aren’t talking about file or OS-level permissions. The corresponding origins would be ReadableOrigin and WritableOrigin, which I think are much more newbie-friendly than mutable and immutable and IMO they help make origins easier to understand.

1 Like

In the original keyword-renaming thread, one argument against “immut” and related names was that they’re ugly. Even though they’re the default argument convention and won’t usually be written for arguments, they would still have to be used explicitly in capture syntax. I don’t see why “read” can’t be the default convention for captures, so it might be a worthwhile trade-off to keep the arguably uglier “immut” for consistency, since few people are likely to use it explicitly.

Status quo:

  • read/mut, ImmutOrigin/MutOrigin

Proposal:

  • immut/mut, ImmutOrigin/MutOrigin

Alternative proposal (martinvuyk):

  • read/write, ReadableOrigin/WritableOrigin

Bold: deviation from status quo

1 Like

Thanks for starting this thread! I agree we should have only one. I’m curious what y’all think about changing read to immut, but also the alternate of changing Immut to Read - or possibly some other candidate. One thing to note is that the word should also work in capture lists.

I’m also curious what people think about “ImmOrigin” vs “ImmutOrigin”.

Can we have ‘read’ be the default convention for capture lists?

“read” is more accurate than “immut”. The word needs to be positive, i.e. it needs to describe what you can do with an argument/origin. This is due to the fact that every “mutable origin” is also a “readable origin”. If you instead change the terminology to “immutable”, we would be saying that every “mutable origin” is also an “immutable origin”, which doesn’t make sense.

“read” should be understood like a trait. It specifies a requirement that the caller must meet. Traits are always positive concepts. The quality of being immutable can’t be expressed as a trait, because it’s negative: it means a lack of mutability.

4 Likes

G…great mind think alike?

2 Likes

I’m not sure if iI understand your argument correctly. But to me, this is rather an argument in favor of immut. Why: Because you can‘t provide an "immutable reference“ to a "mutable argument“. Therefore a "mutable origin“ is not an "immutable origin“ too. Whereas the read argument convention is more ambiguous in this context and must be interpreted as “read only” to capture its semantic.

you can‘t provide an "immutable reference“ to a "mutable argument“.

You don’t need the term “immutable” to explain how function calls are constrained. Mojo programmers know that you can’t provide T: AnyType to a function requiring T: Copyable, because T is not known/declared to be copyable at the call site. Similarly, you can’t provide a ReadableOrigin to a function requiring a MutableOrigin, because the origin is not known to be mutable at the call site.

True. I‘m all with you because ReadableOrigin implies “read only” semantic when using it.

So what would be your proposal?

  • read/mut, ReadableOrigin/MutOrigin ?
2 Likes

Yes I think we should keep read and mut. For the origin types I’m not too fussed right now, because origins and Mojo’s safety model are very WIP and subject to change. But something like ReadableOrigin would make sense.

2 Likes

We have now three proposals that would unify the naming of the argument convention and the corresponding origin:

  • immut/mut, ImmutOrigin/MutOrigin
  • read/write, ReadableOrigin/WritableOrigin
  • read/mut, ReadableOrigin/MutOrigin

bold: deviation from status quo

Either read or immut is fine with me.
I personally prefer the parity of read/write or immut/mut but it’s not that bothersome to me.

In terms of naming schemes - if we have Mut for MutOrigin (and not Mutable) we should have ReadOrigin and not Readable.

1 Like

Concerning imm, ImmOrigin vs. immut, ImmutOrigin:

I think imm is too ambiguous. Searching for words that start wit “imm” inside the modular repo yields “immediate”, “immovable”, "immutable“ and “IMMA Kernel”. But I like its three-character shortness.

@clattner : shall I add this to the list of proposals?

  • imm/mut, ImmOrigin/MutOrigin
2 Likes

We have now three proposals with different levels of abbreviations that would unify the naming of the argument convention and the corresponding origin:

immut/mut

  • immut/mut, ImmutOrigin/MutOrigin
  • imm/mut, ImmOrigin/MutOrigin

read/write

  • read/write, ReadableOrigin/WritableOrigin
  • read/write, ReadOrigin/WriteOrigin

read/mut

  • read/mut, ReadableOrigin/MutableOrigin
  • read/mut, ReadOrigin/MutOrigin

bold: deviation from status quo