stack classes

if it wasn't already discussed here is the preliminary proposal, if it was
then my +1 to the feature.

i propose we have an explicit apparatus to denote classes having stack
storage.

stack class StackObject { // guaranteed to be on stack
}

class NonStackObject { // is not guaranteed to be on stack, can be on heap
as well
}

this is for performance reasons. sometimes what we need is “structs with
deinit” and as this is not going to happen the next best thing could be
“lightweight” classes. this shall be self obvious, here are few examples:

stack class StackObject {
    var variable = 0

    func foo() {
        print(“i am ok to live on stack”)
    }
}

stack class BadObject {
    var variable = 0

    func foo() {
        DispatchQueue.main.async { // error: can’t be a stack class
            self.variable = 1
        }
    }
}

class NonStackObject {
    …
}

foo() {
    let stackObject = StackObject()

    DispatchQueue.main.async {
        stackObject.foo() // error: can’t use a stack object in this
context
    }
}

Could you explain more about your use case? I am not sure I understand the motivation…

Also, what are you hoping to dealloc in structs?

Thanks,
Jon

···

On Oct 27, 2017, at 6:27 AM, Mike Kluev via swift-evolution <swift-evolution@swift.org> wrote:

if it wasn't already discussed here is the preliminary proposal, if it was then my +1 to the feature.

i propose we have an explicit apparatus to denote classes having stack storage.

stack class StackObject { // guaranteed to be on stack
}

class NonStackObject { // is not guaranteed to be on stack, can be on heap as well
}

this is for performance reasons. sometimes what we need is “structs with deinit” and as this is not going to happen the next best thing could be “lightweight” classes. this shall be self obvious, here are few examples:

stack class StackObject {
    var variable = 0

    func foo() {
        print(“i am ok to live on stack”)
    }
}

stack class BadObject {
    var variable = 0

    func foo() {
        DispatchQueue.main.async { // error: can’t be a stack class
            self.variable = 1
        }
    }
}

class NonStackObject {
    …
}

