Skip to content

Conversation

@ChrisBenua
Copy link

@ChrisBenua ChrisBenua commented Feb 1, 2026

Description

This PR fixes FIXME for getting type and module name. String(reflecting: type) eventually calls _typeName(_:qualified: true).

Motivation

_typeName(_:qualified: true) is far more efficient. And also is more robust and suitable to retrieve module and type name.

Verification

CompilerPluginTests passed locally.
Same optimization/replacement was made here: swiftlang/swift#77369.

Checklist

  • I have read the Contributing Guide.
  • I have processed the feedback of the Swift Syntax team (if applicable).
  • I have added a test case that demonstrates the issue and verified the fix. (there are already plenty of tests, so I've just run them to verify my changes)

@grynspan
Copy link
Contributor

grynspan commented Feb 2, 2026

Can you define "far more efficient"? Have you measured the performance difference? Do you have any metrics to share?

@ChrisBenua
Copy link
Author

ChrisBenua commented Feb 3, 2026

Can you define "far more efficient"? Have you measured the performance difference? Do you have any metrics to share?

@grynspan Hi Jonathan! Shortly, String(describing:) and String(reflecting:) perform costly operations - protocol conformance checks n OutputStream.swift: CustomDebugStringConvertible, CustomStringConvertible, TextOutputStreamable and CustomReflectable inside Mirror initializer. First conformance check for each pair of (class, protocol) is time-consuming because we need to scan all protocol conformance type descriptors. In our app we have more than 200k protocol conformance descriptors, so each String(reflecting: type) has 800k iterations overhead compared to _typeName(:qualified:) function.

While profiling our app using Xcode Instruments Time Profiler we've discovered that each String(describing:)/String(reflecting:) call has duration about 6-7 ms on iPhone 13. Measurements for different apps may vary because performance of protocol conformance check is dependent on amount of protocol conformance descriptors.

But internally, String(reflecting:) called on class-type eventually calls _typeName(:qualified:) function with qualified: true.

So using _typeName function is more appropriate and efficient.

Here is detailed explanation

@grynspan
Copy link
Contributor

grynspan commented Feb 3, 2026

It sounds like the correct fix may be to short-circuit metatype checks, as they cannot conform to Swift protocols, rather than advising teams (within the Swift project and outside it) to adopt unstable and unsupported functions. 🙂 @mikeash is that something that could be optimized?

@ChrisBenua
Copy link
Author

It sounds like the correct fix may be to short-circuit metatype checks, as they cannot conform to Swift protocols, rather than advising teams (within the Swift project and outside it) to adopt unstable and unsupported functions.

The only possible solution I can come up with is introducing new overloads for String(describing/reflecting:) with Any.Type parameter

@grynspan
Copy link
Contributor

grynspan commented Feb 3, 2026

The standard library could check if value is Any.Type before any protocol conformance checking. That check is very fast.

@ChrisBenua
Copy link
Author

The standard library could check if value is Any.Type before any protocol conformance checking. That check is very fast.

This will cause code duplication between print_unlocked and adHoc_print_unlocked function? Or I didn't quite get your perspective on that

@grynspan
Copy link
Contributor

grynspan commented Feb 3, 2026

The point is that this problem can be resolved inside the Swift stdlib and/or runtime rather than needing to be applied ad hoc to a variety of projects. A fix in Swift itself would benefit all these projects simultaneously.

It might even benefit you in other ways if a fix can be implemented inside the runtime because it could apply to all conformance checks, not just those around stringification.

The exact details of the fix aren't really the salient point. I don't anticipate a significant increase in code size in Swift here regardless of how the fix is implemented.

@ChrisBenua
Copy link
Author

ChrisBenua commented Feb 3, 2026

adopt unstable and unsupported functions.

I don't quite get why this function is unstable or unsupported?

It is public and moreover it is inlined into client code inside DefaultStringInterpolation by @_alwaysEmitIntoClient

In my opinion, this is more appropriate function to use. As for me _typeName function seems for semantically correct that String(describing:)

@grynspan
Copy link
Contributor

grynspan commented Feb 3, 2026

Symbols in the Swift standard library whose names start with underscores are, de jure unstable and unsupported. That's why their names start with underscores.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants