Proposal: Allow Getters and Setters to Throw

One of the aspects of Swift that I like is computed properties for
structures and classes. It allows for adding logic when obtaining values or
for having the returned value be dependent on another.

As of the `ErrorType` protocol introduction in Swift 2, we can throw errors
when it comes to functions and initializers. However, this does not apply
to getters and setters.

struct File<Data> {
    var contents: Data {
        get throws { ... }
        set throws { ... }
    }
}

A better example would be getting and setting the current working directory
of the process:

import Foundation

extension Process {
    static var workingDirectory: String {
        get {
            let fileManager = NSFileManager.defaultManager()
            return fileManager.currentDirectoryPath
        }
        set throws {
            let fileManager = NSFileManager.defaultManager()
            guard fileManager.changeCurrentDirectoryPath(newValue) else {
                throw Error("...")
            }
        }
    }
}

7 Likes

+1 to this. Subscripts should also be able to throw and currently cannot.

···

On Dec 5, 2015, at 9:08 PM, Nikolai Vazquez via swift-evolution <swift-evolution@swift.org> wrote:

One of the aspects of Swift that I like is computed properties for structures and classes. It allows for adding logic when obtaining values or for having the returned value be dependent on another.

As of the `ErrorType` protocol introduction in Swift 2, we can throw errors when it comes to functions and initializers. However, this does not apply to getters and setters.

struct File<Data> {
    var contents: Data {
        get throws { ... }
        set throws { ... }
    }
}

A better example would be getting and setting the current working directory of the process:

import Foundation

extension Process {
    static var workingDirectory: String {
        get {
            let fileManager = NSFileManager.defaultManager()
            return fileManager.currentDirectoryPath
        }
        set throws {
            let fileManager = NSFileManager.defaultManager()
            guard fileManager.changeCurrentDirectoryPath(newValue) else {
                throw Error("...")
            }
        }
    }
}

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

1 Like

One of the aspects of Swift that I like is computed properties for structures and classes. It allows for adding logic when obtaining values or for having the returned value be

+1 to this. Subscripts should also be able to throw and currently cannot.

+1 from me as well. Subscripts also currently cannot be generic.

I consider all of these implementation limitations, not intentional parts of the design of Swift. Patches would be very very welcome to help improve these areas.

-Chris

···

On Dec 5, 2015, at 9:08 PM, Nikolai Vazquez via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 5, 2015, at 7:17 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

dependent on another.

As of the `ErrorType` protocol introduction in Swift 2, we can throw errors when it comes to functions and initializers. However, this does not apply to getters and setters.

struct File<Data> {
    var contents: Data {
        get throws { ... }
        set throws { ... }
    }
}

A better example would be getting and setting the current working directory of the process:

import Foundation

extension Process {
    static var workingDirectory: String {
        get {
            let fileManager = NSFileManager.defaultManager()
            return fileManager.currentDirectoryPath
        }
        set throws {
            let fileManager = NSFileManager.defaultManager()
            guard fileManager.changeCurrentDirectoryPath(newValue) else {
                throw Error("...")
            }
        }
    }
}

_______________________________________________
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 <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

1 Like

+1

···

On Sat, Dec 5, 2015 at 10:17 PM Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

+1 to this. Subscripts should also be able to throw and currently cannot.

On Dec 5, 2015, at 9:08 PM, Nikolai Vazquez via swift-evolution < > swift-evolution@swift.org> wrote:

One of the aspects of Swift that I like is computed properties for
structures and classes. It allows for adding logic when obtaining values or
for having the returned value be dependent on another.

As of the `ErrorType` protocol introduction in Swift 2, we can throw
errors when it comes to functions and initializers. However, this does not
apply to getters and setters.

struct File<Data> {
    var contents: Data {
        get throws { ... }
        set throws { ... }
    }
}

A better example would be getting and setting the current working
directory of the process:

import Foundation

extension Process {
    static var workingDirectory: String {
        get {
            let fileManager = NSFileManager.defaultManager()
            return fileManager.currentDirectoryPath
        }
        set throws {
            let fileManager = NSFileManager.defaultManager()
            guard fileManager.changeCurrentDirectoryPath(newValue) else {
                throw Error("...")
            }
        }
    }
}

_______________________________________________
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

Great to hear Chris and thanks for mentioning generic subscripts as well. I have a use case for a generic throwing subscript so I hope patches will be forthcoming.

···

Sent from my iPad

On Dec 6, 2015, at 12:07 AM, Chris Lattner <clattner@apple.com> wrote:

On Dec 5, 2015, at 9:08 PM, Nikolai Vazquez via swift-evolution <swift-evolution@swift.org> wrote:

One of the aspects of Swift that I like is computed properties for structures and classes. It allows for adding logic when obtaining values or for having the returned value be

On Dec 5, 2015, at 7:17 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

+1 to this. Subscripts should also be able to throw and currently cannot.

+1 from me as well. Subscripts also currently cannot be generic.

I consider all of these implementation limitations, not intentional parts of the design of Swift. Patches would be very very welcome to help improve these areas.

-Chris

dependent on another.

As of the `ErrorType` protocol introduction in Swift 2, we can throw errors when it comes to functions and initializers. However, this does not apply to getters and setters.

struct File<Data> {
    var contents: Data {
        get throws { ... }
        set throws { ... }
    }
}

A better example would be getting and setting the current working directory of the process:

import Foundation

extension Process {
    static var workingDirectory: String {
        get {
            let fileManager = NSFileManager.defaultManager()
            return fileManager.currentDirectoryPath
        }
        set throws {
            let fileManager = NSFileManager.defaultManager()
            guard fileManager.changeCurrentDirectoryPath(newValue) else {
                throw Error("...")
            }
        }
    }
}

_______________________________________________
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

Thanks for bringing this up, Nikolai. IMHO it does need a formal proposal because property (and subscript) access can be used in more interesting ways than just calling the getter or setter. In particular, how does this interact with inout? Is there a "rethrows" equivalent? What are the rules for overrides? (That last is probably very straightforward, but it ought to be written out explicitly.)

Jordan

···

On Dec 5, 2015, at 19:08, Nikolai Vazquez via swift-evolution <swift-evolution@swift.org> wrote:

One of the aspects of Swift that I like is computed properties for structures and classes. It allows for adding logic when obtaining values or for having the returned value be dependent on another.

As of the `ErrorType` protocol introduction in Swift 2, we can throw errors when it comes to functions and initializers. However, this does not apply to getters and setters.

struct File<Data> {
    var contents: Data {
        get throws { ... }
        set throws { ... }
    }
}

A better example would be getting and setting the current working directory of the process:

import Foundation

extension Process {
    static var workingDirectory: String {
        get {
            let fileManager = NSFileManager.defaultManager()
            return fileManager.currentDirectoryPath
        }
        set throws {
            let fileManager = NSFileManager.defaultManager()
            guard fileManager.changeCurrentDirectoryPath(newValue) else {
                throw Error("...")
            }
        }
    }
}

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

1 Like

+1 from here too!

···

søn. 6. dec. 2015 kl. 21.43 skrev Ilya Belenkiy via swift-evolution < swift-evolution@swift.org>:

+1

On Sat, Dec 5, 2015 at 10:17 PM Matthew Johnson via swift-evolution < > swift-evolution@swift.org> wrote:

+1 to this. Subscripts should also be able to throw and currently cannot.

On Dec 5, 2015, at 9:08 PM, Nikolai Vazquez via swift-evolution < >> swift-evolution@swift.org> wrote:

One of the aspects of Swift that I like is computed properties for
structures and classes. It allows for adding logic when obtaining values or
for having the returned value be dependent on another.

As of the `ErrorType` protocol introduction in Swift 2, we can throw
errors when it comes to functions and initializers. However, this does not
apply to getters and setters.

struct File<Data> {
    var contents: Data {
        get throws { ... }
        set throws { ... }
    }
}

A better example would be getting and setting the current working
directory of the process:

import Foundation

extension Process {
    static var workingDirectory: String {
        get {
            let fileManager = NSFileManager.defaultManager()
            return fileManager.currentDirectoryPath
        }
        set throws {
            let fileManager = NSFileManager.defaultManager()
            guard fileManager.changeCurrentDirectoryPath(newValue) else {
                throw Error("...")
            }
        }
    }
}

_______________________________________________
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

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

If I may propose some answers to your questions, to spur discussion:

In particular, how does this interact with inout?

When you use an `inout` parameter, notionally the getter is called before the function it’s passed to, and then the setter is called after. Either way, the error would be thrown at the call site and the callee would never even be aware that an error was possible. Basically, this just means that all the fancy optimizations where `swiftc` secretly elides the temporary variable used during `inout` have to be disabled, to ensure that any throw happens after the callee returns.

The inout parameter use will, of course, have to be marked with `try`. It would be nice if the grammar allowed you to mark only the `inout` parameter if that’s the semantic you wanted (not sure if `try &property` or `&try property` would be more appropriate for that); if for some reason that’s difficult to do, though, marking the entire call wouldn’t be a big deal.

Is there a "rethrows" equivalent?

I don’t think so. What would it be rethrowing an error from? The value if it happened to be a closure? That seems a bit esoteric.

What are the rules for overrides? (That last is probably very straightforward, but it ought to be written out explicitly.)

T -> U is a subtype of T throws -> U, right? So you could override a throwing accessor to make it non-throwing, but not the other way around.

···

--
Brent Royal-Gordon
Architechies

One could associate `throws` with getter and setter, not with the subscript itself, e.g.

subscript(index: Int) {
  get throws {
    // ...
  }
  set {
    // ...
  }
}

Pozdrawiam – Regards,
Adrian Kashivskyy

···

Wiadomość napisana przez Jordan Rose via swift-evolution <swift-evolution@swift.org> w dniu 07.12.2015, o godz. 20:59:

