# Unary operator key paths

**URL:** <https://forums.swift.org/t/unary-operator-key-paths/51920>\
**Category:** Pitches\
**Created:** [September 9, 2021, 3:31pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920 "2021-09-09T15:31:59Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ilias\_Karim](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ilias_karim/32/2339_2.png) [@Ilias\_Karim](https://forums.swift.org/u/Ilias_Karim)\
**Post date:** [September 9, 2021, 3:31pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/1 "2021-09-09T15:31:59Z")

</div>

Current solutions to getting the inverse value of a bool using key path syntax, or inverting a number from positive to negative or vice versa require adding extensions to the relevant type.

See discussion [`toggled` or `isFalse` property/method on bool for use with KeyPath APIs - Evolution / Discussion - Swift Forums](https://forums.swift.org/t/toggled-or-isfalse-property-method-on-bool-for-use-with-keypath-apis/51464)

This is one existing workaround.

```swift
extension Bool {
  var not: Bool {
    return !self
  }
}

let yes = true
let no = yes[keyPath: \Bool.not] // false

```

Here is a naive implementation that could work, but doesn't, without something like this pitch here.

```swift
let yes = true
let no = yes[keyPath: \!] // Expected expression path in Swift key path

```

The boilerplate `not` extension on Bool should _not_ be necessary for a developer to write, because it is simply using a unary operator. It is useful in use cases such as e.g. array.filter(otherArray.contains) since Swift lacks a complementary reject method where a developer could write array.reject(otherArray.contains). Let's not go the ruby route when unary key paths provide value and don't introduce new methods to the namespace.

Enabling unary operators for key path usage also makes it possible to use another unary operator, `-`.  
This example will not compile.

```swift

let one = 1
let two = one[keyPath: \-] //Expected expression path in Swift key path

```

Again, it requires more boilerplate for developers to write and include in the projects they write. See,

```swift
extension SignedNumeric {
  var inverse: Self {
    return -self
  }
}

let one = 1
let two = one[keyPath: \.inverse] // -1

```

Please provide your feedback.

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [September 9, 2021, 3:40pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/2 "2021-09-09T15:40:15Z")

</div>

How do you propose distinguishing prefix and postfix operators?

In the standard library the range-formation operator “`...`” can be used as both. In that specific case the return types are different, but one can easily imagine an operator where they were the same.

---

<div class="post-metadata">

**Author:** ![ensan-hcl](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ensan-hcl/32/15186_2.png) [@ensan-hcl](https://forums.swift.org/u/ensan-hcl)\
**Post date:** [September 9, 2021, 3:46pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/3 "2021-09-09T15:46:13Z")

</div>

> [@Ilias\_Karim](#):
>
> ```swift
> let yes = true
> let no = yes[keyPath: \!] // Expected expression path in Swift key path
> 
> ```

How would it solve the problem `persons.filter(\.isChild.not)` after all? How to use `\!` here? `\.isChild.!`? What was proposed in the previous thread is `!\.isChild`, but then I don't think `\!` is necessary here. Am I missing something?

---

<div class="post-metadata">

**Author:** ![toph42](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/toph42/32/7807_2.png) [@toph42](https://forums.swift.org/u/toph42)\
**Post date:** [September 9, 2021, 3:46pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/4 "2021-09-09T15:46:42Z")

</div>

I’d prefer to be able to apply unary operators to `KeyPath` directly when `Value` can use the operator.

For example, I expected to be able to filter an `Array` of `ToDo`s for ones awaiting completion by just passing a negated `KeyPath` to its `completed` property:

```
let outstanding = todos.filter(!\.completed)

```

I was surprised when this didn’t work.

---

<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:** [September 10, 2021, 5:43am UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/5 "2021-09-10T05:43:56Z")

</div>

> [@toph42](#):
>
> I’d prefer to be able to apply unary operators to `KeyPath` directly when `Value` can use the operator.

Agreed.

Or, even for binary operators, as long as both operands are key paths:

```swift
let asciiDigits = "1️⃣2️⃣٣٤56".filter(\.isASCII && \.isNumber)

// maybe even this:
let nonASCIIDigits = "1️⃣2️⃣٣٤56".filter(!\.isASCII && \.isNumber)

```

---

<div class="post-metadata">

**Author:** ![ExFalsoQuodlibet](https://avatars.discourse-cdn.com/v4/letter/e/bbce88/32.png) [@ExFalsoQuodlibet](https://forums.swift.org/u/ExFalsoQuodlibet)\
**Post date:** [September 10, 2021, 7:30am UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/6 "2021-09-10T07:30:50Z")

</div>

`!` in Swift - in anywhere but a prefix position - always means "force a value where the compiler is not sure it exists", that is, when force unwrapping or in case of `try!`. Using `!` as the last expression in a chain **is confusing** , more so for beginners, so please let's avoid it. `!` communicates "urgency" and Swift leverages this interpretation: the reason for the `prefix !` negation is historical, and not really related to how Swift typically represents concepts with symbols, so please let's not proliferate it.

I think it would be better to automatically create keypath versions of operators when defining them, but it doesn't seem possible right now, with the current `KeyPath` APIs.

---

<div class="post-metadata">

**Author:** ![Ilias\_Karim](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ilias_karim/32/2339_2.png) [@Ilias\_Karim](https://forums.swift.org/u/Ilias_Karim)\
**Post date:** [September 10, 2021, 2:50pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/7 "2021-09-10T14:50:52Z")

</div>

Thank you for your response @ensan-hcl. If I understand your suggestion, `\.isChild.!` is what I did pitch, yes, although @toph42's suggestion of `!\.isChild` agrees with me.

> [@ensan-hcl](#):
>
> What was proposed in the previous thread is `!\.isChild` , but then I don't think `\!` is necessary here. Am I missing something?

While I do not understand your question (perhaps a complete code sample would help), `!\.isChild` was not in proposed in the [previous thread](https://forums.swift.org/t/toggled-or-isfalse-property-method-on-bool-for-use-with-keypath-apis/51464) from what I can tell.

However, after your comment @toph42 did write out an example using the syntax you wrote was proposed in the previous thread. Applying unary operators to `KeyPath` directly when `Value` can use the operator, to use his precise words, sounds like a great idea to me.

---

<div class="post-metadata">

**Author:** ![Ilias\_Karim](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ilias_karim/32/2339_2.png) [@Ilias\_Karim](https://forums.swift.org/u/Ilias_Karim)\
**Post date:** [September 10, 2021, 2:56pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/8 "2021-09-10T14:56:38Z")

</div>

This is an excellent point you raise, so good an argument that it likely would block any such proposal of applying unary oparators to `KeyPath` directly when `Value` can use the operator.

One proposal not just to move this pitch forward but to advance the language to smooth out its rough edges would be to deprecate ! for force unwrap and add a throwing .forceUnwrap() to Optional, as well as deprecate try!, in my opinion.

Why repurpose a common unary operator used in diverse programming languages already in the design of a new one is entirely beyond me.

---

<div class="post-metadata">

**Author:** ![ensan-hcl](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ensan-hcl/32/15186_2.png) [@ensan-hcl](https://forums.swift.org/u/ensan-hcl)\
**Post date:** [September 10, 2021, 3:13pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/9 "2021-09-10T15:13:56Z")

</div>

Maybe my misunderstanding, sorry. Since the title is 'Unary operator key paths', I thought you are suggesting key paths for operators as `\!` . (About example, it should be `persons.filter(\.isChild.not)` , I totally mistook🙏)

I can just barely understand how the example `yes[keyPath: \!]` works. What I don't understand is, what is `\!` after all. For exapmle, `\.isChild` is actuall `\Person.isChild` . However, what is the `Root` of `\!` ? I want to hear more detailed design of `UnaryKeyPath` here.

---

<div class="post-metadata">

**Author:** ![Ilias\_Karim](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ilias_karim/32/2339_2.png) [@Ilias\_Karim](https://forums.swift.org/u/Ilias_Karim)\
**Post date:** [September 10, 2021, 5:08pm UTC](https://forums.swift.org/t/unary-operator-key-paths/51920/11 "2021-09-10T17:08:58Z")

</div>

@ensan-hcl, the root here in my original example `yes[keyPath: \!]` is `Bool` because `yes` is set to `true`. It's a poor example in the first place, that I wrote, because `let no = !yes` works, in this case. @toph42's [example](https://forums.swift.org/t/unary-operator-key-paths/51920/4) expresses the intent of my pitch much better. That is,

```swift
let outstanding = todos.filter(!\.completed)

```
