profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/pcbeard/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.

Ableton/LinkKit 99

iOS SDK for Ableton Link, a new technology that synchronizes musical beat, tempo, and phase across multiple applications running on one or more devices.

pcbeard/Adafruit_nRF8001 0

Drivers for Adafruit's nRF8001 Bluetooth Low Energy Breakout

pcbeard/Adafruit_Trellis_Library 0

Arduino library for controlling Adafruit Trellis

pcbeard/after-dark-css 0

Uses modern CSS techniques to imitate your favorite After Dark screensavers

pcbeard/AudioKit 0

Open-source audio synthesis, processing, & analysis platform.

pcbeard/AutoHotInterception 0

An AutoHotkey wrapper for the Interception driver

pcbeard/BlockServer 0

A minecraft PE server written in java

pcbeard/Checkpoint 0

Fast and simple homebrew save manager for 3DS and Switch.

pcbeard/CocoaAsyncSocket 0

Asynchronous socket networking library for Mac and iOS

pull request commentapple/swift-collections

Add a priority queue implementation built on top of a min-max heap

OK, invariant checks have been added. Anything else we need to address here? (cc/ @kylemacomber)

This is our first big addition to the collections package, so there's not really any existing precedent, but I think it'd be great to do an API review on the collections section of the forums to finalize the names.

I think something similar to the review of the FilePath Syntactic APIs would work well. Nothing too fancy—just a dump of all the public APIs and their doc comments along with a little commentary. We should include at least couple example uses of PriorityQueue (either in the doc comments or the commentary)!

AquaGeek

comment created time in 39 minutes

pull request commentapple/swift-collections

Add a priority queue implementation built on top of a min-max heap

public mutating func insert<S: Sequence>(contentsOf newElements: S) where S.Element == Element

I was trying to figure out if there is a performant way to do this — build a heap out of the new sequence and then merge the two?

I think it's fine to just add the naive loop that calls insert for every element in the sequence to start. Since we don't have to worry about ABI stability, it's trivial to substitute the implementation with a more efficient algorithm in the future.

AquaGeek

comment created time in 3 hours

pull request commentapple/swift-collections

Add a priority queue implementation built on top of a min-max heap

OK, invariant checks have been added. Anything else we need to address here? (cc/ @kylemacomber)

AquaGeek

comment created time in 8 hours

Pull request review commentapple/swift-collections

Add a priority queue implementation built on top of a min-max heap

+//===----------------------------------------------------------------------===//+//+// This source file is part of the Swift Collections open source project+//+// Copyright (c) 2021 Apple Inc. and the Swift project authors+// Licensed under Apache License v2.0 with Runtime Library Exception+//+// See https://swift.org/LICENSE.txt for license information+//+//===----------------------------------------------------------------------===//++import Swift+import Foundation++extension PriorityQueue {+  #if COLLECTIONS_INTERNAL_CHECKS+  @inlinable+  @inline(never)+  // Iterates through all the levels in the heap, ensuring that items in min+  // levels are smaller than all their descendants and items in max levels+  // are larger than all their descendants.+  //+  // The min-max heap indices are structured like this:+  //  min               0+  //  max        1             2+  //  min      3   4         5     6+  //  max     7 8 9 10     11 12 13 14+  //  min    15...+  //  ...+  //+  // The iteration happens in depth-first order, so the descendants of the+  // element at index 0 are checked to ensure they are >= that element. This is+  // repeated for each child of the element at index 0 (inverting the+  // comparison at each level).+  //+  // In the case of 7 elements total (spread across 3 levels), the checking+  // happens in the following order:+  //   compare >= 0: 1, 3, 4, 2, 5, 6+  //   compare <= 1: 3, 4+  //   compare >= 3: (no children)+  //   compare >= 4: (no children)+  //   compare <= 2: 5, 6+  //   compare >= 5: (no children)+  //   compare >= 6: (no children)+  internal func _checkInvariants() {

Since heaps have some invariants that need to be maintained (min-max heaps especially), you could consider adding a method that checks these invariants just for testing purposes. With some of the operations it can be a bit tricky to keep a clear mental model of exactly what's happening.

@timvermeulen Is this what you had in mind?

AquaGeek

comment created time in 8 hours

pull request commentapple/swift-collections

Add a priority queue implementation built on top of a min-max heap

OK, @hassila's "iterative instead of recursive" PR has been merged. I think the only thing left here is to add invariant tests. I was planning on following the approach taken in some of the other data structures:

// PriorityQueue+Invariants.swift
extension PriorityQueue {
  #if COLLECTIONS_INTERNAL_CHECKS
  @inlinable
  @inline(never)
  internal func _checkInvariants() {
    // TODO: Check that the layers in the min-max heap are in the proper order
  }
  #else
  @inlinable
  @inline(__always)
  public func _checkInvariants() {}
  #endif  // COLLECTIONS_INTERNAL_CHECKS
}
AquaGeek

comment created time in 9 hours

Pull request review commentapple/swift-evolution

[DRAFT] Add shared storage for property wrappers

