How to get a protocol's name in its extensions

I have hard-coded the protocol names in the print statements below.

protocol Foo {
}

extension Foo {
    func go () {
        print (type (of:self), "Foo", #function)
    }
}

protocol Bar: Foo {
}

extension Bar {
    func go() {
        print (type (of:self), "Bar", #function)

        func _super (self:some Foo) {
            print (type (of:self), "Bar", #function)
            self.go()
        }

        _super(self: self)
    }
}

struct Clever: Bar {
    
}

Is there a way to get the name of a protocol, analogous to #function or type (of:self), so that I don't have to hard-code them?

1 Like

You can use Swift Runtime to do so

// Module A
protocol P {
    func hello()
}

@_silgen_name("swift_getTypeName")
@inline(__always)
private func _getTypeName(_ type: Any.Type, qualified: Bool)
  -> (UnsafePointer<UInt8>, Int)

print(String(cString: _getTypeName(P.self, qualified: true).0)) 
// Print A.P

print(String(cString: _getTypeName(P.self, qualified: false).0))
// Print P

Here is my Library's usage https://github.com/Kyle-Ye/OpenSwiftUI/blob/f02d16bef286f8698371d4bd71f308f6e67a6a73/Sources/OpenSwiftUI/Other/ProtocolDescriptor.swift#L1-L8

Update:

Swift Standard Library actually already shipped it as an underscore API.

You can also just use it directly

import Swift // Implicitly added for all Swift file

print(_typeName(P.self)) // A.P
print(_typeName(P.self, qualified: false)) // P

Relative Code is here

1 Like

Thank you, @Kyle-Ye, but the protocol name is still hard-coded in the examples.

I am beginning to think that this, getting the name of a protocol in its extensions, is currently not possible. It would be really nice if we had something like #protocol analogous to #function.

1 Like

Seems like a perfect fit for a user-defined expression macro!

The standard library contains the following set of macros:

macro function<T>() -> T

Produces the name of the declaration in which it appears.

macro file<T>() -> T

Produces the path to the file in which it appears.

macro fileID<T>() -> T

Produces a unique identifier for the source file in which the macro appears.

macro filePath<T>() -> T

Produces the complete path to the file in which the macro appears.

macro line<T>() -> T

Produces the line number on which it appears.

macro column<T>() -> T

Produces the column number in which the macro begins.

I wish it had one more:

macro type<T>() -> T

Produces the name of the type in which the macro appears or the name of the protocol in an extension of which the macro appears.

I wonder why this particular one is missing.

1 Like