Failing to understand the Delegate

I am trying to wrap my head around how to properly use the Delegate type from within Silver / Fire. After reading the documentation and a few forum threads, I thought I had a basic understanding. But I am receiving four Type mismatch errors when evaluating between a Delegate as a function parameter and casting Callback typealias.

The exact error messages from the compiler are below:

E: Type mismatch, cannot find operator to evaluate “Delegate!” + “Callback” [/Users/lorenalexm/Projects/Square Surge/Logic/Events.swift (84)]
E: Type mismatch, cannot find operator to evaluate “Delegate!” - “Callback” [/Users/lorenalexm/Projects/Square Surge/Logic/Events.swift (91)]
E: Type mismatch, cannot find operator to evaluate “Delegate!” + “Callback” [/Users/lorenalexm/Projects/Square Surge/Logic/Events.swift (117)]
E: Type mismatch, cannot find operator to evaluate “Delegate!” - “Callback” [/Users/lorenalexm/Projects/Square Surge/Logic/Events.swift (124)]

These errors are raised when attempting to add or remove a handler function to the Delegate.

My understanding was the following public typealias Callback = () → () would be evaluated as a Delegate type. This does not seem to be the case? Might someone be able to lend a thought towards what I am missing? Thank you!

I have attached the complete source file below if it would be helpful. This is an attempt to bring a C# utility I use over to Swift.

// MARK: Placeholder, replace with real types
public enum EventType {
    case notSet
}

// MARK: Delegate type aliases
public typealias Callback = () -> ()
public typealias Callback = (arg: T) -> ()

// MARK: Event exceptions
public class HandlerException: Exception {
    /// Constructor to forward message to base Exception class
    /// - parameter message: The message to be thrown with the exception
    init(_ message: String) {
        super.init(message)
    }
}

public class BroadcastException: Exception {
    /// Constructor to forward message to base Exception class
    /// - parameter message: The message to be thrown with the exception
    init(_ message: String) {
        super.init(message)
    }
}

static internal class EventsManager {
    // MARK: Fields
    static var eventTable: [EventType:Delegate] = [:]

    // MARK: Class functions
    /// Adds event KVP to the table if not already present
    /// - parameter type: Key for the event
    /// - parameter handler: Delegate response for the event
    static func onAdding(_ type: EventType, handler: Delegate) {
        if eventTable.keys.contains(type) == false {
            _ = eventTable.updateValue(handler, forKey: type)
        }
        
        var delegate: Delegate = eventTable[type]
        if delegate != nil && delegate.GetType() != handler.GetType() {
            throw HandlerException("Attempting to add handler with inconsistent signatures for event type \(type).")
        }
    }
    
    /// Removes event KVP from table if delegate is no longer assigned
    /// - parameter type: Key for the event
    /// - parameter handler: Delegate response for the event
    static func onRemoved(_ type: EventType, handler: Delegate) {
        var delegate: Delegate? = eventTable[type]
        if delegate == nil {
            _ = eventTable.removeValue(forKey: type)
        }
    }
    
    /// Checks if the KVP exists within the table, throws a BroadcastException if not
    /// - parameter type: Key for the event
    static func onBroadcasting(type: EventType) {
        if eventTable.keys.contains(type) == false {
            throw BroadcastException("Broadcasting event \(type), but no listeners are found.")
        }
    }
    
    /// Creates a new BroadcastException for signature mismatches
    /// - parameter type: The EventType the broadcast was sent with
    static public func signatureExceptionFor(_ type: EventType) -> BroadcastException {
        BroadcastException("Broadcasting event \(type) but listeners have a different signature than the broadcaster.")
    }
}

static public class Events {
    // MARK: Fields
    static private var eventTable: [EventType:Delegate] = EventsManager.eventTable

    //MARK: Class functions
    /// Adds the Callback handler to the event table
    /// - parameter type: Event to which the handler will be added
    /// - parameter handler: Handler to be called when event is received
    public static func addHandler(type: EventType, handler: Callback) {
        EventsManager.onAdding(type, handler: handler)
        eventTable[type] += handler
    }
    