foo() {
    let stackObject = StackObject()

    DispatchQueue.main.async {
        stackObject.foo() // error: can’t use a stack object in this context
    }
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

if it wasn't already discussed here is the preliminary proposal, if it was then my +1 to the feature.

i propose we have an explicit apparatus to denote classes having stack storage.

stack class StackObject { // guaranteed to be on stack
}

class NonStackObject { // is not guaranteed to be on stack, can be on heap as well
}

this is for performance reasons. sometimes what we need is “structs with deinit” and as this is not going to happen the next best thing could be “lightweight” classes. this shall be self obvious, here are few examples:

Move-only struct types will be able to provide deinit. See the ownership manifesto.

John.

···

On Oct 27, 2017, at 9:27 AM, Mike Kluev via swift-evolution <swift-evolution@swift.org> wrote:

stack class StackObject {
    var variable = 0

    func foo() {
        print(“i am ok to live on stack”)
    }
}

stack class BadObject {
    var variable = 0

    func foo() {
        DispatchQueue.main.async { // error: can’t be a stack class
            self.variable = 1
        }
    }
}

class NonStackObject {
    …
}

foo() {
    let stackObject = StackObject()

    DispatchQueue.main.async {
        stackObject.foo() // error: can’t use a stack object in this context
    }
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Hello,

It looks like you want compiler guarantees that an object will be "deinited" at the end of a syntactic block:

  func f() {
    let a = Object()
    ...
    // <- guarantee that a.deinit is called here
  }

Currently, Swift does not grant such guarantee. If the object gets retained somewhere, its deallocation is postponed:
  
  var storage: [Object] = []
  func f() {
    let a = Object()
    storage.append(a)
    // <- a.deinit is not called here
  }

With your proposal, the code above would not compile.

The current Swift way to guarantee "cleanup" tasks is the `defer` statement:

  func f() {
    let a = Object()
    defer { a.cleanup() }
    ...
  }

But this has several defects: object is not fully responsible of its state, and one can get "zombie" values that stay around:

  var storage: [Object] = []
  func f() {
    let a = Object()
    defer { a.cleanup() } // <- can be forgotten
    storage.append(a) // <- storage will contain "zombie" object
  }

So I understand how it looks like Swift does not currently support what C++ programmers are used to when they mix RAII with guaranteed stack allocation. Note, though, that in C++ guaranteed stack allocation comes for the declaration of a value, not from its type.

Is it the correct context of your pitch? Given the immense C++ experience of Swift designers, this is surely something they know pretty well. I don't know why they did not bring this to Swift. This question itself is an interesting topic!

Gwendal

···

Le 27 oct. 2017 à 15:27, Mike Kluev via swift-evolution <swift-evolution@swift.org> a écrit :

if it wasn't already discussed here is the preliminary proposal, if it was then my +1 to the feature.

i propose we have an explicit apparatus to denote classes having stack storage.

stack class StackObject { // guaranteed to be on stack
}

class NonStackObject { // is not guaranteed to be on stack, can be on heap as well
}

this is for performance reasons. sometimes what we need is “structs with deinit” and as this is not going to happen the next best thing could be “lightweight” classes. this shall be self obvious, here are few examples:

stack class StackObject {
    var variable = 0

    func foo() {
        print(“i am ok to live on stack”)
    }
}

stack class BadObject {
    var variable = 0

    func foo() {
        DispatchQueue.main.async { // error: can’t be a stack class
            self.variable = 1
        }
    }
}

class NonStackObject {
    …
}

foo() {
    let stackObject = StackObject()

    DispatchQueue.main.async {
        stackObject.foo() // error: can’t use a stack object in this context
    }
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m highly supportive of this, but this pitch is incomplete. Unless we
restrict stack-classes to be non-escaping, and non copyable, at the minimum
we need to force the user to implement a copy initializer as well as deinit.
If we also want to support moves, this could make the compiler diagnostics
more complex since now it’s possible for a variable to be deinitialized
before the end of a block. Also as a nit, I would rather such a thing use
the struct keyword as I associate the keyword class in Swift with heap
indirection.

···

On Fri, Oct 27, 2017 at 10:49 AM, Gwendal Roué via swift-evolution < swift-evolution@swift.org> wrote:

Hello,

It looks like you want compiler guarantees that an object will be
"deinited" at the end of a syntactic block:

        func f() {
                let a = Object()
                ...
                // <- guarantee that a.deinit is called here
        }

Currently, Swift does not grant such guarantee. If the object gets
retained somewhere, its deallocation is postponed:

        var storage: [Object] = []
        func f() {
                let a = Object()
                storage.append(a)
                // <- a.deinit is not called here
        }

With your proposal, the code above would not compile.

The current Swift way to guarantee "cleanup" tasks is the `defer`
statement:

        func f() {
                let a = Object()
                defer { a.cleanup() }
                ...
        }

But this has several defects: object is not fully responsible of its
state, and one can get "zombie" values that stay around:

        var storage: [Object] = []
        func f() {
                let a = Object()
                defer { a.cleanup() } // <- can be forgotten
                storage.append(a) // <- storage will contain "zombie"
object
        }

So I understand how it looks like Swift does not currently support what
C++ programmers are used to when they mix RAII with guaranteed stack
allocation. Note, though, that in C++ guaranteed stack allocation comes for
the declaration of a value, not from its type.

Is it the correct context of your pitch? Given the immense C++ experience
of Swift designers, this is surely something they know pretty well. I don't
know why they did not bring this to Swift. This question itself is an
interesting topic!

Gwendal

> Le 27 oct. 2017 à 15:27, Mike Kluev via swift-evolution < > swift-evolution@swift.org> a écrit :
>
> if it wasn't already discussed here is the preliminary proposal, if it
was then my +1 to the feature.
>
> i propose we have an explicit apparatus to denote classes having stack
storage.
>
> stack class StackObject { // guaranteed to be on stack
> }
>
> class NonStackObject { // is not guaranteed to be on stack, can be on
heap as well
> }
>
> this is for performance reasons. sometimes what we need is “structs with
deinit” and as this is not going to happen the next best thing could be
“lightweight” classes. this shall be self obvious, here are few examples:
>
> stack class StackObject {
> var variable = 0
>
> func foo() {
> print(“i am ok to live on stack”)
> }
> }
>
> stack class BadObject {
> var variable = 0
>
> func foo() {
> DispatchQueue.main.async { // error: can’t be a stack class
> self.variable = 1
> }
> }
> }
>
> class NonStackObject {
> …
> }
>
> foo() {
> let stackObject = StackObject()
>
> DispatchQueue.main.async {
> stackObject.foo() // error: can’t use a stack object in this
context
> }
> }
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution