How do you get labeled associated values from Mirror children?

Every schoolchild knows that you Cannot create a single-element tuple with an element label.

But this returns (label: ()).Type. How do we cast that?!

( Mirror(
    reflecting: Enum.labeled( label: () )
  ).children.first?.value
).map(Mirror.init)?.subjectType

You can dig into that with another mirror. Can that be avoided?

enum Enum {
  case unlabeled(Void)
  case tuple(label0: Void, label1: Void)
  case labeled(label: Void)

  func getAssociatedValue<AssociatedValue>(_: AssociatedValue.Type) -> AssociatedValue? {
    Mirror(reflecting: self).children.first?.value as? AssociatedValue
  }
}

Enum.unlabeled( () ).getAssociatedValue(Void.self)  // ()
Enum.tuple( label0: (), label1: () ).getAssociatedValue( (Void, Void).self ) // ((), ())
Enum.labeled( label: () ).getAssociatedValue(Void.self) // nil
2 Likes

Ah, Mirror is giving us a value of a type that is not meant to exist in Swift, thus we cannot cast it from Any to its actual / runtime type (a labeled single element tuple).

enum E {
  case foo(bar: Int)
}

let e: E = .foo(bar: 123)

let m = Mirror(reflecting: e)
let v = m.children.first!.value
print(v)            // (bar: 123)  <--. This value and its type is
print(type(of: v))  // (bar: Int)  <--' not meant to exist in Swift!

So this is a bug.
But how should it be fixed?

Should labeled associated values of one element be represented without their label while the ones of two or more elements keep their labels?

1 Like

I see that you've put a lot of good thought into this! Roadmap for and state of single element tuple types?

I'd be fine with this as is, as long as it could be cast to not have the label, the same as other tuples.

I'm not sure what you mean. You'd be fine with keeping the bug as is, as long as another bug is introduced (the ability to cast a non-existing type to an existing type)?

I bet you actually are sure what I mean, and you just don't agree with me. :stuck_out_tongue_closed_eyes:

It doesn't matter if we can't use the type, if we can cast it to something we can use. It's the same as throwing out argument labels when you store a function as a closure.

As I said in the other thread, I hate that we don't have single-element labeled tuples across the board, but I'm happy that they're in there somewhere. It shows that they're useful and will inspire somebody to fix the situation someday.

1 Like

No, I wasn't actually sure what you meant, thanks for clarifying.


I simply think that if single element tuples are banned (as they currently are), they shouldn't be in the language.


OK, yes I agree that single element tuples (labeled and unlabeled) should be allowed. Banning them is just an exception that causes confusion (and creates unfortunate situations like the one in the OP).

Allowing them doesn't seem totally impossible:


Since tuples are not the only things in Swift which happen to be written using parentheses, I guess unlabeled single element tuples would have to be written as eg:

let foo = (_: 123)
print(type(of: foo)) // (_: Int)

or

let foo = (123,)
print(type(of: foo)) // (Int,)