79597607

Date: 2025-04-29 04:37:17
Score: 1
Natty:
Report link

I completely see what you’re running into.

Even though Plugin: AnyObject, when you refer to any Plugin, it's treated as an existential — and existentials in Swift are not class types, even if the protocol they come from is AnyObject.
That's why ObjectHashable<T: AnyObject> refuses to accept any Plugin as T — because any Plugin isn't itself a class, even if implementations of Plugin must be.

Why any Plugin is a Problem

any Plugin is a value type representing "any instance conforming to Plugin."

It doesn't guarantee that it's a class instance at the type level in a way generic constraints can check.

Swift treats any Plugin differently than concrete types that conform to Plugin.

So... how to solve your situation?

Here's the trick: Instead of writing ObjectHashable<any Plugin>,
you need ObjectHashable<some Plugin> at usage sites,
or redesign ObjectHashable slightly to accept existential values.

A Clean Solution for Your Case

Change ObjectHashable to accept any AnyObject (even any Plugin existentials).

Here's a slightly updated version of ObjectHashable:

public struct ObjectHashable: Hashable {
    public let object: AnyObject

    public init(_ object: AnyObject) {
        self.object = object
    }

    public static func ==(lhs: Self, rhs: Self) -> Bool {
        return ObjectIdentifier(lhs.object) == ObjectIdentifier(rhs.object)
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(ObjectIdentifier(object))
    }
}

Now you don't need to worry about generics.
You can store any class object — including any Plugin — wrapped properly.

Usage:


var dict: [ObjectHashable: String] = [:]
let pluginInstance: any Plugin = SomePlugin()
dict[ObjectHashable(pluginInstance)] = "some value"

But you asked for strictness (not too open like AnyObject)...

If you still want it to be restricted only to Plugin (not any class), here's how you can do it more strictly:

public struct PluginHashable: Hashable {
    public let plugin: any Plugin

    public init(_ plugin: any Plugin) {
        self.plugin = plugin
    }

    public static func ==(lhs: Self, rhs: Self) -> Bool {
        return ObjectIdentifier(lhs.plugin as AnyObject) == ObjectIdentifier(rhs.plugin as AnyObject)
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(ObjectIdentifier(plugin as AnyObject))
    }
}

- This ensures you can only wrap any Plugin, not any AnyObject.
- And you still hash based on the object identity.

Usage:

var pluginDict: [PluginHashable: String] = [:]
let p1: any Plugin = MyPlugin()
let p2: any Plugin = MyOtherPlugin()
pluginDict[PluginHashable(p1)] = "First Plugin"
pluginDict[PluginHashable(p2)] = "Second Plugin"

Why can't you use ObjectHashable<Plugin>?

Because ObjectHashable<T: AnyObject> expects a class type T,
but any Plugin is not a class type — it’s an existential value.

You have to either:

I hope this helps. Let me know if your issue is solved.

Reasons:
  • Blacklisted phrase (1): how to solve
  • Whitelisted phrase (-1): hope this helps
  • RegEx Blacklisted phrase (1.5): how to solve your situation?
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Low reputation (0.5):
Posted by: Ebillson GRAND JEAN