-2

I'm trying to achieve something similar to--but not quite the same as--the Codable/CodableKeys protocols that Swift4 uses.

Given the following code:

protocol Handler{}
protocol HandlerValues{}

class SomeClass : Handler{

    enum MyEnum : String, HandlerValues{
        case first
        case second
    }
}

class SomeOtherClass : Handler{

    enum MyEnum : String, HandlerValues{
        case third
        case fourth
        case fifth
    }
}

The following statements are guaranteed to be true:

  1. A class that implements Handler, must specify an enum that implements HandlerValues, or an error will be thrown.

  2. That enum's name will always be MyEnum (in this example)

  3. Any enum that implements HandlerValues will always be defined within a Handler class. (similar to CodableKeys being defined within a Codable. Technically this can't be enforced, but if it's defined anywhere else, it's simply ignored.)

What I'm trying to do is one of two things:

  1. Inside a function that takes a HandlerValue as an argument, infer it's containing class, or...
  2. Inside a function that takes a Handler as an argument, to be able to enumerate its HandlerValues (like how implementations that take a Codable know how to iterate over its CodableKeys enum.)

For the first, my thought is to use String(reflecting:), split on '.', lop off the last component, reassemble/join to a string, then get the type based on it. It's three-lefts-to-go-right, but it would get me there.

In the second case, I'm trying to define Handler in such a way to guarantee it will have a HandlerValues enum that can be enumerated (again, like Codable knows it will have a CodableKeys enum. I just don't know how Codable defines that.)

I tried this, but of course this doesn't work...

protocol HandlerValues{}
protocol Handler{
    enum MyEnum : HandlerValues
}

Update

This seems to be getting me closer...

protocol HandlerValues : RawRepresentable{}
protocol Handler{
    associatedtype MyEnum : HandlerValues
}

...but I still don't know how to achieve #2 above (i.e. given a Handler instance, how can you enumerate the values of its MyEnum or how do you even guarantee MyEnum is an enum in the first place?)

So how can that information be obtained?

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • You have to refer to `MyClass` explicitly – Alexander Dec 13 '17 at 01:39
  • That defeats the entire point of the question. You should be able to get type information from `someValue`. I'm trying to figure out how to walk the hierarchy. – Mark A. Donohoe Dec 13 '17 at 01:41
  • 2
    Swift doesn't expose any relationship between a nested type and its container. What are you actually trying to accomplish? – Dave Weston Dec 13 '17 at 01:47
  • 1
    Apart from the namespacing effect that nesting types has, `MyClass` and `MyClass.MyEnum` are completely unrelated types. – Alexander Dec 13 '17 at 01:48
  • Of course they are separate types, but MyClass is a type and MyEnum is a nested type, ergo you can't define MyEnum without also specifying MyClass as part of its name. Where do you think 'MyClass.MyEnum' comes from? Put another way, when you call String(describing:) with MyEnum, you just get 'MyEnum'. But when you call String(reflecting:) with it, you get 'MyClass.MyEnum'. Internally it has to know what the hierarchy is in order to build that path up. That's what I'm after. – Mark A. Donohoe Dec 13 '17 at 01:50
  • A current API we're using accepts two parameters... a type of a class, then a value from an enumeration defined within it that inherits a specific protocol. The problem is two-fold: One, nothing stops you from passing in the type of one class, then a value from another class's enumeration so long as it too implements that protocol. Two, specifying the class type twice is redundant. I'm trying to say 'Hey... for the passed-in enum that adheres to this protocol, because it does, I know it's a nested enum, so just get the containing class. Cleans up and simplifies the API and removes errors. – Mark A. Donohoe Dec 13 '17 at 06:16
  • I've cleaned-up, clarified the question. If I could ask you to remove the down-votes I would appreciate it. – Mark A. Donohoe Dec 13 '17 at 06:25
  • @MarqueIV Thanks for clarifying the question; although now it (unless I'm missing something) seems to just boil down to "*how can I enumerate the cases of a given enumeration?*", which seems to be the same question that you're asking in https://stackoverflow.com/q/47784254/2976878, and is a topic that has been discussed before here: https://stackoverflow.com/q/24007461/2976878 (there's also an SE proposal for it here: https://github.com/apple/swift-evolution/pull/114). – Hamish Dec 13 '17 at 13:44
  • I actually already have code that enumerates an enum. The problem is getting at the enum from a type (passed as SomeClass.self), then enumerating that. (I'll update the question more.) It's easy if I know the concrete enum type, but I only know the class its defined on. I've attempted to expose it via a protocol's associated type. I think I'm close, but I'm not quite there yet. – Mark A. Donohoe Dec 13 '17 at 16:14
  • @MarqueIV I would just define a protocol, something like `CaseEnumerable` from the SE proposal, containing a property requirement `static var allCases: [Self] { get }`, and then have `HandlerValues` derive from that protocol. You should then be able to access that on the `MyEnum` associated type. – Hamish Dec 13 '17 at 16:53
  • That's actually the direction I'm already heading down, the same way `Codable` makes its enum implement the `CodableKeys` protocol. I do agree this should be something all enums should support implicitly so I'll also be voting on the proposal for that as well. Thanks again! Took three questions here on SO, but I think I now have all the pieces. Just have to put them together. – Mark A. Donohoe Dec 13 '17 at 17:31

1 Answers1

0

I figured out how to achieve what I'm after. In short, I now have solution approach #2 working in a purely-Swift way.

Here's the link to the answer on my other question.

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286