+## Introduction++Property Wrappers have empowered users to abstract common property implementation details into expressive components. This proposal aims to make property wrappers more flexible and efficient by allowing them to opt-in to a shared storage.++## Motivation++Property Wrappers are responsible for wrapping common getting and setting boilerplate and also for storing any auxiliary helper properties. Often, these helpers are constant across different instances of the wrapper, not changing after initialization. Thus, having to store these properties in each individual wrapper instance should be avoided. In the following `Clamped` example, every wrapped instance will store its own `range` — even though there isn't a way for this range to change across different `Hud` initializations.++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {+  private var value: Value+  let range: ClosedRange<Value>+  +  init(wrappedValue: Value, _ range: ClosedRange<Value>) {+    self.value = range.clamping(wrappedValue) +    self.range = range+  }+  +  var wrappedValue: Value {+    get { value }+    set { value = range.clamping(newValue) }+  }+}++struct Hud {+  @Clamped(0...100) var value = 100+}++// the `range` property is constant and has the same value+// on both `hud1` and `hud2` +let hud1 = Hud()+let hud2 = Hud()+```++### API-level property wrappers++Another motivation for this feature is mentioned in the [Static property-wrapper attribute arguments](https://github.com/apple/swift-evolution/blob/main/proposals/0293-extend-property-wrappers-to-function-and-closure-parameters.md#static-property-wrapper-attribute-arguments) Future Direction's section of SE-0293. To achieve consistency across the multiple initialization kinds API-level property wrappers are not allowed to have arguments in their wrapper attribute. ++## Proposed solution++We propose introducing a storage that is shared per property wrapper instance. The storage is immutable, initialized once, and stored outside of the instance scope. It's a tool for property wrapper authors to optimize their wrapper abstractions and avoid repeated unnecessary storage.++```swift+@propertyWrapper+struct Wrapper<Value> {+  shared let storage: SharedStorage+  var wrappedValue: Value { ... }+  +  // a plain struct, with properties that will be shared across wrappers+  struct SharedStorage { ... }+}+```++## Detailed design++The storage is declared using the new `shared` property attribute inside a Property Wrapper declaration. This property will be initialized and stored globally by the compiler, while remaining accessible to the property wrapper instance like any other private property defined in the wrapper type. ++In the next example, the `RangeStorage` struct will be used for the `Clamped` wrapper. ++```swift+struct RangeStorage<Value: Comparable> {+  let range: ClosedRange<Value>+  init(_ range: ClosedRange<Value>) { +    self.range = range+  } +  +  func clamp(_ value: Value) -> Value {}+}++@propertyWrapper+struct Clamped<Value: Comparable> {+  shared let storage: RangeStorage<Value>+  private var value: Value+  +  init(wrappedValue: Value, shared: RangeStorage<Value>) {+    self.value = shared.clamp(wrappedValue)+  }+  +  var wrappedValue: Value {+    get { value }+    set {+      // `storage` is available like any other property+      value = storage.clamp(newValue) +    }+  }+}  +```++And at the point of use, the compiler will make sure `RangeStorage` is initialized once for each wrapper application, and stored at a scope outside of the instances. Later on, when multiple instances of `Hud` are initialized, they'll all be given access to the same `$shared` properties. Suggestions on how to name the `$shared` property would be much appreciated. 🙂++```swift+struct Hud {+  @Clamped(.init(0...14)) var bar = 5+  @Clamped(.init(1...9)) var foo = 1+}++var hud1 = Hud()+var hud2 = Hud()++// desugars to++struct Hud {+  shared let bar$shared = RangeStorage(0...14)+  shared let foo$shared = RangeStorage(1...9)+  +  var bar = Clamped(wrappedValue: 5, shared: bar$shared)+  var foo = Clamped(wrappedValue: 1, shared: foo$shared)+}++// both Hud's get access to the same $shared properties.+var hud1 = Hud() +var hud2 = Hud() +```++### Initialization++Inside the wrapper's initializer, assigning the shared value to the `shared` property is handled by the compiler, so there's not need to explicitly do it. If the initializer itself needs access to storage properties, it should be done through the `shared` parameter. ++```swift+shared let storage: RangeStorage<Value>++init(wrappedValue: Value, shared: RangeStorage<Value>) {+  self.value = shared.clamp(wrappedValue)++  // referencing `storage` inside the initializer is not okay since +  // it might not have been initialized yet?+}+```++At the call site, we can drop the label for the shared argument if there aren't other arguments to be passed (except wrappedValue and projectedValue). ++```swift+// without the label+@Clamped(RangeStorage(1...7)) var weekday: Int = 7++// with a third parameter on the initializer... +init(wrappedValue: Value, shared: RangeStorage<Value>, defaultValue: Value) { }++// ... we bring back the label+@Clamped(shared: RangeStorage(1...7), defaultValue: 1) var weekday: Int = 7+```++Property wrapper authors may also enable passing the values that will be used to initialize the storage instance directly. That can be accomplished by adding a `@shared` attribute on the initializer. ++```swift++struct RangeStorage<Value> {+  init(_ range: ClosedRange<Value>) { ... } +}++/// ...+// using `@shared` instead of `shared`...+init(wrappedValue: Value, @shared: RangeStorage<Value>) {}++// ...+// call site+@Clamped(1...7) var weekday: Int = 3+```++The initialization of the storage value itself follows the same principles as static variables: it can't instance variables or methods that depend on `self` being initialized. Though literals and other type variables can be used. ++```swift+struct RangeStorage {+  init(_ range: String) { ... } +}++struct Container { +  @Clampped(1...7) var weekday = 3+}++// not okay+struct ContainerB {+  var minDay: Int+  var maxDay: Int+  @Clampped(minDay...maxDay) var weekday = 3+}+```++Property wrappers can be initialized in multiple ways (through a `wrappedValue` initializer, a `projectedValue`, or default inits). For property wrappers passed as function arguments, which initializer is called depends on the value that is passed to the function. For those reasons, property wrappers that declare a dependence of a `shared` storage will need to include it on all initializers.++```swift+@propertyWrapper+struct Wrapper<Value> {+  var wrappedValue: Value+  var projectedValue: Wrapper+  shared let storage: SomeStorage+  +  init(wrappedValue: Value, shared storage: SomeStorage) { // }+  +  init(projectedValue: Wrapper, shared storage: SomeStorage) { //	}+  +  init(shared storage: SomeStorage = SomeStorage()) { // }+}++// ...++@Wrapper(SomeStorage()) var value = ""+```++It's important that the initialization of the shared storage is resolved and stored at the call site. So providing a default value on the initializer argument is allowed but initializing it inside the wrapper declaration is not. ++```swift+@propertyWrapper +struct Wrapper {+  // ...+  shared let storage = SomeStorage() // * error+}+```++Since the goal of this feature is to allow instances of the type containing a property wrapped property to share the same storage instance, injecting the shared storage into the `Container` is also a violation. ++```swift+class Container {+  @Wrapper var someProperty: String +  +  // this way instances of `Container` could have different `storage` values +  init(value: String, shared storage: SomeStorage) {+    self._someProperty = Wrapper(wrappedValue: value, shared: storage)  // error+  }+}+```++### Access control++The shared property is accessible anywhere in the `Wrapper` scope, like any other property. However, unlike other generated property wrapper properties, it's not *directly* visible to the container type. It can only be accessed through the backing storage property (unless it was declared private).++```swift+class Container { +  // shared let someProperty$shared = SomeStorage("hi") +  @Wrapper(SomeStorage("hi")) var someProperty = ""+  +  func accessStorage() {+    print(someProperty$shared) // not allowed+    print(_someProperty.storage) // okay+  }+}+```++### Lifecycle++There are a few important aspects about the lifecycle of the shared storage. About its initialization, it happens only once. And then it's reused for subsequent instances that need it. ++```swift+class Container { +  @Wrapper(SomeStorage()) var someProperty = ""+}++let firstContainer = Container() // `shared let someProperty$shared` initialized++// the following `Container` instances use the `someProperty$shared` +let secondContainer = Container()+let anotherContainer = Container()++```++The shared storage can be declared with classes, structs, and enums. Multiple containers will end up using the storage, potentially at the same time, so it should be read-only. Since the storage is immutable and Swift uses copy on write to avoid needlessly copying values, only one instance of the storage will be alive in the memory regardless of how many container instances use it. ++The storage lifecycle is not tied to the "original" instance that caused it to be initialized in the first place. Instead, it follows the rules of other Type properties: it must be given a default value, and it is lazily initialized.++### API-level Property Wrappers on function parameters++Implementing this feature also unlocks the possibility for API-level wrappers to pass arguments to the `shared storage` when passed as function parameters. And unlike the strategy mentioned in the Future Directions section of the SE-0293, using the shared storage won't require accessing wrapped and projected values through subscripts.++```swift+struct Layout {} ++struct SharedStorage { +  let layout: Layout+  +  static func italic() -> Layout {}+} ++@propertyWrapper+struct Style {+  shared let storage: SharedStorage+  var wrappedValue: UIView +  var projectedValue: Style { self }+  +  init(wrappedValue: UIView) {}+  +  init(projectedValue: Style, shared: SharedStorage) { // }  +}++// come up with another example+func emphasized(@Style(.italic()) label: UILabel) {}+```++### Composition of Property Wrappers++When a property declares multiple property wrappers, they get composed and their effects are combined through a composition chain. For wrappers with a shared storage dependency, the same can be applied. ++Take for example the following composition chain, where one of the wrappers has shared storage and the other does not. ++```swift+@WithShared(.init()) @Without var foo: Bool = false+```++The composition chain will be resolved by nesting the inner wrapper into the outer wrapper type and initializing the shared property as needed. The same logic applies for the reversed order of application ( `@Without @WithShared var foo`).++```swift+shared let foo$shared = Shared()+var foo: WithShared<Without<Bool>> = WithShared(wrappedValue: Without(wrappedValue: false), foo$shared)+```++In the case of a property with multiple applications of the same wrapper with shared storage, the composition chain would be resolved in the same way. Each wrapper gets its own shared storage property regardless. ++```swift+@WithShared(.init()) @WithShared(.init()) var foo: Bool = false +```++```swift+shared let baz$shared = Shared()+shared let baz2$shared = Shared()++var baz: WithShared<WithShared<Bool>> = WithShared(wrappedValue: WithShared(wrappedValue: false, baz$shared), baz2$shared)+```++## Impact on existing code++This is an additive feature, and it shouldn't impact existing source code. ++### Backward compatibility++However, from a library evolution standpoint, making an existing property wrapper opt-in into the shared storage model can be a non-resilient change for ABI-public property wrappers. ++Consider a type that exposes a property with a property wrapper to its public API. ++```swift+@propertyWrapper+public struct Wrapper<Value> {+  var wrappedValue: Value { ... }+  var projectedValue: Wrapper { ... } +}++public struct Container {+  @Wrapper public var someValue: String+}++// -------+// the generated interface+public struct Container {+  public var someValue: String +  public var $someValue: Wrapper +}++@propertyWrapper+public struct Wrapper<Value> { ... }+```++Suppose that on a later version, the author of this property wrapper decides to change it by adding shared storage. Even if the shared storage is given a default argument in the property wrapper initializer, this is a non-resilient change. The same would be true for the opposite scenario: removing the shared storage from an ABI-public wrapper.++The example shows an API-level property wrapper, but the same would apply to an ABI-public implementation detail wrapper.  ++### Alternatives considered++**Static shared storage**++Instead of introducing a new attribute, we could store the generated storage property as a normal static variable in its enclosing instance.++```swift+@propertyWrapper(shared: Storage)+struct Clamped {+  private var value: Value+  +  var wrappedValue: Value { fatalError("use the subscript!") }+  +  // wrappedValue would be accessed through a subscript+  subscript(shared storage: Storage) -> Value {+    get { value }+    set { value = storage.range.clamping(newValue) }+  }+  +  struct Storage {+    let range: ClosedRange<Value>+    init(range: ClosedRange<Value>) { // ... } +  }+} ++// .... using it++struct Hud {+  @Clamped(range: 0...100) var value = 100+}++// Desugared version:+struct Hud {+  private var _value: Clamped<Int> = .init(wrappedValue: 100)+  private static let _value$shared: Clamped<Int>.Storage = .init(range: 0...100)+  var value: Int {+    get { _value[shared: Hud._value$shared] }+    set { _value[shared: Hud._value$shared] = newValue }+  }+}+```++Readability is one of the main disadvantages of this approach, as it would require passing the storage around through subscripts. ++### Related Work++The Future Directions sections on both SE-0258 and SE-0293, and the threads discussing this feature, especially this [post](https://www.notion.so/Copy-of-Shared-storage-for-Property-Wrappers-GSoC-Proposal-c6ac301b7e6a401e960a5e2a06adf962), were essential to this proposal.

