immutable by default

33 views
Skip to first unread message

Michael Hendricks

unread,
Oct 20, 2011, 10:26:45 PM10/20/11
to General Dart Discussion
When I write "int x = 7", x is mutable.  Could someone explain why mutable was chosen as the default rather than immutable?  I haven't found any record of the discussion behind this particular decision.

I'd personally like to see something like this:

    var x = 7; // mutable
    final x = 7; // immutable
    int x = 7; // immutable
    var int x = 7; // explicitly mutable
    // apply the same rules to method parameters

It seems Java developers are taught to use final everywhere, but tire of typing it and reading it. JavaScript (and other dynamic language) programmers shouldn't care as long as "var x" creates immutable variables. Functional programmers should prefer immutability.  So that you know my biases, my daily programming is 80% Perl, 10% Java, 10% Haskell.

Anyway, I'm interested to know what discussions were had on this point before Dart saw the light of day.  Is the decision still open to change?

Thanks.

-- 
Michael

Bob Nystrom

unread,
Oct 21, 2011, 1:10:18 PM10/21/11
to Michael Hendricks, General Dart Discussion
On Thu, Oct 20, 2011 at 7:26 PM, Michael Hendricks <mic...@ndrix.org> wrote:
When I write "int x = 7", x is mutable.

We should be careful around terminology here because "immutable" can mean a couple of different things depending on who you ask. It can mean:

1. Single-assignment: a variable or field can be initialized and that's it.
2. Deep transitive immutability: the object and everything it references are unchanging.

You're right that variables, by default, are not single assignment in Dart. If you want a single-assignment variable, you use final.

Could someone explain why mutable was chosen as the default rather than immutable?  I haven't found any record of the discussion behind this particular decision.

I don't think there is a record. I'm not sure exactly what the designers were thinking, but my guess is that Dart is following the path of most imperative languages here: C, C++, Java, C#, JavaScript, Smalltalk, Python, Ruby, etc. all allow variables to be assigned to after creation. Given Dart's very strong syntactic similarity to C/C++/Java/JS/C# in particular, it would be astonishing to lots and lots of programmers if this was an error:

int x = 3;
x = 4;
 

I'd personally like to see something like this:

    var x = 7; // mutable
    final x = 7; // immutable
    int x = 7; // immutable
    var int x = 7; // explicitly mutable

This seems like it punishes with verbosity the common case of a typed but re-assignable variable. Those are used heavily through our code and I'd hate to make them longer.
 
    // apply the same rules to method parameters

It seems Java developers are taught to use final everywhere, but tire of typing it and reading it.

We use final fairly frequently for local variables but we aren't gung-ho about it. I find it makes it a little easier to read code when I know what variables will be re-assigned to, but it's not a huge deal. If your method is so long that you really need that to keep track of what's going on, your method is just too long.

Keep in mind that Java has another motivation for final: anonymous inner classes can only close over final variables and not non-final ones. Dart has real closures that don't have that limitation.
 
JavaScript (and other dynamic language) programmers shouldn't care as long as "var x" creates immutable variables. Functional programmers should prefer immutability.  So that you know my biases, my daily programming is 80% Perl, 10% Java, 10% Haskell.

Anyway, I'm interested to know what discussions were had on this point before Dart saw the light of day.  Is the decision still open to change?

