Keyword to refer to LHS of an assignment on the RHS

Oftentimes one wishes to assign to a variable a modified version of itself, but a special assignment operator such as += does not exist for that particular modification. Unfortunately, for very long variables, this requires writing out the full name on both sides of the equals sign — for instance, to negate a Bool, some.reallyLong.bool.variable = !some.reallyLong.bool.variable. This is unnecessarily verbose and impairs readability.

I propose the introduction of the keyword itself to refer to the LHS of an assignment on the RHS. This would allow e.g., some.reallyLong.boolean = !itself and some.reallyLong.int = itself * itself - 1.

1 Like

... or this piece of complicated logic can be extracted into a function that takes LHS inout. As a nice side-effect, you'd get a meaningful name for the operation.

func doubleAndIncrement(_ x: inout Int) {
  x = x * x + 1
}

or if you want to get hacky :)

_ = { $0 = $0 * $0 + 1}(&some.reallyLong.int)

2 Likes

That said though I do like the idea, however, I think the with statement would minimize this issue while giving even more functionality.

with(&some.reallyLong.int) { $0 = $0 * $0 + 1 }

1 Like

this seems really obscure and not at all clear what the code is doing. itself makes more sense to read

I suppose the two have enough semantic difference to warrant both in the language.

Just define with yourself:

Welcome to Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2). Type :help for assistance.
  1> func with<T>(_ v: inout T, _ f: (inout T)->Void) { f(&v) }
  2> var foo = 3
foo: Int = 3
  3> with(&foo) { $0 = $0 * $0 + 1 }
  4> foo
$R0: Int = 10

Or if for some reason you want with to be able to return values:

Welcome to Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2). Type :help for assistance.
  1> func with<T,R>(_ v: inout T, _ f: (inout T)->R)->R { return f(&v) }
  2> var foo = 3
foo: Int = 3
  3> func plusplus(_ a: inout Int) -> Int { defer {a = a+1}; return a}
  4> with(&foo, plusplus)
$R0: Int = 3
  5> foo
$R1: Int = 4
  6> with(&foo, plusplus) 
$R2: Int = 4
  7> foo 
$R3: Int = 5

I was actually referring to supporting this proposal over this. But I do suppose now the two are different enough to both be included.

Yes, with seems more appropriate for modifying instance members directly while itself would be used for applying operations or methods returning the same type (like sorted). Certainly possible with with, but less clear. In fact I think with would be better off being non-inout.

FWIW check this thread.

This thread kind of died... any further interest from anyone?

swift-evolution/0199-bool-toggle.md at master · apple/swift-evolution · GitHub should mostly address your needs.

For other cases, I think it might be a better idea to define a custom function.

That was indeed the inspiration for this idea but being able to refer to the LHS on the RHS in any expression is useful in many other contexts, and is much cleaner than writing a one-off function. Some examples:

someReallyLongIntVar = (itself - 1) * (itself - 1)
someReallyLongStringVar = itself.uppercased()
someReallyLongSequenceVar = itself.filter(func)

Not only are these easier to write, they're (significantly!) easier to read because you don't need to mentally parse the long variable name twice. For comparison:

someReallyLongIntVar = (someReallyLongIntVar - 1) * (someReallyLongIntVar - 1)
someReallyLongStringVar = someReallyLongStringVar.uppercased()
someReallyLongSequenceVar = someReallyLongSequenceVar.filter(func)

Essentially, itself provides a very ergonomic way to fill gaps in the language where the mutating version of a non-mutating function doesn't exist.

As @Justin_Jia said, defining a function may be a better fit.

There are some pitches going around for a with function that addresses some of the same issues, but I see that @DevAndArtist already pointed this out. You can already do some of that yourself:

func with<T>(_ x: inout T, _ f: (inout T) -> ()) { f(&x) }

var longVariableName = 42
with(&longVariableName) {
  $0 = ($0 - 1) * ($0 - 1)
}

In general, new syntactic sugar is of the lowest priority in Swift's evolution; unless there is something truly astounding made possible, pitching a new keyword seems unlikely to meet with much success.

1 Like

Just a warning. I don‘t remember if the pure function is bugged but a custom inout operator definetelly is bugged in Swift 4.1. I‘ll update this post when I‘ll be back at my workstation with a link to a bug-issue. There is a compiler bug related to inout which appears on a release build because of some aggressive optimizations and basically will crash your whole application.