Supporting Extensions for Structural Types

Aside the problem you have mentioned which I also dislike and wish we had Type<T> type for one part of the metatypes, you can workaround your issue:

var someData = [AnyHashable: String]()
someData[ObjectIdentifier(Int.self)] = "integer"

Thanks @Fryie! I agree with you. In this case, it would be great if someone could answer the following couple questions:

  1. What is it that makes extending tuples hard right now? Why are tuples not represented as structs?
  2. What would it take to add support for this feature, without worrying about variadic generics for now? Are there some good starting points about where to look and what needs to change?

In struct R<T...>, there is no single type “T”, so the func bar(_: T...) must take all the generic types “T...”. There is no meaning to “a variadic argument list of just type T”, because there is no type T.

I don’t know what (if any) syntax there will be for enumerating the individual types within T..., but if we use a strawman of indexing into T then you might be able to write, eg:

func bar(_: T[0]...)

(Which would presumably crash at runtime if T... is empty.)

Requiring that multiple generic parameters be the same is…not really desirable. Your struct B only has one generic parameter, so it should not use variadic generics at all. If it needs a generic multiplicity parameter as well, then I recommend heading over to the Generics Vector Manifesto thread.

Quite interesting idea you have here. Just thinking out loud my thoughts that something similar could be used on types to express a fixed length of variadic parameters. struct Tuple<T[1...]> or struct W<T[2 ..< 6]> (a range expression to statically define the minimum and maximum bound of parameters).

You meant Vector not Generics.

1 Like

I don't know if things have changed in the he intervening year and a half, but back in Nov of 2017 @John_McCall made a couple of posts that partially answers your questions. They're both from the same thread so the forum software names them the same, but these two links really are different :slight_smile:

  1. Synthesizing Equatable, Hashable, and Comparable for tuple types
  2. Synthesizing Equatable, Hashable, and Comparable for tuple types

Assuming nothing has changed WRT this in the past year and a half, the notable quote relevant to this thread is, "I think it would be difficult to allow useful user-defined extensions/conformances of arbitrary tuple types without variadic generics". I'd love to know if he (or anyone else who's sufficiently familiar with the compiler) thinks this is still the case.

IIRC @Douglas_Gregor is (or at least was at one point) the generics guy, so maybe he has thoughts on the matter as well.

Nothing has changed (or will change) about that assessment: any mechanism that makes it possible to do non-trivial user-defined extensions of arbitrary tuples is essentially providing some sort of variadic generics.

1 Like

Do you think it would be worthwhile at some point to have the compiler and runtime provide special-case support making tuples equatable and hashable but nothing user-defined?

6 Likes

If this was feasible it would be pretty awesome to have. I have a custom Unit type for the sole reason that Void is not Equatable and Hashable and would love to ditch it.

1 Like

i suspect Hashable and Equatable form 95% of the use cases for this feature, and tuple-based vector libraries make up the other 5%

1 Like

One truly horrible workaround would be an untyped AnyTuple wrapper type that conforms to Hashable and contains a tuple, implementing equality and hashing via reflection on the underlying tuple value.

1 Like

Yes, I think it would be useful to provide special-case conformances for tuple equatability and hashability. We could certainly just generate them magically in the runtime, although I think we'd almost certainly want to also allow devirt/specialization/inlining at the SIL level.

9 Likes

Codable would also be nice, but I'm not sure if that could work for Tuples with unnamed elements.

2 Likes

Don’t forget metatypes, please! :)

Metatypes aren’t structural types. Static members on the underlying type are actually instance members on the metatype so you can extend them today, you just can’t conform them to protocols. I have some notes on a related pitch / manifesto I plan to present when I have a chance. The design I have in mind would allow metatypes (and existentials) to conform to protocols.

4 Likes

If this manifesto of yours supports extension of metatypes, then I really think now will be the best time to present it. So by the time or before Swift 6.0 is out, extension of metatypes are implemented.

I’ll try to post something in the next month or two, but that won’t determine whether anything makes it into Swift 6 or not. That requires implementation and I won’t be able to do that. But it’s always possible somebody will be interested in collaborating as an implementer.

Correct me if I'm wrong, but isn't this mostly a problem because of the "arbitrary tuples" requirement? I mean, isn't it reasonable to say that if you use a 25 element tuple you're probably doing something wrong? Seems to me that even just being able to add protocol conformances to fixed size tuples would be a massive improvement, even if it does potentially mean that there is some code duplication. To some extent that kind of code duplication can also be mitigated by using something like sourcery.

Yes, it would be comparatively easy to allow extensions on just pairs or triples, although doing that in the short term might interfere with a variadic extension that provided the same conformances in the long term.

5 Likes

On the prefix vs postfix argument to represent variatic tuples, how about:

(T, ...)

Are you suggesting that for heterogeneous or homogeneous tuples?