How to tell Mojo that something is intended to be constant?

In mojo 24.1.0 (55ec12d6) I get a new warning:
'let' is being removed, please use 'var' instead
I think it is good practice to make explicity my intention that something is constant. How to I do that (in the future) since let is deprecated?
50 Replies
Ehsan M. Kermani (Modular)
You can use alias as a compile time constant. The old let was there to emphasize immutable variable deceleration which is no longer needed.
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
Of course I know of the existence of alias, it is just that there is a very large semantic difference between var x = 8 and let x = 8, namely that it is my intention (the programmer) that a variable (not a compile constant) is constant, how are my colleagues to know my intentions if i cannot make that explicit? What were the reasons for removing this?
Ehsan M. Kermani (Modular)
GitHub
mojo/proposals/remove-let-decls.md at main · modularml/mojo
The Mojo Programming Language. Contribute to modularml/mojo development by creating an account on GitHub.
ModularBot
ModularBot•9mo ago
Congrats @Ehsan M. Kermani, you just advanced to level 1!
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
I did not comment on the proposal when it was made, but now that it has been executed, I'm interested in the 'official' reason let will be removed. Because now I cannot tell that something is intended to be constant, which is, for me, a very important concept.
benny
benny•9mo ago
well, atleast from how I see it, this becomes the same argument as when I proposed private struct fields. The effect you need can be made with changing naming scheme, though the compiler will not recognize it officially. The same way I can say _data is a private field, although not enforced, you can say var DATA is a constant, hence the naming scheme
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
@benny you mean that by naming a variable with eg capitals we can communicate that it is not intended to be changed, but the compiler will not enforce it (anymore). Similar, that all fields are public, but by naming it differently my colleagues can know that it should not be used.
benny
benny•9mo ago
correct you can imply behavior without it being enforced, which i believe is intended i personally am not sure I agree with this, but i see both sides of the arguments
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
Thus, our ability to write bug free code is sacrificed for ...., i hope it is something important...
gabrieldemarmiesse
gabrieldemarmiesse•9mo ago
A workaround is to create a function. In a function signature, it's possible to declare that an input value can't be mutated. And it works with references too.
benny
benny•9mo ago
👍🏻 along with this, I can think of few cases where I 1. don’t know the value or the function to get the value, and 2. need it to be immutable during runtime. I’m not saying there aren’t any, there are, i’m just saying alias can and should be used wherever possible, and i believe that is what that change is trying to emphasize plus there are some other issues with let/var being used with pointer/referencd since semantically you aren’t changing the pointer, rather the value it points to, if given the choice it can be ambiguous for new developers to choose let or var for that use case whereas alias is a little more imperative that the pointer itself is immutable while its underlying data may not be ^something that reference improves on even more, explicitly saying if it’s a mutable or immutable reference
Melody Daniel
Melody Daniel•9mo ago
It introduces complexity to the compiler and it doesn't work well What started this "bug-free code" movement?
ModularBot
ModularBot•9mo ago
Congrats @toiletsandpaper, you just advanced to level 1!
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
I want Mojo to do well because it gives us access to top-notch MLIR lowering capabilities (translation: it compiles to speedy code). For Mojo to succeed, the company Modular is creating a product called Max (written in Mojo) aimed at companies with highly profitable but complicated AI technology setups. And anyone who's dealt with such setups knows what a complete and total nightmare they can be. So, Modular, help us out (for us programmers' sake). How do we convince others (meaning management, who aren't keen on changing a highly profitable AI stack) that Mojo is a solid language? What does not quite helps is that it lacks basic Encapsulation (no private member fields) and has dropped Immutability. But that's okay if there are solid reasons behind it. Arguments like "it makes the compiler tricky" or "it's tough for new hires to grasp const int * const foo" just won't cut it. Even more challenging is how to persuade that Mojo can match Rust's capabilities without these fundamentals.
Melody Daniel
Melody Daniel•9mo ago
I think every company should use what they feel is the best tool for their job. If all these features are important then Rust is the obvious choice. For people having problems Mojo is intended to solve, these things are a non-factor. I'm talking AI Researchers, Python developers, and C/C++ devs writing extensions for Python.
sora
sora•9mo ago
How can they be non-factor when pretty much all the foundational AI libraries are written in C++, and C++ devs are trained to use const whenever possible? It made the code look horrible (because mutable is the wrong default), but it's the right thing to do nonetheless.
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
@sora Yes, and forgetting a const where it should have been is an error because it signals that something is allowed to be changed, and someday someone will change it, not knowing that it was intended to be immutable. For a compiler this is trivial to check, and absurd that it is dropped from a otherwise sound language.
sora
sora•9mo ago
I would go as far as saying this: even having let without the enforcement from the compiler is better than having only var for it communicates the intent of the programmer better.
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
Yes, agreed. I would have been happier that due to some weird regression Immutability would not have been enforceable anymore, while we kept a well established convention to convey our intent to future programmers. Lisp
Melody Daniel
Melody Daniel•9mo ago
Interesting. I thought Rust
sora
sora•9mo ago
It goes way back. Dijkstra, for instance, does much of his work (proving the correctness of programs) without touching a computer or having a compiler at all. A Discipline of Programming is a must read, if you are interested in "bug-free code". OCaml, which Rust was originally implemented in and got many of the good ideas from, was invented to implement Coq (a proof assistant). So you can kinda see Rust's lineage. The Software Foundations series is also an interesting read (uses Coq).
Nick!
Nick!•9mo ago
I was initially opposed to the removal of let, but I've since warmed up to it. As a language feature, let basically does nothing. It has no influence on the runtime behaviour of a program. It's essentially just a #comment on steroids. (Albeit, a useful comment.) It's weird to have a language feature that does nothing, especially when you have to teach everyone about this nothingness. So I can sympathize with its removal, even if I have historically been a fan of immutability. As a "fancy comment", let has two main utilities: - It allows a programmer to signal that they don't intend for a variable's value to change. - It allows the compiler to alert the programmer that the program is not consistent with this intention. There's no particular reason why this intention needs to manifest as a keyword. I suspect 90% of the benefit can be achieved just by using an IDE that colors variables differently depending on whether they are mutated at some point. If you accidentally mutate a variable, its color will change. Most of the time you'll notice this, and stop and think whether you've make a mistake. (Assuming you read your code before committing it!)
Melody Daniel
Melody Daniel•9mo ago
I think the problem of mutable variables is superficial, Mojo still enforces mutability in the important places. Namely, there can not be more than one owner, and there can't be two immutable borrows.
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
@Nick!
There's no particular reason why this intention needs to manifest as a keyword. I suspect 90% of the benefit can be achieved just by using an IDE that colors variables differently depending on whether they are mutated at some point.
Which brings me back to my question, how do I do that in Mojo? 1. How do I setup a warning that something is changed that should not be changed. 2. And how do I make such warning system explicit (read a new keyword) such that I can read that I made my intent clear. If i cannot do that i will consider "moving on".
Nick!
Nick!•9mo ago
I’m not here to convince you to use Mojo, so you’re always free to move on
sora
sora•9mo ago
Immutability is one basic form of proof carrying code. Imagine one day, we can write pre/post conditions in Mojo and have a SMT solver prove the correctness of our code. Given your very narrow view of programming, that also does nothing, it's absurd. And how is immutability difficult to teach? Wow, do you really meant to say that?
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
@Nick! you are just trolling, I want Mojo to be successful, but that is difficult if the basics are dropped without good reasons. If a language can be changed without good reasons, what are we doing here.
ModularBot
ModularBot•9mo ago
Congrats @Henk-Jan Lebbink, you just advanced to level 5!
Nick!
Nick!•9mo ago
@sora I just think the "moving on" comment sounded like it was imposing an obligation on me (or somebody else in this thread) to provide a satisfying answer to OP, which is a bit unfair, because I'm just a random person on the internet trying to provide some helpful information.
Immutability is one basic form of proof carrying code.
This is not something that needs to be part of the type system though, because it is a trivial property. A local variable is "immutable" iff you didn't mutate it. A keyword doesn't make the lack of mutation any more official
sora
sora•9mo ago
What about enforcing no uninitiated variable? Maybe you don't need or want help from the compiler, but I do. To put it to the extreme, it's "correct code" iff you don't ever make mistake.
A keyword doesn't make the lack of mutation any more official
I think you would agree that compiler does check something for us, so this is not factual.
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
We and a lot of others are here to invest their personal time (on a Saturday), knowing that someday the need to convince others (read management) that Mojo makes sense, and that is hampered by big decisions that I cannot explain. Thus a nice explanation would be in order.
Nick!
Nick!•9mo ago
>What about enforcing no uninitiated variable? The type system needs to enforce that variables are initialized before use because that is required for soundness. Reading an uninitialized variable at runtime would cause undefined behaviour. In contrast, reading a variable that has been mutated always yields defined behaviour. So let doesn't have the same level of importance/utility as requiring initialization.
sora
sora•9mo ago
Sure thing, isn't it "trivial" in the same way if you just don't access them like you don't mutate immutable variable?
Nick!
Nick!•9mo ago
No. The compiler needs to enforce initialization because that is required for memory safety. In contrast, immutability is not required to ensure memory safety.
ModularBot
ModularBot•9mo ago
Congrats @Nick!, you just advanced to level 6!
Nick!
Nick!•9mo ago
Or put another way: it is always wrong to use an uninitialized variable, but it is basically always correct to use a mutated variable
sora
sora•9mo ago
They are wrong in the sense that they are incorrect code. Memory safety is just a important form of safety. For a system without unmovable type, moving them would be wrong, e.g. I don't think we will see eye to eye on this matter. Nice knowing your position, and having this conversation. Let's move on, though.
Nick!
Nick!•9mo ago
sure
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
Now that Immutability checks are moved to some next round of analysis, e.g., "mojo analyze main" which will be allowed to spend hours of analyzing my complicated code littered with "lets". How do we tell such future analyzer that I intended to have something Immutable?
Nick!
Nick!•9mo ago
@Henk-Jan Lebbink Regarding your last comments, I am always trying to challenge my beliefs and take on new persectives as I learn new languages and develop as a programmer. Up until a few years ago, I was a major proponent of immutability and whatnot, but now I am more on the fence. Sometimes general principles (e.g. "immutability is better") don't hold up in all situations, so it's worth reflecting on each particular issue and trying to gauge just how important it is for a principle to be upheld in that setting. At the end of the day, what matters is whether programmers are actually going to be negatively affected in any shape or form by not having a keyword for local variable immutability. And while I agree with most people in this thread that it feels comforting to declare a variable as immutable, it's quite possible that this comforting feeling is just a result of my prior exposure to programming cultures wherein people tended to praise immutability quite heavily. So personally, I'm going to give Modular the benefit of the doubt (they have a lot of experience with programming languages), and see what a var-only world feels like. Will I ever encounter a bug that could have been prevented via a judicious use of let? I'm not actually sure. But I will find out with experience.
sora
sora•9mo ago
Don't get me wrong. I do find you pointing out "it does nothing" interesting. Maybe I've taken immutability for granted for the wrong reasons.
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
I have some issues with not declaring Immutability when people do not understand what that means (but that is a different problem). So, not using it when it's available is what I (and I suppose Sora) are contemplating. It is worth the experiment. However, Immutability has been a vital tool when sorting out dodgy quality C++ code over the past decade. I'm not sure any of those efforts would have worked without it. In an ideal world where code is clear and easy to understand, Immutability might not make much of a difference to ensuring correctness. But that's not the world I'm stuck in (unfortunately). When working in teams of programmers, I need a means to implement it, and I don't see any other way to enforce it. I treat Mojo a programming framework for real world problems, and teams of programmers are part of the real world, as is layers of management...
Sceptre
Sceptre•9mo ago
Okay so it aint crystal clear to me yet... but wasn't "let" one of the reasons why mojo was faster and better and more secure than python? And instead of removing it.. why not keep it optional?
Michael K
Michael K•9mo ago
The proposal to remove 'let' says no one is aware of any performance implications of the change. You may be thinking of defaulting to passing by immutable reference (borrow) which does have large performance benefits and remains a key feature of the language.
GitHub
mojo/proposals/remove-let-decls.md at main · modularml/mojo
The Mojo Programming Language. Contribute to modularml/mojo development by creating an account on GitHub.
Sceptre
Sceptre•9mo ago
Oh ok thanks
anandc
anandc•9mo ago
This may be impractical or undesirable, but could a future compiler track mutations made to SCREAMING_SNAKE_CASE variables and emit a warning? (As typically this naming scheme is used for constants in Python)
Henk-Jan Lebbink
Henk-Jan LebbinkOP•9mo ago
Ironically, we have that (approx.) at the moment. We can say
let START_TIME_NS = now()
# do lots of stuff, by other
let ELAPSED_TIME_NS = now() - START_TIME_NS
# however; in the future, we are not sure that START_TIME_NS has been
# mutated, and we may need to check that after every commit...
let START_TIME_NS = now()
# do lots of stuff, by other
let ELAPSED_TIME_NS = now() - START_TIME_NS
# however; in the future, we are not sure that START_TIME_NS has been
# mutated, and we may need to check that after every commit...
If we could switch on/off the semantics of keyword "let" such some don't need to understand what it does, while others can use it because they value their time.
Melody Daniel
Melody Daniel•9mo ago
The convention in every language for marking a variable as an unchangeable constant is to use an all-uppercase naming. It does not require a special language construct but Mojo has aliases But this constant doesn't seem to be what people are mooning over.
sora
sora•9mo ago
Exactly
NickL
NickL•8mo ago
If there are two types of variable modifiers that are fully complementary (mutable/immutable) then in theory you should only need one of them to express the intent (overriding the default) There's obviously reconcilable points here in my opinion, which I hope the Mojo team considers. - 'let' was not a completely useless keyword to the old Mojo compiler because it was used to AUTO-enforce run-time variable immutability at compile-time (alias is not a replacement). - 'let' is a meaningless word ('const' would have been a clearer choice), but still, 'var' is already handling the complementary case so I'm glad they are cutting meaningless keywords from the language. - Immutable variables are important and helpful to reason through code that uses multithreaded or asynchronous processes. - There probably shouldn't be logic in a compiler to determine if the case used for each variable is all caps - I'm not totally opposed to these kinds of ideas, but really that's just asking for a unnecessarily slow compiler. Simple solution: - AUTO-enforce immutable variables by default unless explicitly tacked with 'var' in mojo functions Seems to me this solves reasonable concerns and provides a good default for making intentions clear in a simple way.
Want results from more Discord servers?
Add your server