Disallowing weak struct properties


(Jordan Rose) #1

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you—and (AFAICT) would make all values trivially movable, which is a great quality to have.

This wouldn't change local variables, top-level variables, or class properties, just structs. It would make having an array of weak references a little harder, but honestly we should have proper weak-supporting collections anyway; as I understand it the behavior you usually want is auto-compacting rather than leaving a hole. (Evidence: Cocoa has NSHashTable for weak sets and NSMapTable for dictionaries with weak keys and/or values; there's no variant of NSArray that supports weak references other than by making a custom CFArray and being very very careful how you access it.)

Anyway, thoughts? It's not really my department but it cleans up the same areas that are being affected by struct resilience.
Jordan

P.S. I know this would have to go through swift-evolution for real. I just want to know if it's a silly idea to begin with.


(Austin Zheng) #2

+1, and +1 to first-class weak-supporting sets and hash tables.

Austin

···

On Fri, Jan 29, 2016 at 5:56 PM, Jordan Rose via swift-dev < swift-dev@swift.org> wrote:

Hi, everyone. What do you think about dropping support for 'weak' in
struct properties? This would fix a semantic issue—'let' structs containing
weak properties won't change out from under you—and (AFAICT) would make all
values trivially movable, which is a great quality to have.

This wouldn't change local variables, top-level variables, or class
properties, just structs. It *would* make having an array of weak
references a little harder, but honestly we should have proper
weak-supporting collections anyway; as I understand it the behavior you
usually want is auto-compacting rather than leaving a hole. (Evidence:
Cocoa has NSHashTable for weak sets and NSMapTable for dictionaries with
weak keys and/or values; there's no variant of NSArray that supports weak
references other than by making a custom CFArray and being very very
careful how you access it.)

Anyway, thoughts? It's not really my department but it cleans up the same
areas that are being affected by struct resilience.
Jordan

P.S. I know this would have to go through swift-evolution for real. I just
want to know if it's a silly idea to begin with.

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev


(John McCall) #3

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you

Is there a formalizable notion of “change” here that doesn’t include changes in mutable referents and that isn’t just restating bit-equivalence?

—and (AFAICT) would make all values trivially movable, which is a great quality to have.

If you sweep “unowned" up with “weak”, yes, this is true of the current language. It’s not an obvious restriction that we want to adopt forever, though.

John.

···

On Jan 29, 2016, at 5:56 PM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:


(David Sweeris) #4

I'm against it, unless structs can have "WeakCollectionType" properties (which seems like it'd necessarily involve some of that compiler magic we're trying to avoid).

If reference/value semantics weren't tied to struct/class, I'd care a lot less.

I also wouldn't object to removing them from structs, but then adding a "strass" object classification for when you need weak inside a value-semantics object.

-Dave Sweeris

···

Sent from my iPhone

On Jan 29, 2016, at 17:56, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you—and (AFAICT) would make all values trivially movable, which is a great quality to have.

This wouldn't change local variables, top-level variables, or class properties, just structs. It would make having an array of weak references a little harder, but honestly we should have proper weak-supporting collections anyway; as I understand it the behavior you usually want is auto-compacting rather than leaving a hole. (Evidence: Cocoa has NSHashTable for weak sets and NSMapTable for dictionaries with weak keys and/or values; there's no variant of NSArray that supports weak references other than by making a custom CFArray and being very very careful how you access it.)

Anyway, thoughts? It's not really my department but it cleans up the same areas that are being affected by struct resilience.
Jordan

P.S. I know this would have to go through swift-evolution for real. I just want to know if it's a silly idea to begin with.
_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev


(Paul Cantrell) #5

Well, this would certainly pour some cold water on Siesta. It might be able to get by with what you describe, but it’s hard to say without a more specific proposal on the weak-supporting collections. (Without such collections, this would be something of a disaster for the library.)

On the one hand, almost all the weak properties in the whole project occur in structs.

On the other hand, those structs are all meant to support weak collections of various kinds.

On the other other hand, the behavior is more complex than what you outlined above:

there’s StrongOrWeakRef struct used by a cache that needs to be able to switch specific references from strong to weak (at which point auto-compaction of the weak ones would be desirable), and
a WeakRef that hangs on to referent’s ObjectIdentifier’s hash and identity, so that it can be a stable dictionary key.

The second I imagine a dictionary with first-class support for weak keys would probably cover. The first seems pretty purpose-specific, however, and it’s less clear that general-purpose weak collections would cover it.

The StrongOrWeakRef usage suggests, I think, that weak collections may not quite be one size fits all, and having the ability to wrap a weak ref in a struct without incurring an additional allocation may be worth the trouble. At the very least, they’d need some serious thought.

