Proposal for simpler, more explicit control of references in Swift

Originator:nicklockwood81
Number:rdar://17172982 Date Originated:05/06/2014
Status:Open Resolved:
Product:Swift language Product Version:beta 1
Classification:Feature enhancement Reproducible:Always
 
Swift obscurs the concept of pointers by determing whether vars should be byref or byval based on the type. This seems simpler at first, but complicates many other language features, and makes mutability/immutability conceptually more complicated.

I propose that an explicit byref and byval keyword be added to the language that can be included when defining a var. If omitted, the rules would be the same by default as they are now (primitives &* structs byval by default, classes byref by default)

Benefits:

* You could use a class (for inheritance reasons), and still pass byval (for copy-on-reference)
* You could use a struct (for specific data alignment), but still pass byref (for performance)
* You could define immutable class instances using let (currently, only reference itself is immutable)
* The mutating keyword would be meaningful for classes as well as structs (more consistency)
* You could get rid of the separate inout keyword for method params and use byref



Here is an example of where byref / byval would simplify the language. Here I've defined a Vector struct and equivalent class:

struct VectorStruct {
    var x: Float
    var y: Float
    init (x: Float, y: Float) {
        self.x = x
        self.y = y
    }
}

var v1 = VectorStruct(x:5, y:6)
let v2 = v1

v1.x = 7   // defined with "var", so I can do this
v2.x       // still has a value of 5 because it was "let"
v2.x = 7   // error - can't modify "let" value


class VectorClass {
    var x: Float
    var y: Float
    init (x: Float, y: Float) {
        self.x = x
        self.y = y
    }
}

var v3 = VectorClass(x:5, y:6)
let v4 = v1

v3.x = 7   // still works as expected
v4.x       // oops - the value has changed to 7 even though v4 was "let"
v4.x = 7   // no error here - v4 is mutable despite being "let"

this is expected of course, because structs are value types and classes are reference types, but it's still very confusing. And my reasons for wanting to use a class may have nothing to do with mutability rules (I may want to inherit Vector3D from Vector2D for example)

If I could define my VectorClass vars like this:

byref var v3 = VectorClass(x:5, y:6)
byval let v4 = v1

Then the rules would be the same as for struct:

v3.x = 7   // still works the same
v4.x       // still has a value of 5 because assigning from a byref to byval copies the value
v4.x = 7   // this would be an error because you can't modify a byval value defined with "let"

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!