Reputation: 63605
I mean if there's some declarative way to prevent an object from changing any of it's members.
In the following example
class student(var name:String)
val s = new student("John")
"s" has been declared as a val, so it will always point to the same student.
But is there some way to prevent s.name from being changed by just declaring it like immutable???
Or the only solution is to declare everything as val, and manually force immutability?
Upvotes: 3
Views: 636
Reputation: 71590
There is no way that Scala could do this generally.
Consider the following hypothetical example:
class Student(var name : String, var course : Course)
def stuff(course : Course) {
magically_pure_val s = new Student("Fredzilla", course)
someFunctionOfStudent(s)
genericHigherOrderFunction(s, someFunctionOfStudent)
course.someMethod()
}
The pitfalls for any attempt to actually implement that magically_pure_val
keyword are:
someFunctionOfStudent
takes an arbitrary student, and isn't implemented in this compilation unit. It was written/compiled knowing that Student
consists of two mutable fields. How do we know it doesn't actually mutate them?genericHigherOrderFunction
is even worse; it's going to take our Student
and a function of Student
, but it's written polymorphically. Whether or not it actually mutates s
depends on what its other arguments are; determining that at compile time with full generality requires solving the Halting Problem.s
object is actually mutated, though personally I wouldn't find that good enough). What about that course
field? Does course.someMethod()
mutate it? That method call isn't invoked from s
directly.Course
or some subclass of Course
. So even if we are able to analyze a particular implementation of Course
and Course.someMethod
and conclude that this is safe, someone can always add a new subclass of Course
whose implementation of someMethod
mutates the Course
.There's simply no way for the compiler to check that a given object cannot be mutated. The pusca plugin mentioned by 0__ appears to detect purity the same way Mercury does; by ensuring that every method is known from its signature to be either pure or impure, and by raising a compiler error if the implementation of anything declared to be pure does anything that could cause impurity (unless the programmer promises that the method is pure anyway).[1]
This is quite a different from simply declaring a value to be completely (and deeply) immutable and expecting the compiler to notice if any of the code that could touch it could mutate it. It's also not a perfect inference, just a conservative one
[1]The pusca README claims that it can infer impurity of methods whose last expression is a call to an impure method. I'm not quite sure how it can do this, as checking if that last expression is an impure call requires checking if it's calling a not-declared-impure method that should be declared impure by this rule, and the implementation might not be available to the compiler at that point (and indeed could be changed later even if it is). But all I've done is look at the README and think about it for a few minutes, so I might be missing something.
Upvotes: 1
Reputation: 67330
Scala doesn't enforce that, so there is no way to know. There is, however, an interesting compiler-plugin project named pusca (I guess it stands for Pure-Scala). Pure is defined there as not mutating a non-local variable and being side-effect free (e.g. not printing to the console)—so that calling a pure method repeatedly will always yield the same result (what is called referentially transparent).
I haven't tried out that plug-in myself, so I can't say if it's any stable or usable already.
Upvotes: 2
Reputation: 61715
No, it's not possible to declare something immutable. You have to enforce immutability yourself, by not allowing anyone to change it, that is remove all ways of modifying the class.
Someone can still modify it using reflection, but that's another story.
Upvotes: 7