Is there a way to constrain generic placeholder has to be value type?

Is there a way to constrain the generic placeholder to be a value type?

struct Box<T> {
    var value: T
}

how can I constrain T to be a value type?

1 Like

There’s no “negation of AnyObject” requirement because the distinction isn’t useful. Any reference type can become a “value type”:

struct Wrapper {
  var wrapped: SomeClass
}

What you’re probably thinking of is a value semantics guarantee that would be able to rule out the above for example, but that’s not something that a type system like Swift’s can describe.

4 Likes

I know the situation above. but in some cases, I still want to restrict to the value types.

Whenever I think "I really only want __ to be used with value types", I try and think about what I'm hoping to achieve with that restriction. This makes me realize that what I actually want is Sendable or BitwiseCopyable or Hashable, i.e. some quality that I've come to associate with value types and not literally value types. To be clear, I'm not saying these are truly equivalent or that this association actually makes sense, e.g., reference types can be Sendable and Hashable but not BitwiseCopyable while every value type need not have those qualities.

Assuming you could constrain to value types:

extension Box where T: ValueType {
  // What special thing can I do?
}
4 Likes

The concept of value semantics is a tricky one. There have been some legendary discussions about it here on the forums, for example ValueSemantic protocol.

When thinking about this I try to keep in mind:

  • NSUUID, which is an reference type, but is always immutable [1] and thus has value semantics.

  • File descriptors, commonly modelled as CInt, which are value types but do have reference semantics.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

[1] Well, if you ignore subclasses, but subclassing NSUUID would be bananas.

5 Likes

I wouldn't say that. Value semantics is a property of types, not of individual values, so a CInt that represents a file descriptor can't be evaluated differently from one that represents a counter. A CInt variable has a value that's independent of any other variable in the system, which means it has value semantics. Independence means that if it can be mutated (and it can), that mutation cannot change the value of any other variable in the system—notwithstanding the fact that you can use it to access shared mutable state in the filesystem. The filesystem itself has reference semantics, if you like, because it can be read and mutated from everywhere in the code. You can think of it as a synchronized global variable (that can be randomly updated from outside the process!)

This paper seems to have gained traction as establishing the meaning of "value semantics" more formally.

5 Likes