4 ms·
I wish I could upvote this a hundred times; rarely have I seen so well-laid out a post on such a subtle topic. Just as I would form a thought like, "the author
by blahedo 12y ago
I wish I could upvote this a hundred times; rarely have I seen so well-laid out a post on such a subtle topic. Just as I would form a thought like, "the author needs to explicitly break this down as an issue of variables vs values", they did so.
Part of the difficulty here (and part of why others are having a hard time understanding it) is that immutable arrays and mutable arrays are really two different types, and unlike many other types (which are inherently one or the other), you really want both. A Java analogy is that there are two different string types: String, which is immutable, and StringBuilder, which is mutable[0]; but this is a property of the value, not of the variable. (Other languages have similar string classes, and Swift might well also.) For C++ folks, the distinction between mutability of variable and mutability of value is shown in the placement of "const", i.e. "const foo ∗" vs "foo const ∗" (which of course leads us to "const foo const ∗", and the whole thing is a syntactic mess, but anyway), and object values which are mutable can behave differently from values which aren't even when the underlying type is the same. In your own code in any language, of course, you can design a class so that its objects are immutable simply by not giving the user any access to set instance variables; and if you wanted both mutable and immutable versions, even without particular language support, you could make a MutableFoo and an ImmutableFoo that are copy-constructible from each other.
What may confuse the issue here is the idea that we might want brief syntax for both kinds of array. But whatever the language designers decide, the OP is exactly right to point out that they really, really need to think this through and divorce mutability of values from mutability of variables.
[0] Technically three, because StringBuffer is also there, but that's not relevant to this discussion.
- deleted 12y ago[deleted]
- meowface 12y agoI agree. Python, for example, has a list type (mutable), and a tuple type (immutable). Swift could simply adopt the same thing and use `(1, 2, 3)` for immutable arrays and `[1, 2, 3]` for mutable arrays. It would break backwards compatibility but it is a beta. Every other language (Ruby, Python, PHP, Javascript, for example) that uses `[]` as syntax for arrays always uses it as a mutable array type. I don't see why Swift shouldn't do the same, and provide a separate type and possibly new syntax for the immutable version.
- cscurmudgeon 12y agoThis is an excellent post. A meta comment (not on Swift): the number of new languages with C-like syntax and nothing revolutionary semantically is baffling. Do we really need to master yet another C-like syntax to do X where a library (or an existing language) would have sufficed? Is this the new way to create technological walls?
- nardi 12y agoAre you kidding? Swift has a TON of revolutionary stuff over C, including algebraic data types, optionals, destructuring pattern matching, and a lot more. Rust too. There are a ton of new "C-like" languages that are light years beyond C99. Edit: Not to mention automated memory management!
- cscurmudgeon 12y agoI meant C-like syntax. The laundry list of features you mentioned is present in lots of existing mature languages (not C). I don't understand the need to create something rickety without significant innovation (over any relevant language (e.g. SML, Haskell, Racket) and not just C).
- nardi 12y agoYou complained about new C-like languages (C-like in syntax) not being any better than C. I mentioned some ways that new C-like languages (C-like in syntax) are much better than C. Now you're complaining that other languages already had those features. I don't contest that. Doesn't change the fact that your first comment was misguided.
- cscurmudgeon 12y agoYou misunderstood my first comment. I meant new C-like-in-syntax have nothing revolutionary semantically across the board. This is a double blow as each new C-like syntax is difficult to master (compared to Lispy languages) and contributes nothing semantically new.
- to3m 12y agoThe silly thing is they already have NSArray (immutable) and NSMutableArray (mutable) on the Objective-C side. So you'd expect anybody working on putting this stuff together to be familiar with this. I guess the four possibilities in Objective-C are: NSArray *const p; NSMutableArray *const p; NSArray *p; NSMutableArray *p; ("const NSArray *p" and so on makes no sense, as I understand it - the Objective side of Objective-C being not big on const.)
- deleted 12y ago[deleted]
- microtherion 12y agorarely have I seen so well-laid out a post on such a subtle topic I'll have to disagree. I thought the author was quite muddled in their thinking on values vs variables. One of the biggest misunderstandings in the article, and the reason why the proposed "solution" is worthless, is that all the examples discussed are of the form: let a = … var b = a while in reality a much more common "assignment" situation is that an array gets passed as a procedure argument, which has consistent behavior in both the older and the newer Swift array semantics, but would turn into a mess with the proposed "fix".
- blahedo 12y ago> ...but would turn into a mess with the proposed "fix". Can you explain why?
- microtherion 12y agoIf we have, using the proposed syntax: var a = [1,2,3] var b = [: 2,3,4 :] func arrayConsumer(arg: [Int]) {} Under the proposed semantics, arrayConsumer(a) would make arg an immutable variable referencing a mutable array (So assigning to arg[x] would be permitted), while arrayConsumer(b) would make arg an immutable variable referencing an immutable array (So assigning to arg[x] would be forbidden).
- tikhonj 12y agoThe proposed solution is not just a matter of syntax but of types: a and b would not be compatible. So a would have type [Int] and b would have type [:Int:]. You simply couldn't pass b into arrayConsumer without explicitly noting the change: arrayConsumer(b.immutableCopy()) Similarly, if you had a function that expected a mutable array, you would not be able to pass a in without making a mutable copy of it. func mutableArrayConsumer(arg : [:Int:]) { ... } var mutableA = a.copyMutable() mutableArrayConsumer(mutableA) (You want to keep a reference to the mutable copy since a function that explicitly takes in a mutable array probably does something relevant to it.) This solves the problem neatly and statically without any implicit copying or conversions to trip you up.
- sbmassey 12y agoRegarding c++, const foo * is the same type as foo const * . For consistency, one should postfix the const to the thing you want to be immutable, so foo const * is a pointer to an immutable foo, foo * const is an immutable pointer to a mutable foo, and foo const * const is an immutable pointer to an immutable foo. It works pretty well, as far as I can see.
- blahedo 12y agoArgh, yes, you're exactly right, and now I'm too late to edit my post. I hate it when I get that backwards; sorry about that.
- josephlord 12y agoIt may handle some of the subtly of assignment and references but there is a lack of understanding of Swift. If it is a general debate about the meaning of assignment it isn't just about arrays but structs and dictionaries too. If you want to opt in to a shareable mutable array it is easy to implement it by wrapping it in an object (class based) and passing that around.