This notion link looks wrong. Is this supposed to be linking to https://forums.swift.org/t/future-directions-of-property-wrappers/27934 (or this specific comment: https://forums.swift.org/t/future-directions-of-property-wrappers/27934/11) or something else?

iillx

comment created time in 10 hours

Pull request review commentapple/swift-evolution

[DRAFT] Add shared storage for property wrappers

+## Introduction++Property Wrappers have empowered users to abstract common property implementation details into expressive components. This proposal aims to make property wrappers more flexible and efficient by allowing them to opt-in to a shared storage.++## Motivation++Property Wrappers are responsible for wrapping common getting and setting boilerplate and also for storing any auxiliary helper properties. Often, these helpers are constant across different instances of the wrapper, not changing after initialization. Thus, having to store these properties in each individual wrapper instance should be avoided. In the following `Clamped` example, every wrapped instance will store its own `range` — even though there isn't a way for this range to change across different `Hud` initializations.++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {+  private var value: Value+  let range: ClosedRange<Value>+  +  init(wrappedValue: Value, _ range: ClosedRange<Value>) {+    self.value = range.clamping(wrappedValue) +    self.range = range+  }+  +  var wrappedValue: Value {+    get { value }+    set { value = range.clamping(newValue) }+  }+}++struct Hud {+  @Clamped(0...100) var value = 100+}++// the `range` property is constant and has the same value+// on both `hud1` and `hud2` +let hud1 = Hud()+let hud2 = Hud()+```++### API-level property wrappers++Another motivation for this feature is mentioned in the [Static property-wrapper attribute arguments](https://github.com/apple/swift-evolution/blob/main/proposals/0293-extend-property-wrappers-to-function-and-closure-parameters.md#static-property-wrapper-attribute-arguments) Future Direction's section of SE-0293. To achieve consistency across the multiple initialization kinds API-level property wrappers are not allowed to have arguments in their wrapper attribute. ++## Proposed solution++We propose introducing a storage that is shared per property wrapper instance. The storage is immutable, initialized once, and stored outside of the instance scope. It's a tool for property wrapper authors to optimize their wrapper abstractions and avoid repeated unnecessary storage.++```swift+@propertyWrapper+struct Wrapper<Value> {+  shared let storage: SharedStorage+  var wrappedValue: Value { ... }+  +  // a plain struct, with properties that will be shared across wrappers+  struct SharedStorage { ... }+}+```++## Detailed design++The storage is declared using the new `shared` property attribute inside a Property Wrapper declaration. This property will be initialized and stored globally by the compiler, while remaining accessible to the property wrapper instance like any other private property defined in the wrapper type. ++In the next example, the `RangeStorage` struct will be used for the `Clamped` wrapper. ++```swift+struct RangeStorage<Value: Comparable> {+  let range: ClosedRange<Value>+  init(_ range: ClosedRange<Value>) { +    self.range = range+  } +  +  func clamp(_ value: Value) -> Value {}+}++@propertyWrapper+struct Clamped<Value: Comparable> {+  shared let storage: RangeStorage<Value>+  private var value: Value+  +  init(wrappedValue: Value, shared: RangeStorage<Value>) {+    self.value = shared.clamp(wrappedValue)+  }+  +  var wrappedValue: Value {+    get { value }+    set {+      // `storage` is available like any other property+      value = storage.clamp(newValue) +    }+  }+}  +```++And at the point of use, the compiler will make sure `RangeStorage` is initialized once for each wrapper application, and stored at a scope outside of the instances. Later on, when multiple instances of `Hud` are initialized, they'll all be given access to the same `$shared` properties. Suggestions on how to name the `$shared` property would be much appreciated. 🙂++```swift+struct Hud {+  @Clamped(.init(0...14)) var bar = 5+  @Clamped(.init(1...9)) var foo = 1+}++var hud1 = Hud()+var hud2 = Hud()++// desugars to++struct Hud {+  shared let bar$shared = RangeStorage(0...14)+  shared let foo$shared = RangeStorage(1...9)+  +  var bar = Clamped(wrappedValue: 5, shared: bar$shared)+  var foo = Clamped(wrappedValue: 1, shared: foo$shared)+}++// both Hud's get access to the same $shared properties.+var hud1 = Hud() +var hud2 = Hud() +```++### Initialization++Inside the wrapper's initializer, assigning the shared value to the `shared` property is handled by the compiler, so there's not need to explicitly do it. If the initializer itself needs access to storage properties, it should be done through the `shared` parameter. ++```swift+shared let storage: RangeStorage<Value>++init(wrappedValue: Value, shared: RangeStorage<Value>) {+  self.value = shared.clamp(wrappedValue)++  // referencing `storage` inside the initializer is not okay since +  // it might not have been initialized yet?

