Variadic functions (and CustomStringConvertible)

(Marko Havu) #1

The following piece of code brings up a couple of bugs in CustomStringConvertible protocol and variadic functions (not necessarily connected to each other):

public enum LogLevel: Int, CustomStringConvertible {
    case debug
    case info
    case warning
    case error
    case fatal
    
    public var description: String {  // Method hides a method in parent class
        var description: String
        switch self {
        case .debug:
            description = "[DEBUG]"
        case .info:
            description = "[INFO]"
        case .warning:
            description = "[WARNING]"
        case .error:
            description = "[ERROR]"
        case .fatal:
            description = "[FATAL]"
        }
        return description
    }
}

public final class Logger {
    public static let shared = Logger()
    
    private init() {}
    
    public func log(_ message: String, level: LogLevel = .info, _ args: Any...) {
        let levelString = String(describing: level)  // EXC_BAD_ACCESS
        print("\(levelString) \(message) \(args)")
    }
}

Logger.shared.log("Testing logging")
Logger.shared.log("Testing logging", level: .error)  // No matching overload
Logger.shared.log("Testing logging", level: .error, "param")

Logger.shared.log("Testing logging", level: .error) works if the level argument does not have a default value, but combining default values and variadic parameters should be allowed in Swift.

The CustomStringConvertible bug also seems to affect enum constructor init(rawValue:): it doesn’t work for enums that define description.

(Marko Havu) #2

Can anyone verify whether this happens on platforms other than Cocoa?

(RemObjects) #3

Thanks, logged as bugs://81979

(Carlo Kok) #4

The overload error is fixed; working on the exception now.

(RemObjects) #5

bugs://81979 got closed with status fixed.

(Carlo Kok) #6

Oke so the actual bug is fixed; except for a limitation on Toffee itself where:

let levelString = String(describing: level)

Will result in <boxed struct value>. We’re working on that limitation but that’s quite a bit more involved. It will compile and result in the right code now though (and not throw an exception anymore).

(Marko Havu) #7

I can confirm the above code works in Fire 10.0.0.2377, but there’s still something funny about CustomStringConvertible enums:

public enum ErrorCode: UInt8, CustomStringConvertible {
    case ok = 0
    case failed
    case checksum
    
    public var description: String {  // W: Method hides a method in parent class
        var description: String
        switch self {
            case .ok:
                description = "Command received and executed successfully"
            case .failed:
                description = "Failed to execute command"
            case .checksum:
                description = "Wrong checksum"
        }
        return description
    }
}
let status1 = ErrorCode.checksum
print(status1.rawValue)  // E: No such member
let status2 = ErrorCode(rawValue: 0)  // E: No matching overload
print(status2)

If you remove CustomStringConvertible, the code compiles just fine.

(RemObjects) #8

Thanks, logged as bugs://82067

(RemObjects) #9

bugs://82067 got closed with status fixed.