Pitch: Deinit for structs


(Charles Srstka) #1

Introduction:

This is a rather simple proposal, requesting that structs allow the ‘deinit’ destructor, as classes currently do.

Motivation:

Sometimes it is necessary to create an object that wraps a network connection (that needs to be closed when the object is destroyed), or that writes to a file on the disk (that has to be closed when the object is destroyed). Often these objects will implement a close() method, but in the case that the user forgets to call this before the object is disposed of, it is good to call it in deinit just in case. However, deinit currently is available only to classes and not to structs. This means that value types currently cannot be used for network and file-backed constructs. Given Swift’s emphasis on value types, it seems that it would be good to add this functionality to value types.

Proposed Solution:

Allow the deinit destructor in structs.

Impact on Existing Code:

Should be no impact on existing code.

Charles


(Joe Groff) #2

Network and file-backed constructs naturally have identity, so classes are appropriate. What benefit would you get from making them structs? What does it mean to copy a socket?

-Joe

···

On Dec 23, 2015, at 1:07 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

Introduction:

This is a rather simple proposal, requesting that structs allow the ‘deinit’ destructor, as classes currently do.

Motivation:

Sometimes it is necessary to create an object that wraps a network connection (that needs to be closed when the object is destroyed), or that writes to a file on the disk (that has to be closed when the object is destroyed). Often these objects will implement a close() method, but in the case that the user forgets to call this before the object is disposed of, it is good to call it in deinit just in case. However, deinit currently is available only to classes and not to structs. This means that value types currently cannot be used for network and file-backed constructs. Given Swift’s emphasis on value types, it seems that it would be good to add this functionality to value types.


(David Owens II) #3

This is something I asked for before, then I realized it wouldn’t work.

func helper(rs: ResourceHandle) {}

let resource = ResourceHandle()
helper(resource)

result.doSomething() // error

Another example:

let x = Handle()

do {
  let y = x
} // resources are freed here as deinit is called

// x is not safe to use, and freed again when x goes out of scope

Everytime the struct value goes out of scope, the deinit would be called. The other option is to create move and copy semantics, as both would be required.

Given Swift’s emphasis on value types

I think this is a mischaracterization, and one that I’ve made in the past. Swift’s emphasis in on clarity and providing you the mechanism to create things that are value-types for APIs that should behave like a value. However, that doesn’t mean that everything should a struct first.

-David

···

On Dec 23, 2015, at 1:07 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

Introduction:

This is a rather simple proposal, requesting that structs allow the ‘deinit’ destructor, as classes currently do.

Motivation:

Sometimes it is necessary to create an object that wraps a network connection (that needs to be closed when the object is destroyed), or that writes to a file on the disk (that has to be closed when the object is destroyed). Often these objects will implement a close() method, but in the case that the user forgets to call this before the object is disposed of, it is good to call it in deinit just in case. However, deinit currently is available only to classes and not to structs. This means that value types currently cannot be used for network and file-backed constructs. Given Swift’s emphasis on value types, it seems that it would be good to add this functionality to value types.

Proposed Solution:

Allow the deinit destructor in structs.

Impact on Existing Code:

Should be no impact on existing code.

Charles

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


(Félix Cloutier) #4

Just chiming in with you two: deinit for a struct doesn't really work because structs are copied and destroyed all the time. Putting a file descriptor in a struct (along with destruction logic) would fail pretty hard without C++-like copy/move semantics.

Félix

···

Le 23 déc. 2015 à 16:21:42, David Owens II via swift-evolution <swift-evolution@swift.org> a écrit :

This is something I asked for before, then I realized it wouldn’t work.

func helper(rs: ResourceHandle) {}

let resource = ResourceHandle()
helper(resource)

result.doSomething() // error

Another example:

let x = Handle()

do {
  let y = x
} // resources are freed here as deinit is called

// x is not safe to use, and freed again when x goes out of scope

Everytime the struct value goes out of scope, the deinit would be called. The other option is to create move and copy semantics, as both would be required.

Given Swift’s emphasis on value types

I think this is a mischaracterization, and one that I’ve made in the past. Swift’s emphasis in on clarity and providing you the mechanism to create things that are value-types for APIs that should behave like a value. However, that doesn’t mean that everything should a struct first.

-David

On Dec 23, 2015, at 1:07 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction:

This is a rather simple proposal, requesting that structs allow the ‘deinit’ destructor, as classes currently do.

Motivation:

Sometimes it is necessary to create an object that wraps a network connection (that needs to be closed when the object is destroyed), or that writes to a file on the disk (that has to be closed when the object is destroyed). Often these objects will implement a close() method, but in the case that the user forgets to call this before the object is disposed of, it is good to call it in deinit just in case. However, deinit currently is available only to classes and not to structs. This means that value types currently cannot be used for network and file-backed constructs. Given Swift’s emphasis on value types, it seems that it would be good to add this functionality to value types.

Proposed Solution:

Allow the deinit destructor in structs.

Impact on Existing Code:

Should be no impact on existing code.

Charles

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Matthew Johnson) #5

Introduction:

This is a rather simple proposal, requesting that structs allow the ‘deinit’ destructor, as classes currently do.

Motivation:

Sometimes it is necessary to create an object that wraps a network connection (that needs to be closed when the object is destroyed), or that writes to a file on the disk (that has to be closed when the object is destroyed). Often these objects will implement a close() method, but in the case that the user forgets to call this before the object is disposed of, it is good to call it in deinit just in case. However, deinit currently is available only to classes and not to structs. This means that value types currently cannot be used for network and file-backed constructs. Given Swift’s emphasis on value types, it seems that it would be good to add this functionality to value types.

