On removing let and let mut
verdagon.dev
verdagon.dev
final variables in Java can and do change value. They start default initialized, then are assigned at most once. This is a collosal pain in the neck for people writing multithreaded code.
You can also observe the partially initialized final change value in single threaded code by invoking partially initialized stuff around during initialization.
let (value, weight) = let (value, weight)
if values.empty() { if values.empty() {
(0, 1.0) value = 0
} else { weight = 1.0
(values[0], 1/values.len()) } else {
} value = values[0]
weight = 1/values.len()
}
I think the right (the "old way") is more readable. However it requires the variables be mutable or declaration be separable from initialization. let { value, weight } =
if values.empty() {
{ value: 0, weight: 1.0 }
} else {
{ value: values[0], weight: 1 / values.len() }
}
Using JS style object expansion, instead of tuple expansion.I like your second example there. The compiler could probably very easily ensure that a variable was initialized before first usage.
Thank you for the idea and insight!
I actually love this statistical approach to language design, draws parallels to something I read that CPU designers make optimisations to the innerworkings their instructionset based on heuristics such as average number of functions arguments etc.
Keywords are great because they provide redundancy in the grammar that allows for good syntax error messages and recovery.
I recently lamented the absence of a let token in Ruby while working on making Sorbet’s parser more tolerant of syntax errors. Consider this Ruby program:
x.
y = 0
It doesn’t have a syntax error. Ruby treats this as if the user had written x.y=(0)
But because of how the line is broken, probably the user meant to have two separate statements, and is in the middle of inserting a new call like x.foo()
y = 1
Or consider another: class
y = 1
The syntax error Ruby reports here is “class names must start with a capital letter.” It then fails to produce any parse result because there is no end keyword to match the class, throwing away the (properly parsing) `x = 1` subexpression in the parse tree.In these cases it’s frequently possible to hack around the issues with weird contortions. But in basically every such case, if Ruby had used an explicit let keyword it would have been much easier to for the parser to both report syntax errors in places that might otherwise be ambiguous as well as produce some parse tree for the ones that don’t parse.
Vale happens to require semicolons at the end of every line, which helps with this (and a few other corner cases around custom binary operators).
So yeah, long story short I'm also a proponent of semicolons. They help avoid ambiguity for both humans and machines, and make splitting lines less awkward.
That being said I’ve never had a problem with python’s variable definition and assignment syntax being the same where TFA claims it was a failure. Honestly, I even support the walrus operator for the specific reason it was introduced — heresy, I know…
I think that it would be interesting to do like C# does: use this 'mutable letter' to indicate 'in-out' function parameters.
x = 4
if (cond) {
x = 8
log("x is now: ", x)
}
process(x)
Looks right, but it's wrong.Isn't it an issue for Vale?
What is Vale's thesis?
Though, it's a lot more than that, Vale's also doing some pretty crazy things with concurrency [0], determinism, higher raii [1], and region isolation, all of which will help with preventing and detecting bugs.
[0] https://verdagon.dev/blog/seamless-fearless-structured-concu...