    /// Removes the Callback handler from the event table
    /// - parameter type: Event from which the handler will be removed
    /// - parameter handler: Handler to be called when event is received
    public static func removeHandler(type: EventType, handler: Callback) {
        eventTable[type] -= handler
        EventsManager.onRemoved(type, handler: handler)
    }
    
    /// Broadcasts an event to all handlers
    /// - parameter type: Event to broadcast
    public static func broadcast(type: EventType) {
        let callback: Callback = eventTable[type] as! Callback
        if callback != nil {
            callback()
        } else {
            throw EventsManager.signatureExceptionFor(type)
        }
    }
}

static public class Events {
    // MARK: Fields
    static private var eventTable: [EventType:Delegate] = EventsManager.eventTable

    // MARK: Class functions
    /// Adds the Callback handler to the event table
    /// - parameter type: Event to which the handler will be added
    /// - parameter handler: Handler to be called when event is received
    public static func addHandler(type: EventType, handler: Callback) {
        EventsManager.onAdding(type, handler: handler)
        eventTable[type] += handler
    }
    
    /// Removes the Callback handler from the event table
    /// - parameter type: Event from which the handler will be removed
    /// - parameter handler: Handler to be called when event is received
    public static func removeHandler(type: EventType, handler: Callback) {
        eventTable[type] -= handler
        EventsManager.onRemoved(type, handler: handler)
    }
    
    /// Broadcasts an event to all handlers
    /// - parameter type: Event to broadcast
    /// - parameter argument: Argument to be passed along with the event
    public static func broadcast(type: EventType, argument: T) {
        let callback: Callback = eventTable[type] as! Callback
        if callback != nil {
            callback(argument)
        } else {
            throw EventsManager.signatureExceptionFor(type)
        }
    }
}

What platform is this?

Alexander,.

you are declaring two types with the same name, his is that supposed to work?

public typealias Callback = () -> ()
public typealias Callback = (arg: T) -> ()

granted, it should err on this (will log), but it’s not surprising that there’s confusion when hosing the type…

Thanks, logged as bugs://85757

I am using Fire as the Editor and Silver as the platform.

The types of the same name are a carryover from the C# utility. It seemed logical at the time as they are all used for the callback events and passing types through them. Renaming them might be better for clarity though.

That being said, the error does not seem to stem from using the same names with the typealias. If I remove the Events class that accepts the generic type leaving only the basic Events class, I am still receiving the typemismatch error.

It seems that the forum has removed the generics from the snippet posted. I have created a gist with the code for better readability.

Silver is the language — what’s the platform? .NET, Cocoa? native Mac, etc?

I will check…

My apologies, I misunderstood the question! The platform is .NET standard.

1 Like
    static var eventTable: [EventType:Delegate] = [:]

vs

	public static func addHandler(type: EventType, handler: Callback) {
		EventsManager.onAdding(type, handler: handler)
		eventTable[type] += handler // E64 Type mismatch, cannot find operator to evaluate "Delegate!" + "Callback"

handler is of type “Callback” but eventTable is of type Delegate — not the same thing; Delegate is the abstract base type for all delegates and should not be used directly.

changing the dictionary to match:

    static var eventTable: [EventType:Callback] = [:]

will fix the issue.

my tweaked project as it compiles:

ConsoleApplication52 2.bugreport.zip (55.4 KB)

2 Likes

Thank you! I am getting the same thing. The only issue now is with the Events classes accepting the generic types. I can always refactor each of these into their own standalone class and ditch EventsManager class.

I am glad to see that I was on the right track to implementing things. I also greatly appreciate your assistance and speed with this matter @mh!

1 Like

any time!

yeah that’ll be tricky, as you’re somewhat mixing generics with at-runtime Type info “Type”, which aren’t really meant to go well together…

bugs://85757 got closed with status fixed.