You can see the relevant bits of the code in question here:

https://github.com/bustoutsolutions/siesta/blob/e29a5967e7c7e223377107ff2bdc53180f0d2951/Source/Support/ARC%2BSiesta.swift

Cheers,

Paul

···

On Jan 29, 2016, at 7:56 PM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you—and (AFAICT) would make all values trivially movable, which is a great quality to have.

… It would make having an array of weak references a little harder, but honestly we should have proper weak-supporting collections anyway; as I understand it the behavior you usually want is auto-compacting rather than leaving a hole. …


(Joe Groff) #6

I brought this up internally last year, and we decided to keep the current behavior. Weak references are atomically managed by the compiler and runtime, so code should always see all copies of a weak reference in immutable values go to nil simultaneously. You effectively get the semantics of a weak var stored in a box, but without the box. In resilient cases, I don't think we want to make assumptions that opaque types are trivially movable irrespective of weak references, since that would severely limit our future ability to interop with C++ value types in the future, so I don't see any benefit to introducing this constraint.

-Joe

···

On Jan 29, 2016, at 5:56 PM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you—and (AFAICT) would make all values trivially movable, which is a great quality to have.

This wouldn't change local variables, top-level variables, or class properties, just structs. It would make having an array of weak references a little harder, but honestly we should have proper weak-supporting collections anyway; as I understand it the behavior you usually want is auto-compacting rather than leaving a hole. (Evidence: Cocoa has NSHashTable for weak sets and NSMapTable for dictionaries with weak keys and/or values; there's no variant of NSArray that supports weak references other than by making a custom CFArray and being very very careful how you access it.)

Anyway, thoughts? It's not really my department but it cleans up the same areas that are being affected by struct resilience.


(Jordan Rose) #7

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you

Is there a formalizable notion of “change” here that doesn’t include changes in mutable referents and that isn’t just restating bit-equivalence?

If you treat the "value" of a reference as its referent's identity rather than contents, then the "value" of a struct is fully captured by the "values" of its members (which happens to be bitwise equality). The struct value has no identity.

The particular benefit we'd get here is that existential boxes could be passed in registers, but Slava pointed out that we could just force values containing weak references to be stored out of line even if they'd otherwise fit in the box.

—and (AFAICT) would make all values trivially movable, which is a great quality to have.

If you sweep “unowned" up with “weak”, yes, this is true of the current language. It’s not an obvious restriction that we want to adopt forever, though.

I thought unowned was ref-counted (and therefore forwardable) as well, or are we dropping that implementation because we couldn't get it to work with objc?

Jordan

···

On Jan 29, 2016, at 18:22 , John McCall <rjmccall@apple.com> wrote:

On Jan 29, 2016, at 5:56 PM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:


(Jordan Rose) #8

The workaround would be boxing the weak reference in a final class, which isn't particularly efficient (or small!) but would be equivalent.

private final class WeakBox<T: AnyObject> {
  weak var ref: T?
  init(ref: T?) { self.ref = ref }
}

class Foo { … }

struct FooUser {
  private var box: WeakBox<Foo>
  init(ref: Foo?) { self.box = WeakBox(ref) }
  var ref: Foo? {
    get { return box.ref }
    set {
      // Don't mutate the existing box, which may be shared with other FooUser instances
      box = WeakBox(newValue)
    }
  }
}

We could also just make this the implementation of weak-in-structs (possibly with coalescing of multiple weak variables, possibly not), which would get us the optimization properties even if it doesn't fix what I see as a semantic hole. To me, though, weak properties in structs are semantically wrong because they're never actually constant. (Unowned ones, on the other hand, are just checked non-owning references, which means they don't mutate if your program is correct.)

Jordan

···

On Jan 29, 2016, at 19:24 , David Sweeris <davesweeris@mac.com> wrote:

I'm against it, unless structs can have "WeakCollectionType" properties (which seems like it'd necessarily involve some of that compiler magic we're trying to avoid).

If reference/value semantics weren't tied to struct/class, I'd care a lot less.

I also wouldn't object to removing them from structs, but then adding a "strass" object classification for when you need weak inside a value-semantics object.

-Dave Sweeris

Sent from my iPhone

On Jan 29, 2016, at 17:56, Jordan Rose via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you—and (AFAICT) would make all values trivially movable, which is a great quality to have.

This wouldn't change local variables, top-level variables, or class properties, just structs. It would make having an array of weak references a little harder, but honestly we should have proper weak-supporting collections anyway; as I understand it the behavior you usually want is auto-compacting rather than leaving a hole. (Evidence: Cocoa has NSHashTable for weak sets and NSMapTable for dictionaries with weak keys and/or values; there's no variant of NSArray that supports weak references other than by making a custom CFArray and being very very careful how you access it.)

