Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing generic struct for unnamed default parameter results in garbage properties

I'm seeing some odd behaviour in a class I created a while ago, where it seems that a struct's properties are changing immediately after being passed (copied) to a method.

I've boiled it down to a simple test case that can be run in a playground:

struct StructToPass<T> {
    let x: T
}

class MyClass<T> {
    func createAndPassStructWithValue(value: T) {
        let structToPass = StructToPass(x: value)
        println("Before passing to method: \(structToPass.x)")
        passStruct(structToPass)
    }

    func passStruct(_ theStruct: StructToPass<T>? = nil) {
        println("Inside method: \(theStruct!.x)")
    }
}

let myClass = MyClass<Int>()
myClass.createAndPassStructWithValue(42)

Looking at the relevant printed statements, it shows that the struct's x property has changed:

// Before passing to method: 42
// Inside method: 140734543799888


Creating the struct outside the class and calling passStruct(_:) directly causes the playground to crash, as does writing passStruct(_:) as a function:

// Causes playground to crash:
let aStruct = StructToPass(x: 42)
myClass.passStruct(aStruct)

// Also causes playground to crash:
func passStruct<T>(_ theStruct: StructToPass<T>? = nil) {}
passStruct(aStruct)


Changing the passStruct(_:) method/function to use the default external parameter name fixes the issue, as does introducing another parameter (before/after the default parameter):

// This works:
func passStruct<T>(theStruct: StructToPass<T>? = nil) {
    println("Inside function: \(theStruct!.x)")
}
passStruct(theStruct: aStruct)

// This also works:
func passStruct<T>(_ theStruct: StructToPass<T>? = nil, someOtherParam: Int) {
    println("Inside function: \(theStruct!.x)")
}
passStruct(aStruct, 42)


Is this a compiler bug? It seems the compiler doesn't like it when a generic function/method with a single argument with a default value doesn't use an external parameter name. It's a specific case, but I think it ought to work. If it shouldn't work, there ought to be a compiler warning.

like image 571
Stuart Avatar asked Apr 20 '15 20:04

Stuart


1 Answers

110% compiler bug. I've even tried this out of Playground. It all happily compiles until you want to add a line which actually does something, like sending a passStruct. There's all kinds of things wrong with this. I even had this fail:

func passStruct<T>(_ theStruct: StructToPass<T>? = (nil as StructToPass<T>?)) {
    println("Inside function: \(theStruct!.x)")
}

which I kinda thought might be the problem (even though it shouldn't be I've had that elsewhere).

Well found! Report it. They're clearly not finished with generics. In my experiments I found that generic class properties aren't allowed.

static let nilStruct: StructToPass<T>? = nil

does not compile, with one of the "not yet supported" error messages.

like image 94
Richard Birkett Avatar answered Oct 24 '22 14:10

Richard Birkett