Network and file-backed constructs naturally have identity, so classes are appropriate. What benefit would you get from making them structs? What does it mean to copy a socket?

I wonder if the goal is to avoid a heap allocation. Under what circumstances can stack promotion be guaranteed for a final class?

···

Sent from my iPad

On Dec 23, 2015, at 3:15 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 23, 2015, at 1:07 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

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


(Joe Groff) #6

cc'ing Erik, who's working on stack promotion. We need to know the object's lifetime by proving it isn't escaped to somewhere that can extend its lifetime, which is hard to guarantee if you're calling functions from other modules. To guarantee a stack allocation it might be reasonable to have an attribute to say "I want this object to be stack allocated, so assert that it's still uniquely referenced by the time it goes out of scope" or something like that.

-Joe

···

On Dec 23, 2015, at 3:16 PM, Matthew Johnson <matthew@anandabits.com> wrote:

Sent from my iPad

On Dec 23, 2015, at 3:15 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 23, 2015, at 1:07 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

Introduction:

This is a rather simple proposal, requesting that structs allow the ‘deinit’ destructor, as classes currently do.

Motivation:

Sometimes it is necessary to create an object that wraps a network connection (that needs to be closed when the object is destroyed), or that writes to a file on the disk (that has to be closed when the object is destroyed). Often these objects will implement a close() method, but in the case that the user forgets to call this before the object is disposed of, it is good to call it in deinit just in case. However, deinit currently is available only to classes and not to structs. This means that value types currently cannot be used for network and file-backed constructs. Given Swift’s emphasis on value types, it seems that it would be good to add this functionality to value types.

Network and file-backed constructs naturally have identity, so classes are appropriate. What benefit would you get from making them structs? What does it mean to copy a socket?

I wonder if the goal is to avoid a heap allocation. Under what circumstances can stack promotion be guaranteed for a final class?


(Matthew Johnson) #7

Thanks for looping in Erik. An attribute would be cool. I would guess stack promotion maybe be easier to guarantee if / when we have a Rust-like ownership system that could allow “borrowing” without transferring ownership as well. Is that correct?

Matthew

···

On Dec 23, 2015, at 5:25 PM, Joe Groff <jgroff@apple.com> wrote:

On Dec 23, 2015, at 3:16 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On Dec 23, 2015, at 3:15 PM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 23, 2015, at 1:07 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction:

This is a rather simple proposal, requesting that structs allow the ‘deinit’ destructor, as classes currently do.

Motivation:

Sometimes it is necessary to create an object that wraps a network connection (that needs to be closed when the object is destroyed), or that writes to a file on the disk (that has to be closed when the object is destroyed). Often these objects will implement a close() method, but in the case that the user forgets to call this before the object is disposed of, it is good to call it in deinit just in case. However, deinit currently is available only to classes and not to structs. This means that value types currently cannot be used for network and file-backed constructs. Given Swift’s emphasis on value types, it seems that it would be good to add this functionality to value types.

Network and file-backed constructs naturally have identity, so classes are appropriate. What benefit would you get from making them structs? What does it mean to copy a socket?

I wonder if the goal is to avoid a heap allocation. Under what circumstances can stack promotion be guaranteed for a final class?

cc'ing Erik, who's working on stack promotion. We need to know the object's lifetime by proving it isn't escaped to somewhere that can extend its lifetime, which is hard to guarantee if you're calling functions from other modules. To guarantee a stack allocation it might be reasonable to have an attribute to say "I want this object to be stack allocated, so assert that it's still uniquely referenced by the time it goes out of scope" or something like that.


(Joe Groff) #8

That'd certainly make it easier, if everything you interact with is correctly annotated. I think you'd still want to be able to interop with code that hasn't been annotated with ownership conventions, or that needs to temporarily share ownership while still dynamically converging on a fixed lifetime.

-Joe

···

On Dec 23, 2015, at 3:29 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Dec 23, 2015, at 5:25 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Dec 23, 2015, at 3:16 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On Dec 23, 2015, at 3:15 PM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 23, 2015, at 1:07 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction:

This is a rather simple proposal, requesting that structs allow the ‘deinit’ destructor, as classes currently do.

Motivation:

Sometimes it is necessary to create an object that wraps a network connection (that needs to be closed when the object is destroyed), or that writes to a file on the disk (that has to be closed when the object is destroyed). Often these objects will implement a close() method, but in the case that the user forgets to call this before the object is disposed of, it is good to call it in deinit just in case. However, deinit currently is available only to classes and not to structs. This means that value types currently cannot be used for network and file-backed constructs. Given Swift’s emphasis on value types, it seems that it would be good to add this functionality to value types.

Network and file-backed constructs naturally have identity, so classes are appropriate. What benefit would you get from making them structs? What does it mean to copy a socket?

I wonder if the goal is to avoid a heap allocation. Under what circumstances can stack promotion be guaranteed for a final class?

cc'ing Erik, who's working on stack promotion. We need to know the object's lifetime by proving it isn't escaped to somewhere that can extend its lifetime, which is hard to guarantee if you're calling functions from other modules. To guarantee a stack allocation it might be reasonable to have an attribute to say "I want this object to be stack allocated, so assert that it's still uniquely referenced by the time it goes out of scope" or something like that.

Thanks for looping in Erik. An attribute would be cool. I would guess stack promotion maybe be easier to guarantee if / when we have a Rust-like ownership system that could allow “borrowing” without transferring ownership as well. Is that correct?