Anyway, thoughts? It's not really my department but it cleans up the same areas that are being affected by struct resilience.
Jordan

P.S. I know this would have to go through swift-evolution for real. I just want to know if it's a silly idea to begin with.
_______________________________________________
swift-dev mailing list
swift-dev@swift.org <mailto:swift-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-dev


(John McCall) #9

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you

Is there a formalizable notion of “change” here that doesn’t include changes in mutable referents and that isn’t just restating bit-equivalence?

If you treat the "value" of a reference as its referent's identity rather than contents, then the "value" of a struct is fully captured by the "values" of its members (which happens to be bitwise equality). The struct value has no identity.

This is true of weak references as well: the value is the same independent of where it is stored. However, the value *is* dependent on global state.

The particular benefit we'd get here is that existential boxes could be passed in registers, but Slava pointed out that we could just force values containing weak references to be stored out of line even if they'd otherwise fit in the box.

Yes.

—and (AFAICT) would make all values trivially movable, which is a great quality to have.

If you sweep “unowned" up with “weak”, yes, this is true of the current language. It’s not an obvious restriction that we want to adopt forever, though.

I thought unowned was ref-counted (and therefore forwardable) as well, or are we dropping that implementation because we couldn't get it to work with objc?

Unowned references to pure-Swift classes are ref-counted. Unowned references to unrestricted classes have to be (well, “have to be”) address-only for ObjC interop reasons; I fixed that sometime in December.

John.

···

On Jan 29, 2016, at 6:31 PM, Jordan Rose <jordan_rose@apple.com> wrote:

On Jan 29, 2016, at 18:22 , John McCall <rjmccall@apple.com> wrote:

On Jan 29, 2016, at 5:56 PM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:


(Paul Cantrell) #10

Your WeakBox-backed property is more or less how I imagine the semantics of a weak var in a struct — but in the Siesta example elsewhere on this thread, the allocation overhead if it were actually implemented this way would be pretty painful.

P

···

On Jan 29, 2016, at 9:33 PM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

The workaround would be boxing the weak reference in a final class, which isn't particularly efficient (or small!) but would be equivalent.

private final class WeakBox<T: AnyObject> {
  weak var ref: T?
  init(ref: T?) { self.ref = ref }
}

class Foo { … }

struct FooUser {
  private var box: WeakBox<Foo>
  init(ref: Foo?) { self.box = WeakBox(ref) }
  var ref: Foo? {
    get { return box.ref }
    set {
      // Don't mutate the existing box, which may be shared with other FooUser instances
      box = WeakBox(newValue)
    }
  }
}

We could also just make this the implementation of weak-in-structs (possibly with coalescing of multiple weak variables, possibly not), which would get us the optimization properties even if it doesn't fix what I see as a semantic hole. To me, though, weak properties in structs are semantically wrong because they're never actually constant. (Unowned ones, on the other hand, are just checked non-owning references, which means they don't mutate if your program is correct.)

Jordan

On Jan 29, 2016, at 19:24 , David Sweeris <davesweeris@mac.com <mailto:davesweeris@mac.com>> wrote:

I'm against it, unless structs can have "WeakCollectionType" properties (which seems like it'd necessarily involve some of that compiler magic we're trying to avoid).

If reference/value semantics weren't tied to struct/class, I'd care a lot less.

I also wouldn't object to removing them from structs, but then adding a "strass" object classification for when you need weak inside a value-semantics object.

-Dave Sweeris

Sent from my iPhone

On Jan 29, 2016, at 17:56, Jordan Rose via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

Hi, everyone. What do you think about dropping support for 'weak' in struct properties? This would fix a semantic issue—'let' structs containing weak properties won't change out from under you—and (AFAICT) would make all values trivially movable, which is a great quality to have.

This wouldn't change local variables, top-level variables, or class properties, just structs. It would make having an array of weak references a little harder, but honestly we should have proper weak-supporting collections anyway; as I understand it the behavior you usually want is auto-compacting rather than leaving a hole. (Evidence: Cocoa has NSHashTable for weak sets and NSMapTable for dictionaries with weak keys and/or values; there's no variant of NSArray that supports weak references other than by making a custom CFArray and being very very careful how you access it.)

Anyway, thoughts? It's not really my department but it cleans up the same areas that are being affected by struct resilience.
Jordan

P.S. I know this would have to go through swift-evolution for real. I just want to know if it's a silly idea to begin with.
_______________________________________________
swift-dev mailing list
swift-dev@swift.org <mailto:swift-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-dev

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev