# \[Pitch\] Effectful Read-only Properties

**URL:** <https://forums.swift.org/t/pitch-effectful-read-only-properties/44090>\
**Category:** Pitches\
**Tags:** concurrency, properties\
**Created:** [January 23, 2021, 12:44am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090 "2021-01-23T00:44:02Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![kavon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kavon/32/9774_2.png) [@kavon](https://forums.swift.org/u/kavon)\
**Post date:** [January 23, 2021, 12:44am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/1 "2021-01-23T00:44:02Z")

</div>

Hi everyone,

I'd like to share a proposal that allows some properties to have effects specifiers (`throws` and `async`) added to them. Any thoughts or feedback would be greatly appreciated. Please [see here for the complete and most up-to-date version of this proposal](https://github.com/kavon/swift-evolution/blob/async-prop-pitch1/proposals/nnnn-effectful-readonly-properties.md).  
As an appetizer, below you will find the first few sections of the proposal:

* * *

## Introduction

Nominal types such as classes, structs, and enums in Swift support [computed properties](https://docs.swift.org/swift-book/LanguageGuide/Properties.html), which are members of the type that invoke programmer-specified computations when getting or setting them; instead of being tied to storage like stored properties. The recently accepted proposal [SE-0296](https://github.com/kavon/swift-evolution/blob/main/proposals/0296-async-await.md) introduced asynchronous functions via `async`, in conjunction with `await`, but did not specify that computed properties can support effects like asynchrony. Furthermore, to take full advantage of `async` properties, the ability to specify that a property `throws` is also important. This document aims to partially fill in this gap by proposing a syntax and semantics for effectful read-only computed properties.

#### Terminology

A _read-only computed property_ is a computed property that only defines a `get`-ter, which can be `mutating`. Throughout the remainder of this proposal, any unqualified mention of a "property" refers to a read-only computed property. Furthermore, unless otherwise specified, the concepts of synchrony, asynchrony, and the definition of something being "async" or "sync" are as described in [SE-0296](https://github.com/kavon/swift-evolution/blob/main/proposals/0296-async-await.md).

An _effect_ is an observable behavior of a function. Swift's type system tracks a few kinds of effects: `throws` indicates that the function may return along an exceptional failure path with an `Error`, `rethrows` indicates that a throwing closure passed into the function may be invoked, and `async` indicates that the function may reach a suspension point.

The [Swift concurrency roadmap](https://forums.swift.org/t/swift-concurrency-roadmap/41611) outlines a number of features that are referenced in this proposal, such as [structured concurrency](https://forums.swift.org/t/concurrency-structured-concurrency/41622) and [actors](https://forums.swift.org/t/concurrency-actors-actor-isolation/41613). Overviews of these features are out of the scope of this proposal, but basic understanding of the importance of these features is required to fully grasp the motivation of this proposal.

## Motivation

An asynchronous function is designed for computations that may or always will suspend to perform a context switch before returning. Of primary concern in this proposal are scenarios where the future use of Swift concurrency features are limited due to the lack of _effectful read-only computed properties_ (which I will refer to as simply "effectful properties" from now on), so we will consider those first. Then, we will consider programming patterns in existing Swift code where the availability of effectful properties would help simplify the code.

#### Future Code

An asynchronous call cannot appear within a synchronous context. This fundamental restriction means that properties will be severely limited in their ability to use Swift's new concurrency features. The only capability available to them is spawning detached tasks, but the completion of those tasks cannot be awaited in synchronous contexts:

```swift
// ...
class Socket {
  // ...
  public var alive : Bool {
    get {
      let handle = Task.runDetached { await self.checkSocketStatus() }
      // /-- ERROR: cannot 'await' in a sync context
      // v
      return await handle.get()
    }
  }

  private func checkSocketStatus() async -> Bool { /* ... */}
}

```

As one might imagine, a type that would like to take advantage of actors to isolate concurrent access to resources, while exposing information about those resources through properties, is not possible because one must use `await` to interact with the actor from outside of its isolation context:

```swift
struct Transaction { /* ... */ }
enum BankError : Error { /* ... */}

actor class AccountManager {
  // `lastTransaction` is viewed as async from outside of the actor
  func lastTransaction() -> Transaction { /* ... */ }
}

class BankAccount {
  // ...
  private let manager : AccountManager?
  var lastTransactionAmount : Int {
    get {
      guard manager != nil else {
      // /-- ERROR: cannot 'throw' in a non-throwing context
      // v
        throw BankError.notInYourFavor
      }
      // /-- ERROR: cannot 'await' in a sync context
      // v
      return await manager!.lastTransaction().amount
    }
  }
}

```

While the use of `throw` in the `lastTransactionAmount` getter is rather contrived, realistic uses of `throw` in properties have been [detailed in a prior pitch](https://github.com/beccadax/swift-evolution/blob/throwing-properties/proposals/0000-throwing-properties.md) and detached tasks [can be formulated to throw](https://github.com/DougGregor/swift-evolution/blob/structured-concurrency/proposals/nnnn-structured-concurrency.md#cancellation-1) a `CancellationError`.

Furthermore, without effectful read-only properties, actor classes cannot define _any_ computed properties that are accessible from outside of its isolation context as a consequence of their design: a suspension may be performed before entering the actor's isolation context. Thus, we cannot turn `AccountManager`'s `lastTransaction()` method into a computed property without treating it as `async`.

#### Existing Code

According to the [API design guidelines](https://swift.org/documentation/api-design-guidelines/), computed properties that do not quickly return, which includes asynchronous operations, are not what programmers typically expect:

> **Document the complexity of any computed property that is not O(1).** People often assume that property access involves no significant computation, because they have stored properties as a mental model. Be sure to alert them when that assumption may be violated.

but, computed properties that may block or fail do appear in practice (see the motivation in [this pitch](https://github.com/beccadax/swift-evolution/blob/throwing-properties/proposals/0000-throwing-properties.md)).

As a real-world example of the need for effectful properties, [the SDK defines a protocol](https://developer.apple.com/documentation/avfoundation/avasynchronouskeyvalueloading) `AVAsynchronousKeyValueLoading`, which is solely dedicated to querying the status of a type's property, while offering an asynchronous mechanism to load the properties. The types that conform to this protocol include [AVAsset](https://developer.apple.com/documentation/avfoundation/avasset), which relies on this protocol because its read-only properties are blocking and failable.

Let's distill the problem solved by `AVAsynchronousKeyValueLoading` into a simple example. In existing code, it is impossible for property `get` operation to also accept a completion handler, i.e., a closure for the property to invoke with the result of the operation. This is because a computed property's `get` operation accepts zero arguments (excluding `self`). Thus, existing code that wished to use computed properties in scenarios where the computation may be blocking must use various workarounds. One workaround is to define an additional asynchronous version of the property as a method that accepts a completion handler:

```swift
class NetworkResource {
  var isAvailable : Bool {
    get { /* a possibly blocking operation */ }
  }
  func isAvailableAsync(completionHandler: ((Bool) -> Void)?) {
    // method that returns without blocking.
    // completionHandler is invoked once operation completes.
  }
}

```

The problem with this code is that, even with a comment on `isAvailable` to document that a `get` on this property may block, the programmer may mistakenly use it instead of `isAvailableAsync` because it is easy to ignore a comment. But, if `isAvailable`'s `get` were marked with `async`, then the type system will force the programmer to use `await`, which tells the programmer that the property's operation may suspend until the operation completes. Thus, this effect specifier enhances the recommendation made in the [API design guidelines](https://swift.org/documentation/api-design-guidelines/) by leveraging the type checker to warn users that the property access may involve significant computation.

## Proposed solution

For the problems detailed in the motivation section, the proposed solution is to allow `async`, `throws`, or both of these effect specifiers to be marked on a read-only computed property's `get` definition:

```swift
// ...
class BankAccount {
  // ...
  var lastTransactionAmount : Int {
    get async throws { // <-- proposed: effects specifiers!
      guard manager != nil else {
        throw BankError.notInYourFavor
      }
      return await manager!.lastTransaction().amount
    }
  }
}

```

At corresponding use-sites of these properties, the expression will be treated as having the effects listed in the `get`-ter, requiring the usual `await` or `try` to surround it as-needed:

```swift
let acct = BankAccount()
let amount = 0
do {
  amount = try await acct.lastTransactionAmount
} catch { /* ... */ }

extension BankAccount {
  func hadRecentWithdrawl() async throws -> Bool {
    return try await lastTransactionAmount < 0
  }
}

```

The usual short-hands for do-try-catch, `try!` and `try?`, work as usual.

Computed properties that can be modified, such as via a `set`-ter, will not be allowed to use effects specifiers on their `get`-ter, regardless of whether the setter would require any effects specifiers. The main purpose of imposing such a restriction is to limit the scope of this proposal to a simple, useful, and easy-to-understand feature. Limiting effects specifiers to read-only properties in this proposal does _not_ prevent future proposals from offering them for all computed properties. For more discussion of why effectful setters are tricky, see the "Extensions considered" section of this proposal.

* * *

Please [see here for the complete and most up-to-date version of this proposal](https://github.com/kavon/swift-evolution/blob/async-prop-pitch1/proposals/nnnn-effectful-readonly-properties.md), which includes the detailed design and other considerations, such as those for actors!

Thanks,  
Kavon

---

<div class="post-metadata">

**Author:** ![masters3d](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@masters3d](https://forums.swift.org/u/masters3d)\
**Post date:** [January 23, 2021, 2:20am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/2 "2021-01-23T02:20:23Z")

</div>

I know you put lots of work on this and I enjoyed reading the proposal; but overall, I am -1 on the proposal. Swift should provide a way to call async functions from computed properties using [@asyncHandler](https://forums.swift.org/t/se-0296-async-await/42605/71)

I agree with you that blocking is not great on a computed property (specially on a UI thread) but if a computed property is blocking then it should not be a computed property imo.

The issue with the Actor's property being reached from outside the Actor should be addressed in the Actor pitch; Worst case we end up with Java style getters that happen to be async throwing. There is also the open question to re-entrancy.

> A _read-only computed property_ is a computed property that only defines a `get` -ter, which can be `mutating` .

I don't understand this. Can you show an example?

---

<div class="post-metadata">

**Author:** ![ktoso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ktoso/32/44526_2.png) [@ktoso](https://forums.swift.org/u/ktoso)\
**Post date:** [January 23, 2021, 3:46am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/3 "2021-01-23T03:46:37Z")

</div>

Great writeup, thanks Kavon — I think this makes sense 👍 Esp since call sites get the try/await anyway when so it’s “signal enough” that this isn’t just a trivial getter... 👍

I have some minor questions (which don’t impact the core design much, but figured we can flesh it out here).

Would the following be legal or not:

```swift
protocol P {
  var x: X { get async }
}

actor A {
  var x: X { .init() } 
}

```

or are implementations of such declared property forced into the longer version of `var x: X { get async { .init() } }`? Mostly just a “quality of life” question, about how annoying it is to my end users to implement protocols if I define them proactively as async etc.

Otherwise looking great and I’m also +1 for not allowing an async getter where a setter is present 👍

To address the re-entrancy and actor concerns @masters3d mentions, as I spent considerable time thinking about those: I don’t think it matters. If actors end up non-reentrant this proposal makes sense, if they end up reentrant this proposal still makes sense. If we allow `@reentrant` annotations and do non-reentrant, this proposal _still_ makes sense 🙂

---

<div class="post-metadata">

**Author:** ![ktoso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ktoso/32/44526_2.png) [@ktoso](https://forums.swift.org/u/ktoso)\
**Post date:** [January 23, 2021, 6:45am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/4 "2021-01-23T06:45:56Z")

</div>

> [@masters3d](#):
>
> > A _read-only computed property_ is a computed property that only defines a `get` -ter, which can be `mutating` .
> 
> I don't understand this. Can you show an example?

Here's an example:

```swift
protocol X {
    var s: String { mutating get }
}

struct S: X {
    var ss: Int = 0
    var s: String {
        mutating get {
            ss += 1
            return ""
        }
    }
}

```

such property _is_ allowed to be async or throwing. It's a bit weird that those exist, but I guess they make sense in a struct heavy world such as Swift 🙂 (this works today, check it out in the repl)

If it had a `set` too, it would not be allowed to have effects.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [January 23, 2021, 2:36pm UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/5 "2021-01-23T14:36:56Z")

</div>

I just want to echo @ktoso in saying that this is a great write-up, the motivating issue is a timely one, and the solution presented makes sense.

Regarding the QoL question, I'd be satisfied with the long form (i.e., writing out `get`) at the moment; there are a number of attributes permitted on getters that require writing out `get`, so there's precedent for that. The fix-it for automatically inserting requirements for conformance could and should be refined to take the required effects into account, which can alleviate some of the issue, and if in time there's enough `async` getters to justify a shorthand, we can always bikeshed where to put the annotation then.

I do wonder (and I hate to ask about expanding the scope of proposals) whether it would make sense to consider throwing and async get-only subscripts in the same breath as get-only properties.

---

<div class="post-metadata">

**Author:** ![ktoso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ktoso/32/44526_2.png) [@ktoso](https://forums.swift.org/u/ktoso)\
**Post date:** [January 23, 2021, 2:40pm UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/6 "2021-01-23T14:40:28Z")

</div>

> [@xwu](#):
>
> Regarding the QoL question, I'd be satisfied with the long form (i.e., writing out `get` ) at the moment; there are a number of attributes permitted on getters that require writing out `get` , so there's precedent for that.

I see, I missed the precedent — even though I guess I just spelled it out in the next post I made it seems, `mutating` gets the same treatment right? Makes sense, so I guess my QoL concern is moot in face of prior similar patterns requiring the same explicitness 👍

---

<div class="post-metadata">

**Author:** ![Chris\_Lattner3](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/chris_lattner3/32/348_2.png) [@Chris\_Lattner3](https://forums.swift.org/u/Chris_Lattner3)\
**Post date:** [January 25, 2021, 2:31am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/7 "2021-01-25T02:31:08Z")

</div>

this is a great proposal, thanks for tackling this. I'd suggest a few changes though:

1. In motivation, I'd mention the async sequence proposal as further motivation for this. It had to turn a few get-only properties on sequence into functions because of lack of this.

2. In motivation, I'd recommend mentioning throwing subscripts, something people have asked about many times. (but yes, ok, they typically want mutable throwing subscripts; one step at a time).

3. Instead of forbidding setters on a property with an effectful get, I'd recommend allowing a setter, but forbidding it from having effects. Rationale: the current proposal is a pretty significant API evolution dampener. We currently have the situation where you can publish a get-only property and upgrade it to mutable in subsequent releases, but this proposal breaks that.

Allowing setters without effects is a slight creep from your proposal, but doesn't prevent future API evolution limitations: if we decide to allow effects on setters in the future, we should still allow non-effected setters due to subtyping.

In any case, I'm very happy to see this, this will make the language more consistent, and this is a nice step towards supporting the full model. Even though it is a big project to define the "full model" (as [described](https://github.com/kavon/swift-evolution/blob/async-prop-pitch1/proposals/nnnn-effectful-readonly-properties.md#effectful-settable-properties) in alternatives considered) please make sure that whatever is implemented now (at the ABI level) is extensible to support the full model in the future if at all possible.

-Chris

---

<div class="post-metadata">

**Author:** ![Chris\_Lattner3](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/chris_lattner3/32/348_2.png) [@Chris\_Lattner3](https://forums.swift.org/u/Chris_Lattner3)\
**Post date:** [January 25, 2021, 2:32am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/8 "2021-01-25T02:32:25Z")

</div>

> [@masters3d](#):
>
> I know you put lots of work on this and I enjoyed reading the proposal; but overall, I am -1 on the proposal. Swift should provide a way to call async functions from computed properties using [@asyncHandler](https://forums.swift.org/t/se-0296-async-await/42605/71)

I don't see how this solves the problem. I think that the proposal has this right: we need a general solution to effects (including throws and rethrows) not just something for async.

-Chris

---

<div class="post-metadata">

**Author:** ![gwendal.roue](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwendal.roue/32/13992_2.png) [@gwendal.roue](https://forums.swift.org/u/gwendal.roue)\
**Post date:** [January 25, 2021, 4:32am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/9 "2021-01-25T04:32:30Z")

</div>

> [@Chris\_Lattner3](#):
>
> In motivation, I'd recommend mentioning throwing subscripts, something people have asked about many times.

Oh yes, please!

---

<div class="post-metadata">

**Author:** ![masters3d](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@masters3d](https://forums.swift.org/u/masters3d)\
**Post date:** [January 25, 2021, 6:20am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/10 "2021-01-25T06:20:12Z")

</div>

Perhaps I am missing the problem; I'd love to learn more about the problem. I do recognize that Actors might force our hand to provide a solution to async/throwing properties but as it is this solution could only give us async/throwing computed properties correct? Wouldn't we then we need a solution to stored properties in Actor code?

---

<div class="post-metadata">

**Author:** ![Chris\_Lattner3](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/chris_lattner3/32/348_2.png) [@Chris\_Lattner3](https://forums.swift.org/u/Chris_Lattner3)\
**Post date:** [January 25, 2021, 6:25am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/11 "2021-01-25T06:25:23Z")

</div>

> [@masters3d](#):
>
> Perhaps I am missing the problem; I'd love to learn more about the problem. I do recognize that Actors might force our hand to provide a solution to async/throwing properties but as it is this solution could only give us async/throwing computed properties correct? Wouldn't we then we need a solution to stored properties in Actor code?

Properties on actors are unrelated to this proposal, but I'll explain how they work:

Stored properties in an actor are always sync just like any other stored property - reading or writing to them doesn't imply any asynchronicity from within the actor, they are just normal local state.

The only time that you get async with them is when you access them from some other place that is outside of the actor (e.g. when they are public). Reaching across actor boundaries always turns sync things into async things (including sync functions etc), and so the get and set of a stored property should also be treated as an async access.

This is one reason why I think it is inevitable that this proposal will have to handle the case of async setters. That said, I can understand the goal of wanting to subset the complexity and do things one step at a time, we just should not cut off the subsequent steps.

-Chris

---

<div class="post-metadata">

**Author:** ![wowbagger](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wowbagger/32/13847_2.png) [@wowbagger](https://forums.swift.org/u/wowbagger)\
**Post date:** [January 25, 2021, 8:04am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/12 "2021-01-25T08:04:01Z")

</div>

> [@Chris\_Lattner3](#):
>
> In motivation, I'd mention the async sequence proposal as further motivation for this. It had to turn a few get-only properties on sequence into functions because of lack of this.

I concur. I was thinking about the [discussion](https://forums.swift.org/t/se-0298-async-await-sequences/43786/7) about `AsyncSequence.first()` while reading this proposal.

It was also mentioned in the [concurrency manifesto](https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782#extending-the-model-through-await):

> Swift currently doesn't allow property accessors to `throw` or be `async` . When this limitation is relaxed, it would be straight-forward to allow `actor var` s to provide the more natural API.

---

<div class="post-metadata">

**Author:** ![masters3d](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@masters3d](https://forums.swift.org/u/masters3d)\
**Post date:** [January 25, 2021, 3:40pm UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/13 "2021-01-25T15:40:30Z")

</div>

> [@Chris\_Lattner3](#):
>
> Reaching across actor boundaries always turns sync things into async things (including sync functions etc), and so the get and set of a stored property should also be treated as an async access.
> 
> This is one reason why I think it is inevitable that this proposal will have to handle the case of async setters. That said, I can understand the goal of wanting to subset the complexity and do things one step at a time, we just should not cut off the subsequent steps.
> 
> -Chris

Got it. I would be interested in seeing what a full model would look like from the user perspective. I would love to see an API similar to @propertyWrapper where as I user I could delegate the async/throwing to a type (this would not address subscripts thought).

---

<div class="post-metadata">

**Author:** ![kavon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kavon/32/9774_2.png) [@kavon](https://forums.swift.org/u/kavon)\
**Post date:** [January 25, 2021, 7:45pm UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/14 "2021-01-25T19:45:35Z")

</div>

> [@ktoso](#):
>
> Would the following be legal or not:
> 
> ```swift
> protocol P {
> var x: X { get async }
> }
> 
> actor A {
> var x: X { .init() } 
> }
> 
> ```
> 
> or are implementations of such declared property forced into the longer version of `var x: X { get async { .init() } }` ? Mostly just a “quality of life” question, about how annoying it is to my end users to implement protocols if I define them proactively as async etc.

Right, the proposal is missing some discussion of property conformance (I'll add a new section about that). For @xwu and others: My intention is to carry-over the conformance rules that apply to functions with effects. So, _a protocol's requirements will be satisfied if the property's getter has the same or fewer effects_.

So, in your example, `A` could conform to `P`. When accessing `x` through a value of type `A`, such as with `A().x`, it's the usual synchronous access. But, if you cast `A` to `P`, it's now async: `await (A() as P).x`. Here's a little example that typechecks today to demonstrate what I mean by carrying-over what happens for functions:

```swift
// All code here typechecks today.

protocol P {
  func f() async
}

protocol Q {
  func g() throws
}

protocol R {
  func h() async throws
}

class NoEffects : P, Q, R {
  func f() {}
  func g() {}
  func h() {}
}

class JustThrows : Q, R {
  func g() throws {}
  func h() throws {}
}

class JustAsync : P, R {
  func f() async {}
  func h() async {}
}

NoEffects().f()
NoEffects().g()
NoEffects().h()
_ = { await (NoEffects() as P).f() }
_ = { try! (NoEffects() as Q).g() }
_ = { try! await (NoEffects() as R).h() }

```

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [January 25, 2021, 7:58pm UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/15 "2021-01-25T19:58:29Z")

</div>

Allowing non-effectful setters to exist alongside an effectful getter still means that read-write operations, like passing `inout`, are possible and have effects, which actually increases the scope substantially. We should just do one proposal later that adds all of that at once.

I do think this proposal should be generalized to cover non-mutable `subscript`s; we have intentionally avoided treating properties and `subscript`s differently in the access model, and there doesn't seem to be a good reason to do so here.

---

<div class="post-metadata">

**Author:** ![ktoso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ktoso/32/44526_2.png) [@ktoso](https://forums.swift.org/u/ktoso)\
**Post date:** [January 25, 2021, 11:38pm UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/16 "2021-01-25T23:38:44Z")

</div>

> [@kavon](#):
>
> Right, the proposal is missing some discussion of property conformance (I'll add a new section about that). For @xwu and others: My intention is to carry-over the conformance rules that apply to functions with effects. So, _a protocol's requirements will be satisfied if the property's getter has the same or fewer effects_ .

Thanks, sounds good to me and the rules make sense 👍

---

<div class="post-metadata">

**Author:** ![kavon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kavon/32/9774_2.png) [@kavon](https://forums.swift.org/u/kavon)\
**Post date:** [January 29, 2021, 1:43am UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/17 "2021-01-29T01:43:40Z")

</div>

> [@Chris\_Lattner3](#):
>
> In motivation, I'd recommend mentioning throwing subscripts, something people have asked about many times. (but yes, ok, they typically want mutable throwing subscripts; one step at a time).

> [@xwu](#):
>
> I do wonder (and I hate to ask about expanding the scope of proposals) whether it would make sense to consider throwing and async get-only subscripts in the same breath as get-only properties.

I agree that get-only subscripts should be fine to add to this proposal. I'll update the pitch to reflect this soon.

Also, something that the pitch did not cover is key-paths. I've updated the pitch with discussion about why they are not included. I'll copy the text here for convenience:

* * *

#### KeyPaths

A [key-path expression](https://docs.swift.org/swift-book/ReferenceManual/Expressions.html) is syntactic sugar for instances of the `KeyPath` class and its type-erased siblings. The introduction of effectful properties would require changes to the synthesis of `subscript(keyPath:)` for each type. It would also probably require restrictions on type-erasure for key-paths that can access effectul properties.

For example, because we do not allow for function overloading based only on differences in effects, some sort of mechanism like `rethrows` and an equivalent version for `async` (such as a "reasync") would be required on `subscript(keyPath:)` as a starting-point. While a key-path literal can be [automatically treated as a function](https://github.com/apple/swift-evolution/blob/main/proposals/0249-key-path-literal-function-expressions.md), a general `KeyPath` value is not a function, so it cannot carry effects in its type. This causes problems when trying to make, for example, a `rethrows` version of `subscript(keyPath:)` work.

We could also introduce additional kinds of key-paths that have various capabilities, like the existing `WritableKeyPath` and `ReferenceWritableKeyPath`. Then, we could synthesize versions of `subscript` with the right effects specifiers on it, for example, `subscript<T : ThrowingKeyPath>(keyPath : T) throws`. This would require `KeyPath` kinds for all three new combinations of effects beyond "no effects".

So, a non-trivial restructuring of the type system, or significant extensions to the `KeyPath` API, would be required to make key-paths work for effectul properties. Thus, for now, we will disallow accesses to effectful properties via key-paths. There already exist restrictions on key-paths to mutable properties based on the instance type (e.g., `WritableKeyPath`), so it would not be unusual to disallow key-paths to effectful properties.

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [April 13, 2021, 10:19pm UTC](https://forums.swift.org/t/pitch-effectful-read-only-properties/44090/18 "2021-04-13T22:19:26Z")

</div>

Hey folks, we've initiated a review of this proposal over at [SE-0310: Effectful Read-only Properties](https://forums.swift.org/t/se-0310-effectful-read-only-properties/47401). Thanks everyone for improving the design through your participation in the pitch, and let's bring any further feedback over to that thread. Thanks!