I agree - accessing the shared property directly is fine here

iillx

comment created time in 10 hours

Pull request review commentapple/swift-evolution

[DRAFT] Add shared storage for property wrappers

+## Introduction++Property Wrappers have empowered users to abstract common property implementation details into expressive components. This proposal aims to make property wrappers more flexible and efficient by allowing them to opt-in to a shared storage.++## Motivation++Property Wrappers are responsible for wrapping common getting and setting boilerplate and also for storing any auxiliary helper properties. Often, these helpers are constant across different instances of the wrapper, not changing after initialization. Thus, having to store these properties in each individual wrapper instance should be avoided. In the following `Clamped` example, every wrapped instance will store its own `range` — even though there isn't a way for this range to change across different `Hud` initializations.++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {+  private var value: Value+  let range: ClosedRange<Value>+  +  init(wrappedValue: Value, _ range: ClosedRange<Value>) {+    self.value = range.clamping(wrappedValue) +    self.range = range+  }+  +  var wrappedValue: Value {+    get { value }+    set { value = range.clamping(newValue) }+  }+}++struct Hud {+  @Clamped(0...100) var value = 100+}++// the `range` property is constant and has the same value+// on both `hud1` and `hud2` +let hud1 = Hud()+let hud2 = Hud()+```++### API-level property wrappers++Another motivation for this feature is mentioned in the [Static property-wrapper attribute arguments](https://github.com/apple/swift-evolution/blob/main/proposals/0293-extend-property-wrappers-to-function-and-closure-parameters.md#static-property-wrapper-attribute-arguments) Future Direction's section of SE-0293. To achieve consistency across the multiple initialization kinds API-level property wrappers are not allowed to have arguments in their wrapper attribute. ++## Proposed solution++We propose introducing a storage that is shared per property wrapper instance. The storage is immutable, initialized once, and stored outside of the instance scope. It's a tool for property wrapper authors to optimize their wrapper abstractions and avoid repeated unnecessary storage.++```swift+@propertyWrapper+struct Wrapper<Value> {+  shared let storage: SharedStorage+  var wrappedValue: Value { ... }+  +  // a plain struct, with properties that will be shared across wrappers+  struct SharedStorage { ... }+}+```++## Detailed design++The storage is declared using the new `shared` property attribute inside a Property Wrapper declaration. This property will be initialized and stored globally by the compiler, while remaining accessible to the property wrapper instance like any other private property defined in the wrapper type. ++In the next example, the `RangeStorage` struct will be used for the `Clamped` wrapper. ++```swift+struct RangeStorage<Value: Comparable> {+  let range: ClosedRange<Value>+  init(_ range: ClosedRange<Value>) { +    self.range = range+  } +  +  func clamp(_ value: Value) -> Value {}+}++@propertyWrapper+struct Clamped<Value: Comparable> {+  shared let storage: RangeStorage<Value>+  private var value: Value+  +  init(wrappedValue: Value, shared: RangeStorage<Value>) {+    self.value = shared.clamp(wrappedValue)+  }+  +  var wrappedValue: Value {+    get { value }+    set {+      // `storage` is available like any other property+      value = storage.clamp(newValue) +    }+  }+}  +```++And at the point of use, the compiler will make sure `RangeStorage` is initialized once for each wrapper application, and stored at a scope outside of the instances. Later on, when multiple instances of `Hud` are initialized, they'll all be given access to the same `$shared` properties. Suggestions on how to name the `$shared` property would be much appreciated. 🙂++```swift+struct Hud {+  @Clamped(.init(0...14)) var bar = 5+  @Clamped(.init(1...9)) var foo = 1+}++var hud1 = Hud()+var hud2 = Hud()++// desugars to++struct Hud {+  shared let bar$shared = RangeStorage(0...14)+  shared let foo$shared = RangeStorage(1...9)+  +  var bar = Clamped(wrappedValue: 5, shared: bar$shared)+  var foo = Clamped(wrappedValue: 1, shared: foo$shared)+}++// both Hud's get access to the same $shared properties.+var hud1 = Hud() +var hud2 = Hud() +```++### Initialization++Inside the wrapper's initializer, assigning the shared value to the `shared` property is handled by the compiler, so there's not need to explicitly do it. If the initializer itself needs access to storage properties, it should be done through the `shared` parameter. ++```swift+shared let storage: RangeStorage<Value>++init(wrappedValue: Value, shared: RangeStorage<Value>) {+  self.value = shared.clamp(wrappedValue)++  // referencing `storage` inside the initializer is not okay since +  // it might not have been initialized yet?

