How to determine if it is an Optional?

In a function I receive an Equatable. I want to log this. Some of what I receive is Optionals, some is not.

If I use String(describing: value) to format it is formatted like Optional(27) and I want that unwrapped to be just "27".

Any ideas on how to do this?

You can't directly check if a value is Optional, but you can do it via an intermediate protocol. I use this approach:

protocol _Optional {
    var value: Any? { get }
}

extension Optional: _Optional {
    var value: Any? {
        return self
    }
}

let anyValue: Any = ... // might be an optional
if let optionalValue = anyValue as? _Optional {
    // it's an optional
    if let value = optionalValue.value {
        // it's non-nil
        print(value)
    } else {
        print("nil")
    }
} else {
    print(anyValue)
}

Thank you! That did it.

This is almost exactly what I already did with one minor detail: "Any".

I had this:

protocol OptionalMarkerProtocol {
    var orNil: String { get }
}

extension Optional: OptionalMarkerProtocol {
    var orNil : String {
        if self == nil {
            return "nil"
        }
        if "\(Wrapped.self)" == "String" {
            return "\"\(self!)\""
        }
        return "\(self!)"
    }
}

// (value is Equatable)
let svalue: String
if let optionalValue = value as? OptionalMarkerProtocol {
    svalue = optionalValue.orNil
} else {
    svalue = String(describing: value)
}

The real annoying thing is that "my" code works fine in debug build but not in release build.

Weird. I can't immediately see any reason why what you've written wouldn't work in release mode.

I'd suggest if self is String instead of if "\(Wrapped.self)" == "String" though, as the latter seems a bit fragile (e.g. if the value was an NSString that test would fail).

You might also want to consider using guard let or some other more traditional way of unwrapping the self value inside orNil to avoid all those force unwraps.

Ah yes. Very good suggestions. Much more sane and readable code with those changes.

It is really weird with this difference between release and debug builds. It is easily reproducable with a Xcode project with almost only the above code.

Can you open a bug with an example that can be compiled and run that demonstrates the difference in behavior between unoptimized and optimized builds?

Sure: https://bugs.swift.org/browse/SR-7722