Open chocolateboy opened 7 years ago
+1
I don't know about "being default" part (I'll like it but it's a breaking change and can cause confusion. How to autoinitialize mutable fields then?) but there is a lot of cases where some field is assigned only at creation.
keep simple , thanks .
How did I miss this issue!
It would be possible, I think, for the compiler to detect if an instance variable is immutable or not without changing anything. I'm not sure if it would be a good idea though. Having which ivars are immutable (I'd prefer to call this readonly, as for classes / pointers the contents of the class can change) documented would be great.
@konovod I think 'recommended' is a nice way
Yeah, set-once ivars is a common pattern, and formally saying so gives both clarification to human reader and low-level optimization benefits to backend. +1.
Are we talking about immutable variables, or variables which have immutable types once set? The page at docs/if_var is talking about how the type might change within an if
statement.
I ask because it seems to me that both kinds of "immutable" could be valuable.
Hmm. "immutable type" is not a good description of what I'm thinking of. I have instance variables which I initialize as @somevar = nil
, but after the initialization I would never re-set the value to nil
. So once the variable is given a non-nil value, it will never become nil
again. In fact, it'd be a bug in my own logic if anything did set it to nil
.
Not sure if the compiler should have explicit support for that, but the idea matches the issue discussed in docs/if-var.
@drosehn - this is immutability regarding value, or well, not even that; just variable/symbol (the value can still be mutated [depending on our definition of value in this context], but you can't reassign the variable), that's what I was referring to at least.
Regarding the type inference, to stick to a first inferred type, and consider subsequent variations errors, that's another thing. Normally would solve that by actually typing the variable (which wasn't possible for locals in earlier releases). Others and I have suggested a way to mark for locking the inference to first inferred type, disallowing type unions, thereby giving the result you seek. Haven't looked lately on the discussion of those issues.
With regard to a late value initialization that is still immutable in practice, that's also something that has been pondered in a couple of issues. For me it was the (seemingly straight forward) case of being able to have methods doing inits of some ivars, invoked from one or more instance initializers (the "constructors"), and there are other situations too that are even "late for real" (still undefined post object instantiation), like many come across in android dev (not related to crystal, but for example). Unfortunately compilation cost is increased a bunch by doing reachability analysis to ensure that a variable, despite being uninitialized, is never accessed before it is initialized, even though at an arbitrarily later stage. Concurrency complicates it further. _I here differentiate between "being initially nil" (which is a value, of the Nil type) and "uninitialized" meaning it is still T
instead of T|Nil
, but is set and subsequently used after it's containing instance life cycle has already begun_. It would be great out of a user perspective! Unfortunately I think the only way to circumvent it practically is by unsafe practices like "parking" the ivar on a dummy value before real init to avoid the Nil union - in which case the insurance of knowing it is never used before it's set (for real, not work-around-dummy-set) is thrown out of the window, along with insurance that it is not re-set.
Disclaimer: Sorry if I've completely misunderstood something and clutter up the comment space here!
I would have it so that the value can only be written to inside the constructor (before self
escapes), and after the constructor is finished the value is fixed. This also means the type is fixed for all methods. The class cannot be reentrant before self
escapes, so types can be checked without if foo = @foo
, and after that the variable cannot be set so the same holds. So theoretically this could work.
However I think changing the semantics so subtly there could be more confusing than helpful, and using if foo = @foo
is quite succinct. I don't mind the idea of immutable instance variables but changing semantics could be a bit weird.
If you want to narrow the type of an instance variable in Crystal you have to assign it to a local variable first, as documented here. This is a kludge which continues to trip users up:
If instance variables could be declared immutable, we wouldn't have to launder them through local variables because they would be guaranteed not to change.
Since we can't introduce variable declarators (presumably), how about a new operator for immutable initialization:
In addition, auto-initialization could be immutable by default e.g.:
Before:
After:
See Also