Thanks for bringing this up, Nikolai. IMHO it does need a formal proposal because property (and subscript) access can be used in more interesting ways than just calling the getter or setter. In particular, how does this interact with inout? Is there a "rethrows" equivalent? What are the rules for overrides? (That last is probably very straightforward, but it ought to be written out explicitly.)

Jordan

On Dec 5, 2015, at 19:08, Nikolai Vazquez via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

One of the aspects of Swift that I like is computed properties for structures and classes. It allows for adding logic when obtaining values or for having the returned value be dependent on another.

As of the `ErrorType` protocol introduction in Swift 2, we can throw errors when it comes to functions and initializers. However, this does not apply to getters and setters.

struct File<Data> {
    var contents: Data {
        get throws { ... }
        set throws { ... }
    }
}

A better example would be getting and setting the current working directory of the process:

import Foundation

extension Process {
    static var workingDirectory: String {
        get {
            let fileManager = NSFileManager.defaultManager()
            return fileManager.currentDirectoryPath
        }
        set throws {
            let fileManager = NSFileManager.defaultManager()
            guard fileManager.changeCurrentDirectoryPath(newValue) else {
                throw Error("...")
            }
        }
    }
}

_______________________________________________
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

Is there a "rethrows" equivalent?

I don’t think so. What would it be rethrowing an error from? The value if it happened to be a closure? That seems a bit esoteric.

This isn't particularly interesting for a property, but may be useful for a subscript that took a closure as an index. (I personally wouldn't like such an API, but think of something like XPath <Microsoft Learn: Build skills that open doors in your career)

Jordan

Brent Royal-Gordon <brent@...> writes:

When reading this excellent proposal in December, my colleagues and I had just
had a discussion about the very same topic.

I am bumping because I think it would be a great addition to the language - and
since I have not seen the same proposal discussed in other threads.
Please excuse me if the topic has already been discussed elsewhere.

A very quick summary of the thread:
Basically Nikolai Vazquez proposes that getters and setters can be marked
as 'throws'.
Chris Lattner responds that he thinks that the feature does not need a formal
proposal, since the lack of the feature is an implementation detail.
Jordan Rose notes that there are subtleties of the feature that would be good to
discuss in a formal proposal.

I would like to try and summarise the comments so far into a formal proposal
- although the internal optimisations of swiftc regarding inout parameters is
beyond my knowledge.

Any comments on whether the feature is a good idea - or whether a
formal proposal is the next step to take?

Is there a "rethrows" equivalent?

I don’t think so. What would it be rethrowing an error from? The value if it happened to be a closure? That seems a bit esoteric.

This isn't particularly interesting for a property, but may be useful for a subscript that took a closure as an index. (I personally wouldn't like such an API, but think of something like XPath.)

You’re right—I wasn’t thinking of subscripts.

···

--
Brent Royal-Gordon
Architechies

+1 A formal proposal would be awesome. This would be a great feature to the language.

···

--
Richard

On Mar 12, 2016, at 4:59 AM, Morten Bek Ditlevsen via swift-evolution <swift-evolution@swift.org> wrote:

Brent Royal-Gordon <brent@...> writes:

When reading this excellent proposal in December, my colleagues and I had just
had a discussion about the very same topic.

I am bumping because I think it would be a great addition to the language - and
since I have not seen the same proposal discussed in other threads.
Please excuse me if the topic has already been discussed elsewhere.

A very quick summary of the thread:
Basically Nikolai Vazquez proposes that getters and setters can be marked
as 'throws'.
Chris Lattner responds that he thinks that the feature does not need a formal
proposal, since the lack of the feature is an implementation detail.
Jordan Rose notes that there are subtleties of the feature that would be good to
discuss in a formal proposal.

I would like to try and summarise the comments so far into a formal proposal
- although the internal optimisations of swiftc regarding inout parameters is
beyond my knowledge.

Any comments on whether the feature is a good idea - or whether a
formal proposal is the next step to take?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Devolution&d=CwIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=Ezje1IF3xGXfUMfsj4fBc7oM7BcJys1dhQ6psfXzLMU&m=9a5UK9m7tDsJdUS2Z_mLPI3NTxiyAGccVhtiwBCUI3o&s=7UfO0mdMczc0ncEtu_aVTQsEJSc9OVmidpKDj8QUmiI&e=

Hi, any news about this proposal yet?
In Swift 5 its not included, but you can use the new Result Type instead.

I agree. This would definitely be useful, for example in custom json decoders.

struct Foo {
  subscript <T>(value: T) -> T {
        return value
    }
}

This compiles and runs fine for me.

The post you quoted was from December 2015, when it did not :slight_smile:

3 Likes

Oops :stuck_out_tongue:

If someone wants to pick this up, I’d be happy to guide them through the implementation. There’s some fairly serious compiler work involved, though, including adding new kinds of apply instruction to SIL.

7 Likes

I would be very happy to pick this up and work on an implementation! I believe it would require changes to a lot of areas (like the Parser, Sema, SIL, IRGen, etc)?

7 Likes

Yes, it will. Feel free to start a compiler-development thread and @ me.

2 Likes