opensas
opensas

Reputation: 63605

scala - is it possible to force immutability on an object?

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

Answers (3)

Ben
Ben

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:

  1. 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?
  2. 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.
  3. Let's assume we could get around that (maybe we could set some secret flags that mean exceptions get raised if the 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.
  4. Worse than that, we only know that we'll have passed in an instance of 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

0__
0__

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

Matthew Farwell
Matthew Farwell

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

Related Questions