Allow custom nested `Type` and `Protocol` types

Here's a quick pitch. If someone would like spin off a formal proposal and possibly implement it, feel free to take over.

Similarly how we allow certain parts of our language to re-use language reserved keywords by surrounding them with back-ticks:

enum E {
  case `default`
}

we should permit the usage of custom nested types named Type when its also surrounded by back-ticks.

struct S {
  struct `Type` {
    init() {}
  }
}

// before: error - Type 'S.Type' has no member 'init'
// after: okay
S.`Type`.init()

This should also apply to the todays reserved singleton metatype namespace Protocol.

protocol P {}
extension P {
  typealias `Protocol` = S.`Type`
}

P.`Protocol`.init()
3 Likes

Sure, this is consistent, but what use case do you have in mind for this?

I would like to use the Type as a nested nominal types where the term type fits better than kind for example.

1 Like

Evidently, but my question is: what use case do you have in mind for a nested nominal type named Type?

From the top of my head I could imagine having something like this:

protocol Interface {
  var type: `Type` { get }
}

enum InterfaceType {
  case …
}

extension Interface {
  typealias `Type` = InterfaceType
}

This example isn‘t perfect as nesting inside protocols is a different topic, so as a workaround I had to use a typealias here.

If I still missed to answer your question, could you please re-phrase it?

Is this an actual use case that you have?

1 Like

I do not have a concrete use case at my hands, as I just tried if this wasn‘t already a feature and found out that it‘s not. I can try to look up our code base later and search for .Kind types which I probably used because the .Type namespace was taken by the language.

6 Likes

In our code base we have at least 30+ nested enum Kind types. In some cases the term is okay, but I still would probably have used Type instead.

Can you share some examples?

extension Firmware {
  public struct Version: Hashable, Comparable {
    public enum Kind: Hashable {
      case release
      case beta(UInt)
    }
  }
}

public struct Permission: Equatable {
  public enum Kind {
    case notSupported
    case readOnly
    case readWrite
  }
}

extension Transition.Context {
  public enum Kind { 
    case push
    case pop
  }
}

// etc.

Nothing truly groundbreaking.


Well it might be that this pitch is doomed as I kinda proposed to introduce the ability to shadow over metatype namespaces.

Counter example would be the fact that back ticks cannot overload:

enum Foo {
  case a
  case `a` // error - Invalid redeclaration of 'a'
}
struct `Foo` {} // error - Invalid redeclaration of 'Foo'
2 Likes

It seems what's suggested already works in Swift 5. For example, I managed to get the following to compile using Xcode 13.1:

class GameObjectNode {
    enum `Type`: String, Codable {
        case ship
        case player
        case asteroid
        case spaceStation
    }
    
    class var metatype: GameObjectNode.`Type`? {
        return nil
    }
}

In such context you're shadowing the .Type namespace, I think this is why it works there. Try using the type from a standalone function, it will likely fail the expectation.