What is "@_eagerMove"?

Hello, I'm Kobe, studying iOS and Swift in South Korea.

It's very cold here in Korea as it's winter.

I'm curious about the weather in the regions where all of you in the forum are located. :)

The thing I'm curious about this time is about @_eagerMove.

While examining the internal implementation of Array, I couldn't figure out what @_eagerMove is, so I'm seeking your help.

I sincerely thank everyone who always responds kindly.

@frozen
@_eagerMove
public struct Array<Element>: _DestructorSafeContainer {
  #if _runtime(_ObjC)
  @usableFromInline
  internal typealias _Buffer = _ArrayBuffer<Element>
  #else
  @usableFromInline
  internal typealias _Buffer = _ContiguousArrayBuffer<Element>
  #endif

  @usableFromInline
  internal var _buffer: _Buffer

  /// Initialization from an existing buffer does not have "array.init"
  /// semantics because the caller may retain an alias to buffer.
  @inlinable
  internal init(_buffer: _Buffer) {
    self._buffer = _buffer
  }
}
2 Likes

Maybe this document will help: swift/docs/ReferenceGuides/UnderscoredAttributes.md at f6dba90cf2b3b646de748b0fc4fbfbd1f65cb0a3 · apple/swift · GitHub

4 Likes

I sincerely thank you for your response.

Thanks to you, I have gained yet another significant piece of knowledge.

I always come to the Swift forum and leave with valuable information.

I am deeply grateful to you, Michel, for taking your precious time to answer my questions.

I pray that your day is filled with happiness.

Wishing you a joyful day.

4 Likes

The documentation is right, but doesn't cover the motivation.

The @_eagerMove attribute means the compiler will destroy variables of that type immediately after their last use, even if that means a weak reference or unsafe pointer gets invalidated:

  func takeArray(_ refs: consuming [Ref]) { ... }

  let arrayOfRefs = [Ref()]
  weak var weakRef = arrayOfRefs[0]
  takeArray(arrayOfRefs) // destroyed at last use
  print(weakRef!)  // crash

Destroying a variable consumes its value ("eagerConsume" would have been a better name). If the value contained any references, this decrements their reference counts.

@_eagerMove is applied to copy-on-write data types: Array, Set, Dictionary, and String.

The main reason for this is practical: failing to optimize away unnecessary instances of a CoW value has dramatic performance implications in which all the collection's elements are unexpectedly copied. In real-world situations, it's almost never possible for the compiler to tell whether weak references or unsafe pointers exist, so relying on conservative analysis is ineffective and unpredictable. Futhermore, we would like to optimize away creation of these containers if they are never used.

The language justification for performing this optimization in important cases is that, formally, Swift and Objective-C (with ARC) have always allowed references to be destroyed after their last use.

The usability rationale for this is that CoW data types have value semantics in Swift. They don't have programer-visible deinitializers. And, in general, programers can't predict when the storage will be freed. It is, of course, possible that the elements of the CoW data type themselves to have deinitializers. And, as shown above, weak references to the elements may exist. This places some burden on programers who want to use a CoW data type to keep its elements alive, without actually requiring the elements to be accessed via the CoW container (a fairly bizarre situation). To do so, the lifetime of the CoW container would need to be explicitly tied to a scope:

  func takeArray(_ refs: consuming [Ref]) { ... }

  let arrayOfRefs = [Ref()]
  weak var weakRef = arrayOfRefs[0]
  defer { withExtendedLifetime(arrayOfRefs) {} }
  takeArray(arrayOfRefs) // copy the array by incrementing its storage refcount
  print(weakRef!)  // correct
16 Likes

Hello Andrew,

This is Kobe. I've thoroughly read your response and feel like my world of knowledge has greatly expanded. It's like receiving an early Christmas gift.

Although we haven't met in person, it's amazing and remarkable that we can connect and communicate through just a single question and answer.

I'm truly grateful to know you, Andrew. Your thoughtful and considerate response deeply resonated with me.

I sincerely thank you for the time you spent writing this answer for me.

Connecting with kind-hearted people through Swift and iOS makes me feel like the happiest person in the world.

Thank you once again for your response, and I wish you a happy remainder of 2023.

With sincerity from Korea,

Kobe.

2 Likes