Regarding variables, I kinda like the following concept. I would define 3 classes of "variables" (not sure this would be the right term to use, but that's another topic):
- Constants (have a type and initial value, can never change)
- Regular variables (have a type, an initial value, and can change)
- Definitions (identifiers bound to an expression that can involve any object in scope)
I would be against the possibility of changing a given variable's class at any point.
For "definitions", here's a very simple example to illustrate them (in some kind of pseudo C-like code):
double Foo(double x1, double y1, double x2, double y2, double r)
{
double x2p = x1 + x2, y2p = y1 + y2;
def double xdiff = x2p - x1, ydiff = y2p - y1, distance = sqrt(xdiff*xdiff + ydiff*ydiff);
while (distance > r)
{
x2p = 0.5*(x1 + x2p);
y2p = 0.5*(y1 + y2p);
}
return distance;
}
Your definitions are more commonly known as lambda's.
The issue here, seems to be conflating the variable with it's value. Though intrinsically linked, they are separate concepts, and have separate lifetimes, mutability, and so forth. C has immutability too, it calls it "const", in which the variables are the immutable part — the value is still free to vary. This is mostly an abomination. Immutability in most cases I've seen, is an attempt to fix that; a variable may or may not be able to vary, but the nature of the value it presently holds, can not. If you take a "view" into that value, your view will remain valid, even if the variable holding it changes.
Further, fundamental value types like a number, are immutable by default, and always have been; 5 will always be 5. I don't believe we have any concept of it ever changing. (Kinda — if you forget that numbers larger than 1 are themselves represented by a collection of other numbers, and sometimes, by collections of collections of basic numbers, and then there are floats…) It's just the more complex types where mutability is optional — arrays, and other collections of fundamental value types.
The problem with C's idea of constant-ness, is that even if you can't change the value, the value can usually still change itself, and worse, other things can "forget" that it was meant to be constant. This means that if you try to reuse part of the value for another purpose, that view into the larger value can now mysteriously (and potentially incorrectly) change without you knowing it. That's bad. And doesn't even consider why you made that view in the first place, and thus whether it's new state, while being valid in and of itself, is valid for the purpose for which you made it.
Sharing is an awesome thing. I don't know how this V-lang uses Immutability, but D-lang, which is based around manipulating "views into data" (they call it "ranges"), has an XML parser that manages to process an entire loaded XML file (loaded as in, the text bytes are by some means readable through a stable range of memory addresses), while only allocating a hundred or so bytes per the "depth" of the deepest node in the entire file. So if you have a 100MB XML file with a maximum depth of only 3 levels, the parser will feed you every node in that file one by one, while only itself allocating 300-ish additional bytes. It does that by handing you strings that are a "view" into the source data, rather than making copies of it — which also makes it significantly faster. This is only possible, because we know the source data will not be changing or disappearing — it's Immutable.
So, Immutability is great for speed and safety! The downside, is that it tends to eat memory because if you have a three byte view into a 100MB XML file still hanging around, that entire 100MB XML file also has to hang around to provide them — unless you have some whacky memory manager which is able to release part of an allocation (certainly possible, but probably not efficient, and not yet natively supported)… D-lang as a result, is amazing awesomeness rivalled by none (IMHO) — if you have buckets of memory to spare. That said, D-lang also doesn't force you to use the GC, and you can easily enough use mutable equivalent types (most of them are provided, and can be used in either mode — in fact, one of it's problems is that it typically offers three versions of everything, so you can chose your memory model), or explicitly copy values which know are going to out-live the source data, thus allowing it to be collected. Immutability enables a lot of good things, but it rather encourages tying up memory, and requiring some stuff that might have lived on the stack, to instead occupy the heap. (D-lang is kinda dual-natured in that regard, favouring value-passed references to shared immutable heap memory — so, more stack as well as more heap, unfortunately. Plus it barely knows what 8- or 16- bit are. It's like, a millennial of the programming language world, or something.)
As an aside, D-lang has UFCS (which it had a good decade before Rust even existed) which makes any function that takes no arguments look like a property. So your "definitions", are indeed simple lambda's in D. In other languages, you would simply need to us the commonly accepted "definition indicator syntax", which is, a pair of empty parenthesis after the value. ie. xdiff(), instead of merely xdiff. (Not at all a function call… it's clearly a "definition", honest!)
This is of course, all to say, Immutable is arguably what C's const should have been, rather than the abomination it is. Still… It's not actually for everything.