There's been some discussion about whether parameters should be final by default, but I think we're pretty happy that locals default to non-final. I find the current syntax for final variables pretty palatable (though I can't deny that I personally like "val" more than "final") so I don't think we have a lot of desire to mess with it. I'm sympathetic to functional style, but what we have is working fine now.

If anything, I'd be more interested in the second definition of immutable: deep unchangeable objects. That seems a more valuable to me than making sure you can't set a local.

Thanks for bringing this up, though! It's good to make sure we're thinking about (and hopefully explaining) decisions like this.

- bob

Dirk Detering

unread,
Oct 21, 2011, 2:04:44 PM10/21/11
to Bob Nystrom, Michael Hendricks, General Dart Discussion


Am 21.10.2011 19:10 schrieb "Bob Nystrom" :
> If anything, I'd be more interested in the second definition of immutable: deep unchangeable objects. That seems a more valuable to me than making sure you can't set a local.
>

Bob, you are confusing me, as I do not consider these two things disjunct.
How can you discuss the deep unchangeability of objects without debating the default immutability of a variable?
OK, it is not so much the method locals but the member variables, but both should be treated consistently.
So the deep immutability of a containment hierarchy is AFAIC so far achieved by the finality of variables.
Every mutability of variables in the structure will make the whole structure mutable. Am I wrong?

KR
Det

Ben Laurie

unread,
Oct 21, 2011, 2:11:25 PM10/21/11
to Dirk Detering, Bob Nystrom, Michael Hendricks, General Dart Discussion
Caja and ES5 (I think) have the ability to freeze an object, which makes it deeply immutable. Perhaps this is a good approach? 

KR
Det


Mark S. Miller

unread,
Oct 21, 2011, 2:25:47 PM10/21/11
to Ben Laurie, Dirk Detering, Bob Nystrom, Michael Hendricks, General Dart Discussion
On Fri, Oct 21, 2011 at 11:11 AM, Ben Laurie <be...@google.com> wrote:
Caja and ES5 (I think) have the ability to freeze an object, which makes it deeply immutable. Perhaps this is a good approach? 

In both Caja and ES5, freeze is shallow. CajaVM.def is a freeze that is transitive over property and prototype traversal, i.e., the "surface" reachable from a given object. But neither freezes encapsulated state, as that would violate the object's encapsulation! 

E and Joe-E have auditors[1,2], the most useful of which is the auditor for transitive immutability ("DeepFrozen" and "Immutable", respectively). By using such auditors, E and Joe-E objects can elect to be *visibly* transitively immutable.

 
--
    Cheers,
    --MarkM

Bob Nystrom

unread,
Oct 21, 2011, 2:35:42 PM10/21/11
to Dirk Detering, Michael Hendricks, General Dart Discussion
Right, sorry I wasn't clear here. You're absolutely right that if all of an object's fields are final, and all of the values in those fields are also object's whose fields are final, recursively, then that's transitive immutability.

I just wanted to be clear that only having the field or variable be final doesn't give you that. You have to ensure that the value contained by the field or variable is also immutable itself. In other words:

final a = []; // a is an immutable value?
a.add(1); // nope, just a single-assignment variable

Sorry for the confusion.

- bob

Michael Hendricks

unread,
Oct 21, 2011, 4:21:05 PM10/21/11
to Bob Nystrom, General Dart Discussion
On Fri, Oct 21, 2011 at 11:10 AM, Bob Nystrom <rnys...@google.com> wrote:
We should be careful around terminology here because "immutable" can mean a couple of different things depending on who you ask. It can mean:

1. Single-assignment: a variable or field can be initialized and that's it.
2. Deep transitive immutability: the object and everything it references are unchanging.

You're right. I should have been more precise.  I meant single-assignment.
 
Given Dart's very strong syntactic similarity to C/C++/Java/JS/C# in particular, it would be astonishing to lots and lots of programmers if this was an error:

int x = 3;
x = 4;

Those same programmers will be surprised that this code compiles and runs without an error:

  main() {
    int x = 7;
    String y = "7";
    print( x*y );
  }

We're OK with that because we can teach new Dart programmers to pay attention to the compiler warnings and to develop with type checking enabled.  It's a new language, so they'll have to learn a few new tricks.  The benefits of optional typing are worth it.

In some ways, the above x*y failure is more troublesome because it fails quietly.  The single-assignment failure happens loudly and at compile time.  If their code really needs both type information and multiple assignment, we can teach new Dart programmers to type "var int".  The benefits are worth it :-)
 
I'd personally like to see something like this:

    var x = 7; // mutable
    final x = 7; // immutable
    int x = 7; // immutable
    var int x = 7; // explicitly mutable

This seems like it punishes with verbosity the common case of a typed but re-assignable variable. Those are used heavily through our code and I'd hate to make them longer.

I think we have an honest disagreement about which is the common case.  A quick analysis of my Java code shows that only 10% of variables are assigned more than once.  If anyone has data on how often multiple-assignment is used in the wild, that would settle it for me.  If anyone can point me toward tools for writing a static analysis tool like that, I'm glad to take a swing at it.

 
If your method is so long that you really need that to keep track of what's going on, your method is just too long.

My methods aren't that long, but "theirs" are :-)  A lot of real world code is written by untalented programmers.  I've been called in to rewrite 200+ line methods often enough that it doesn't surprise me anymore.  Those programmers, and the ones cleaning up after them, would benefit from single-assignment by default.

I've tried to leave my functional programming hat at home this time because  this is actually an issue I encounter in large scale, imperative programming.  Hopefully we can get some data to settle exactly how surprising single-assignment would be to Java/JavaScript/C# programmers.

-- 
Michael 

Bob Nystrom

unread,
Oct 21, 2011, 7:22:14 PM10/21/11
to Michael Hendricks, General Dart Discussion
On Fri, Oct 21, 2011 at 1:21 PM, Michael Hendricks <mic...@ndrix.org> wrote:

We're OK with that because we can teach new Dart programmers to pay attention to the compiler warnings and to develop with type checking enabled.