@hborla I think we briefly touched on this but I'm not sure if it would really be a problem to access storage directly. Since it would be initialized already. 🤔

iillx

comment created time in 11 hours

created repositoryPaulStoffregen/MyFault

created time in 16 hours

created tagapple/swift-syntax

tagswift-5.5-DEVELOPMENT-SNAPSHOT-2021-06-23-a

SwiftPM package for SwiftSyntax library.

created time in 21 hours

created tagapple/indexstore-db

tagswift-5.5-DEVELOPMENT-SNAPSHOT-2021-06-23-a

Index database library for use with sourcekit-lsp

created time in 21 hours

created tagapple/swift-stress-tester

tagswift-5.5-DEVELOPMENT-SNAPSHOT-2021-06-23-a

Stress testing utilities for Swift's tooling

created time in 21 hours

created tagapple/swift-integration-tests

tagswift-5.5-DEVELOPMENT-SNAPSHOT-2021-06-23-a

Automated tests for validating the generated Swift snapshots behave correctly

created time in 21 hours

created tagapple/swift-corelibs-libdispatch

tagswift-5.5-DEVELOPMENT-SNAPSHOT-2021-06-23-a

The libdispatch Project, (a.k.a. Grand Central Dispatch), for concurrency on multicore hardware

created time in 21 hours

