Skip to content

XCTUnimplemented -> unimplemented #1530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 19, 2022
Merged

XCTUnimplemented -> unimplemented #1530

merged 1 commit into from
Oct 19, 2022

Conversation

stephencelis
Copy link
Member

The XCTUnimplemented helper is a more general tool than XCTest, and can surface valuable runtime warnings in your application even if you never write a single test. Because of this we'd like to distance our tools from the XCT prefix where it feels appropriate.

As a small step, this means renaming XCTUnimplemented to unimplemented. While XCTUnimplemented still works today, it is soft-deprecated to push folks towards unimplemented, and assuming this course feels good, we'll eventually hard-deprecate it.

The one repercussion is that folks used to defining "unimplemented" dependencies using static let unimplemented will run into circular reference issues:

extension APIClient {
  static let unimplemented = Self(
    fetchUser: unimplemented("\(Self.self).fetchUser")  // 🛑
  )
}

In TCA apps this shouldn't pose a problem as we use testValue:

extension APIClient: TestDependencyKey {
  static let testValue = Self(
    fetchUser: unimplemented("\(Self.self).fetchUser")  // ✅
  )
}

In vanilla apps, though, you'll need to adopt a new name or qualify the function call. You could adopt testValue to get a jumpstart if you ever plan on any future migration to TCA. Or you can always keep unimplemented as the name, it's just a little verbose to fully qualify the function and break the circular reference:

extension APIClient {
  static let unimplemented = Self(
    fetchUser: XCTestDynamicOverlay.unimplemented("\(Self.self).fetchUser")  // ✅
  )
}

@tgrapperon
Copy link
Contributor

tgrapperon commented Oct 19, 2022

Do you think that something like:

extension TestDependencyKey {
  static func unimplemented(
}

would help discovery after typing ., or this is probably too much additional strain on the compiler given the number of overloads? This is also a bunch of overlay logic to replicate in a foreign module. There are workarounds like using an Unimplementable protocol with TestDependencyKey: Unimplementable, albeit the semantic is not correct if Value != Self.
I agree that XCTUnimplemented was difficult to reach and that unimplemented will be much better, but .unimplemented will be even easier.
What do you think?

@stephencelis stephencelis merged commit cc535c3 into main Oct 19, 2022
@stephencelis stephencelis deleted the unimplemented branch October 19, 2022 23:17
@stephencelis
Copy link
Member Author

@tgrapperon Given that unimplemented returns a function I'm not quite sure I see how the dot syntax would work...can you flesh things out with a bit more info so I understand?

@tgrapperon
Copy link
Contributor

tgrapperon commented Oct 19, 2022

unimplemented is a free function. My idea was to have it as a static one to provide a context and also maybe make autocomplete present it more easily when typing . from the static testValue context. I'm currently experimenting to check one can make it work without having to specify the "(Self.self).property" string. I'll open a PR if I find something. I don't think my suggestion is worth it if the only thing it brings to the table is a shorter list of autocompletions when typing "." instead of "u".

@tgrapperon
Copy link
Contributor

@stephencelis Furthermore, I've goofed-up and . wouldn't work indeed here. Please disregard my comment.

@mbrandonw
Copy link
Member

@tgrapperon Don't feel bad. Most of my day is telling @stephencelis I have an idea for something and him explaining to me why it won't work. 🥹

@stephencelis
Copy link
Member Author

It goes both ways 😅 I mostly assume I'm missing something!

@tgrapperon
Copy link
Contributor

BTW, here is mostly is what I had in mind. It is very rough, as KeyPath property name extraction doesn't seem to work when Value is a function. So I'm performing a literal sleight of hand with a disvafored dynamicMemberLookup with KeyPaths that makes Xcode propose them, but in reality filing String variants. If the user users autocomplete, it should work.
Of course, it needs many overloads, but this could maybe be a part of XCTDynamicOverlay if one manages to find a safer way to extract KeyPaths property names.

xctdynamicoverload

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.

3 participants