Is it possible to expand which protocols can act as types?

If we have a protocol without any associated types nor any Self requirements, then we can declare a variable of that protocol to act as a multi-type box/pointer for any conforming type. Having either at least one associated type or one Self-marked member disqualifies conforming types from using such boxes.

But, if there was a way to specify a protocol and 100% of its associated types, and the protocol does not have Self requirements, shouldn't we be able to create protocol boxes the same way?

For instance, here's a try at a Swift-y regex:

public protocol PatternMatcher {
    associatedtype Element

    func matchingPrefix<C: Collection>(for collection: C) -> C.Index?
        where C.Element == Element
}

Obviously, I can't create a PatternMatcher existential to hold any conforming type, especially if the Element can change between assignments. But I should be able to make PatternMatcher<where Element == Character> boxes. Otherwise, I currently have no alternative besides ripping out Element and locking it to Character, preventing the generalization of regex matching to any element type.

Here's some older threads that were suggested to me, that I feel may actually be applicable:

1 Like

This was just asked four days ago:

What @kozlow described in that thread (and @jarod did in the older thread) are in the same category as what I want. But I don't want to introduce a new protocol and corresponding name; I want the facility available directly.

That older thread eventually referenced a not-quite-as-old thread by @Joe_Groff about adding a broader form of the idea. However, it drifted towards the existential box types for protocols with Self or associated type constraints to have those members that express those constraints be suppressed. (Those members can be activated indirectly through Stupid Generic Tricks.) But that is the exact opposite of what I want; I want the protocol's full API available.

Let's call protocols with Self or associated type constraints "PAT"s. Right now, only non-PAT protocols can have existential instances of them declared and used as variables. My desire is that what I call "fully specified PATs" can also be used as a type of an existential instance. It would be the name of the protocol followed by a where clause of constraints. But the where clause is protected by the angle brackets ("<>") used for conventional generics. The boundaries for which PAT-restrained protocols can be turned into fully specified PATs are:

  • If the protocol has Self requirements, the only ones allowed are read-only properties of type Self and methods with a return type of Self. Using Self in a function parameter type or in an indirect way in a return type prevents the protocol from being used as a fully specified PAT.
  • Every associated type that does not have a default must be specified in the where clause. (You are allowed to specify associated types that do have a default if you want to override them.) It can be either a type equality or a base-class and/or protocol constraint. Equality specifications always work towards building a fully specified PAT, but not all class/protocol constraints are compatible; subsequent rules will mention when class/protocol constraints cannot be used.
  • (A protocol used in a class/protocol constraint can be either a non-PAT or fully specified PAT.)
  • An associated type that is left as a default is OK only if either it doesn't depend on the explicit types (directly or indirectly) or if the finalized type is the same for a given set of explicit types. This usually means that all explicit types that touch the defaulted types have to use equality constraints and not class/protocol ones. If a default associated type depends on an also-defaulted sibling associated type, then that dependency has to be resolved first.
  • An associated type that uses a class/protocol constraint (instead of an equality constraint) can only appear in members the same way Self can (i.e. read-only property or direct method return).

Hopefully this narrower use case will be easier to implement instead of full-blown generalized existentials or somewhat-generalized existentials but the PAT parts uselessly suppressed. One of the older posts did mention a pull request that could be used, but the author wants to do it over, and I don't know if s/he did.

Terms of Service

Privacy Policy

Cookie Policy