created tagapple/swift-corelibs-xctest

tagswift-5.5-DEVELOPMENT-SNAPSHOT-2021-06-23-a

The XCTest Project, A Swift core library for providing unit test support

created time in 21 hours

created tagapple/swift-llbuild

tagswift-5.5-DEVELOPMENT-SNAPSHOT-2021-06-23-a

A low-level build system, used by Xcode and the Swift Package Manager

created time in 21 hours

PR closed apple/swift-syntax

Make SyntaxToken extend ExpressibleByStringLiteral

@ahoppen I have open a PR, so we can discuss it here.

From #291

4a. TokenSyntax should be ExpressibleByStringLiteral. That way we wouldn’t need SyntaxFactory.makeIdentifier("myFirstVar"). It might also remove the need for convenience of passing in a String for a TokenSyntax in the convinience initializers because TokenSyntax can now just be expressed by a string literal.

I'm not sure how implement this.

Because if we add ExpressibleByStringLiteral to SyntaxToken, how can it now to create a identifier token, just like when we use SyntaxFactory.makeIdentifier("myOtherVar")

+19 -0

2 comments

1 changed file

kimdv

pr closed time in a day

pull request commentapple/swift-syntax

Make SyntaxToken extend ExpressibleByStringLiteral

Good. I was a bit confused. Maybe I didn't know something.

But will close then.

kimdv

comment created time in a day

pull request commentapple/swift-syntax

Make SyntaxToken extend ExpressibleByStringLiteral

Argh, I temporarily forgot that TokenSyntax nodes carry a kind. My initial idea was that let myToken: TokenSyntax = "hello" should create an identifier with the text hello. But since TokenSyntax carries a type, we need to decide whether myToken should indeed be an identifier or maybe some other token like a contextual keyword. So I take back my idea.

I also just realized that since #293 we can write

IdentifierPattern(identifier: .identifier("myOtherVar")),

instead of

IdentifierPattern(identifier: SyntaxFactory.makeIdentifier("myOtherVar")),

which I think is a very precise and short syntax for what we are trying to achieve.

kimdv

comment created time in a day

pull request commentapple/swift-syntax

Move result builder as last parameters

@swift-ci Please test

kimdv

comment created time in a day