We aren't delighted with forcing an astonishment tax on our users, but we think it may be worth it to get the benefits of optional typing. But in all cases, we really really don't like to tax them. Dart tries hard not to do that (even at the expense of not being as fun or expressive as we might want).
 
 It's a new language, so they'll have to learn a few new tricks.  The benefits of optional typing are worth it.

Right. So we hope they don't also have to learn a lot of other tricks too.
 

In some ways, the above x*y failure is more troublesome because it fails quietly.

I think it will throw a NoSuchMethod exception, so it's not very quiet.
 
 The single-assignment failure happens loudly and at compile time.  If their code really needs both type information and multiple assignment, we can teach new Dart programmers to type "var int".  The benefits are worth it :-)

Well... you have to admit that's debatable. I like single-assignment but if that was the default in Dart, even though all of the languages that Dart is based on don't work that way, there would be a pretty high burden of proof that's it worth the change. I could be wrong, but I don't think single-assignment has shown it's worth to that degree yet.
 
 
I'd personally like to see something like this:

    var x = 7; // mutable
    final x = 7; // immutable
    int x = 7; // immutable
    var int x = 7; // explicitly mutable

This seems like it punishes with verbosity the common case of a typed but re-assignable variable. Those are used heavily through our code and I'd hate to make them longer.

I think we have an honest disagreement about which is the common case.
 A quick analysis of my Java code shows that only 10% of variables are assigned more than once.

Understood, but of the remaining 90%, how many would be materially helped by enforcing the single-assignment? I know it adds a bit of clarity, but would it be worth it everywhere?

Keep in mind that Dart's general philosophy is to lean towards what the user wants to do and assume they know what they mean. If I'm already doing an assignment, why should I have to go out of my way to tell Dart "hey, this variable I'm trying to assign to, please let me assign to it"?

 
I've tried to leave my functional programming hat at home this time because  this is actually an issue I encounter in large scale, imperative programming.  Hopefully we can get some data to settle exactly how surprising single-assignment would be to Java/JavaScript/C# programmers.

It's hard to gather data on this. We could find out how often variables are multiply-assigned, but that doesn't tell us much about how much pain users would suffer going forward if single-assignment was the default.

I am sympathetic to your viewpoint, but I think it would be too big of a departure from Dart's syntactic legacy (C/C++/Java/JS/C#) to work differently here.

- bob

Rémi Forax

unread,
Oct 22, 2011, 6:39:05 AM10/22/11
to mi...@dartlang.org
On 10/22/2011 01:22 AM, Bob Nystrom wrote:
 
main() {
    int x = 7;
    String y = "7";
    print( x*y );
  }

In some ways, the above x*y failure is more troublesome because it fails quietly.

I think it will throw a NoSuchMethod exception, so it's not very quiet.

In dartboard,
you have a warning but it prints 49 at runtime.

Rémi


Peter Ahé

unread,
Oct 22, 2011, 6:41:31 AM10/22/11
to Rémi Forax, mi...@dartlang.org

This is a bug in dartc. It should cause a runtime error. This is part
of the challenge around compiling to JavaScript.

Cheers,
Peter

Daniel Rice (דניאל רייס)

unread,
Oct 22, 2011, 2:45:26 PM10/22/11
to Rémi Forax, mi...@dartlang.org
I filed this as issue 208: http://code.google.com/p/dart/issues/detail?id=208

Dan
--
Daniel Rice | Software Engineer | ri...@google.com | 415-613-2441

Michael Hendricks

unread,
Oct 24, 2011, 10:40:33 AM10/24/11
to Bob Nystrom, General Dart Discussion
On Fri, Oct 21, 2011 at 5:22 PM, Bob Nystrom <rnys...@google.com> wrote:
On Fri, Oct 21, 2011 at 1:21 PM, Michael Hendricks <mic...@ndrix.org> wrote:
 The single-assignment failure happens loudly and at compile time.  If their code really needs both type information and multiple assignment, we can teach new Dart programmers to type "var int".  The benefits are worth it :-)

Well... you have to admit that's debatable. I like single-assignment but if that was the default in Dart, even though all of the languages that Dart is based on don't work that way, there would be a pretty high burden of proof that's it worth the change. I could be wrong, but I don't think single-assignment has shown it's worth to that degree yet.

That's fair.  Garbage collection is one of the only modern programming practices for which I've seen conclusive evidence that it reduces bug rates.  I don't follow the programming language literature closely, so there are probably others.  I'm persuaded that lexical scoping, non-nullable variables and single assignment similarly reduce bug rates and debugging time, but can't justify those conclusions with research results.

I have a second, more conservative proposal about single-assignment that should accomodate single-assignment enthusiasts without imposing any burden on other developers.  As time permits, I'll write about it this week.

-- 
Michael
Reply all
Reply to author
Forward
0 new messages