Pull request review commentapple/swift-evolution

[SE-0296] Allow overloads that differ only in async

 This also presents a problem for code evolution, because developers of existing  Instead, we propose an overload-resolution rule to select the appropriate function based on the context of the call. Given a call, overload resolution prefers non-`async` functions within a synchronous context (because such contexts cannot contain a call to an `async` function).  Furthermore, overload resolution prefers `async` functions within an asynchronous context (because such contexts should avoid stepping out of the asynchronous model into blocking APIs). When overload resolution selects an `async` function, that call is still subject to the rule that it must occur within an `await` expression. +The overload-resolution rule depends on the synchronous or asynchronous context, in which the compiler selects one and only one overload. The selection of the async overload requires an `await` expression, as all introductions of a potential suspension point:++```swift+func f() async {+  // In an asynchronous context, the async overload is preferred:+  await doSomething()+  // Compiler error: Expression is 'async' but is not marked with 'await'+  doSomething()+}+```++In non-`async` functions, and closures without any `await` expression, the compiler selects the non-`async` overload:++```

Oops, yes

groue

comment created time in a day

Pull request review commentapple/swift-evolution

[SE-0296] Allow overloads that differ only in async

 This also presents a problem for code evolution, because developers of existing  Instead, we propose an overload-resolution rule to select the appropriate function based on the context of the call. Given a call, overload resolution prefers non-`async` functions within a synchronous context (because such contexts cannot contain a call to an `async` function).  Furthermore, overload resolution prefers `async` functions within an asynchronous context (because such contexts should avoid stepping out of the asynchronous model into blocking APIs). When overload resolution selects an `async` function, that call is still subject to the rule that it must occur within an `await` expression. +The overload-resolution rule depends on the synchronous or asynchronous context, in which the compiler selects one and only one overload. The selection of the async overload requires an `await` expression, as all introductions of a potential suspension point:++```swift+func f() async {+  // In an asynchronous context, the async overload is preferred:+  await doSomething()+  // Compiler error: Expression is 'async' but is not marked with 'await'+  doSomething()+}+```++In non-`async` functions, and closures without any `await` expression, the compiler selects the non-`async` overload:++```

Aha, I see the example 🙃 Would you mind adding in swift after the triple backticks to enable code highlighting?

groue

comment created time in a day

Pull request review commentapple/swift-evolution

[DRAFT] Add shared storage for property wrappers

+## Introduction++Property Wrappers have empowered users to abstract common property implementation details into expressive components. This proposal aims to make property wrappers more flexible and efficient by allowing them to opt-in to a shared storage.++## Motivation++Property Wrappers are responsible for wrapping common getting and setting boilerplate and also for storing any auxiliary helper properties. Often, these helpers are constant across different instances of the wrapper, not changing after initialization. Thus, having to store these properties in each individual wrapper instance should be avoided. In the following `Clamped` example, every wrapped instance will store its own `range` — even though there isn't a way for this range to change across different `Hud` initializations.++```swift+@propertyWrapper+struct Clamped<Value: Comparable> {+  private var value: Value+  let range: ClosedRange<Value>+  +  init(wrappedValue: Value, _ range: ClosedRange<Value>) {+    self.value = range.clamping(wrappedValue) +    self.range = range+  }+  +  var wrappedValue: Value {+    get { value }+    set { value = range.clamping(newValue) }+  }+}++struct Hud {+  @Clamped(0...100) var value = 100+}++// the `range` property is constant and has the same value+// on both `hud1` and `hud2` +let hud1 = Hud()+let hud2 = Hud()+```++### API-level property wrappers++Another motivation for this feature is mentioned in the [Static property-wrapper attribute arguments](https://github.com/apple/swift-evolution/blob/main/proposals/0293-extend-property-wrappers-to-function-and-closure-parameters.md#static-property-wrapper-attribute-arguments) Future Direction's section of SE-0293. To achieve consistency across the multiple initialization kinds API-level property wrappers are not allowed to have arguments in their wrapper attribute. ++## Proposed solution++We propose introducing a storage that is shared per property wrapper instance. The storage is immutable, initialized once, and stored outside of the instance scope. It's a tool for property wrapper authors to optimize their wrapper abstractions and avoid repeated unnecessary storage.++```swift+@propertyWrapper+struct Wrapper<Value> {+  shared let storage: SharedStorage+  var wrappedValue: Value { ... }+  +  // a plain struct, with properties that will be shared across wrappers+  struct SharedStorage { ... }+}+```++## Detailed design++The storage is declared using the new `shared` property attribute inside a Property Wrapper declaration. This property will be initialized and stored globally by the compiler, while remaining accessible to the property wrapper instance like any other private property defined in the wrapper type. ++In the next example, the `RangeStorage` struct will be used for the `Clamped` wrapper. ++```swift+struct RangeStorage<Value: Comparable> {+  let range: ClosedRange<Value>+  init(_ range: ClosedRange<Value>) { +    self.range = range+  } +  +  func clamp(_ value: Value) -> Value {}+}++@propertyWrapper+struct Clamped<Value: Comparable> {+  shared let storage: RangeStorage<Value>+  private var value: Value+  +  init(wrappedValue: Value, shared: RangeStorage<Value>) {+    self.value = shared.clamp(wrappedValue)+  }+  +  var wrappedValue: Value {+    get { value }+    set {+      // `storage` is available like any other property+      value = storage.clamp(newValue) +    }+  }+}  +```++And at the point of use, the compiler will make sure `RangeStorage` is initialized once for each wrapper application, and stored at a scope outside of the instances. Later on, when multiple instances of `Hud` are initialized, they'll all be given access to the same `$shared` properties. Suggestions on how to name the `$shared` property would be much appreciated. 🙂++```swift+struct Hud {+  @Clamped(.init(0...14)) var bar = 5+  @Clamped(.init(1...9)) var foo = 1+}++var hud1 = Hud()+var hud2 = Hud()++// desugars to++struct Hud {+  shared let bar$shared = RangeStorage(0...14)+  shared let foo$shared = RangeStorage(1...9)+  +  var bar = Clamped(wrappedValue: 5, shared: bar$shared)+  var foo = Clamped(wrappedValue: 1, shared: foo$shared)+}++// both Hud's get access to the same $shared properties.+var hud1 = Hud() +var hud2 = Hud() +```++### Initialization++Inside the wrapper's initializer, assigning the shared value to the `shared` property is handled by the compiler, so there's not need to explicitly do it. If the initializer itself needs access to storage properties, it should be done through the `shared` parameter. ++```swift+shared let storage: RangeStorage<Value>++init(wrappedValue: Value, shared: RangeStorage<Value>) {+  self.value = shared.clamp(wrappedValue)++  // referencing `storage` inside the initializer is not okay since +  // it might not have been initialized yet?+}+```++At the call site, we can drop the label for the shared argument if there aren't other arguments to be passed (except wrappedValue and projectedValue). ++```swift+// without the label+@Clamped(RangeStorage(1...7)) var weekday: Int = 7++// with a third parameter on the initializer... +init(wrappedValue: Value, shared: RangeStorage<Value>, defaultValue: Value) { }++// ... we bring back the label+@Clamped(shared: RangeStorage(1...7), defaultValue: 1) var weekday: Int = 7+```++Property wrapper authors may also enable passing the values that will be used to initialize the storage instance directly. That can be accomplished by adding a `@shared` attribute on the initializer. ++```swift++struct RangeStorage<Value> {+  init(_ range: ClosedRange<Value>) { ... } +}++/// ...+// using `@shared` instead of `shared`...+init(wrappedValue: Value, @shared: RangeStorage<Value>) {}++// ...+// call site+@Clamped(1...7) var weekday: Int = 3+```++The initialization of the storage value itself follows the same principles as static variables: it can't instance variables or methods that depend on `self` being initialized. Though literals and other type variables can be used. ++```swift+struct RangeStorage {+  init(_ range: String) { ... } +}++struct Container { +  @Clampped(1...7) var weekday = 3+}++// not okay+struct ContainerB {+  var minDay: Int+  var maxDay: Int+  @Clampped(minDay...maxDay3) var weekday = 3+}+```++As mentioned before, the compiler will enforce that the shared property initialization only happens once. For that reason, the `shared` property is required to be initialized from a `shared` parameter. 

We briefly discussed this, but I think it makes more sense to not require the line self.storage = storage, because it enforces the model that the shared storage is already initialized. What we need to do instead is figure out a way to "match up" the shared parameter with the shared storage, but I think it's better to have new syntax or a new rule for that instead of writing it in a way that looks like stored property initialization.

iillx

comment created time in a day

pull request commentapple/swift-evolution

Incorporate feedback from 3nd review of SE-0292

@tomerd Just pushed one last change to update the link to Registry.md (from https://github.com/apple/swift-package-manager/pull/3541/commits/8185efee6b0542fe58bbcb5b34128a6c0185ec66). I don't have any other changes on my end. Anything else you'd like in here ahead of merging this?

mattt

comment created time in a day

pull request commentapple/swift-evolution

SE-0258: property wrappers, revise the Atomic example.

@DougGregor I should revise this PR. Rather than merge it as-is, we should remove the Atomic example completely. It isn't needed to justify the feature and it's harmful as guidance to any programmer looking to implement atomics. I should explain why the Atomic wrapper was removed in the revisions section for people who come here looking for it and point to the swift-atomics package instead.

atrick

comment created time in a day

MemberEvent

pull request commentapple/swift-collections

Add a priority queue implementation built on top of a min-max heap

Found out that the nice benchmark framework could do a better diff:

> swift-collections-benchmark results compare bench-recursive bench-iterative
Tasks with difference scores larger than 1.05:
  Score   Sum     Improvements Regressions  Name
  1.221   1.221   1.221(#76)   1.000(#0)    PriorityQueue<Int> popMin (*)
  1.201   1.201   1.201(#76)   1.000(#0)    PriorityQueue<Int> popMax (*)
  1.146   1.146   1.146(#76)   1.000(#0)    PriorityQueue<Int> insert (*)
  1.105   1.105   1.105(#76)   1.000(#0)    PriorityQueue<Int> init from range (*)

AquaGeek

comment created time in 2 days