Skip to content
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

Feature: Swift exceptions #554

Open
2 of 3 tasks
danpalmer opened this issue Jan 16, 2025 · 6 comments · May be fixed by #555
Open
2 of 3 tasks

Feature: Swift exceptions #554

danpalmer opened this issue Jan 16, 2025 · 6 comments · May be fixed by #555
Labels
enhancement New feature or request

Comments

@danpalmer
Copy link

Describe what you are looking for

Currently the Swift bindings are just generated from Objective-C. Unfortunately Objective-C uses a different error/exception model to Swift.

Currently, errors are thrown as NSExceptions. These are impossible to catch in Swift, and therefore cause a crash.

It would be great if these were thrown as Swift Exceptions. The Swift/Obj-C translation process can automate part of this with annotations.

Can you contribute to the implementation?

  • I can contribute

Is your feature request specific to a certain interface?

Other

Contact Details

No response

Is there an existing issue for this?

  • I have searched the existing issues

Code of Conduct

  • I agree to follow this project's Code of Conduct
@danpalmer danpalmer added the enhancement New feature or request label Jan 16, 2025
@ashvardanian
Copy link
Contributor

Any chance you can draft a minimal solution?

@danpalmer
Copy link
Author

The pattern in Objective-C that was widely used for errors (exceptions are closer to a panic/fatal error, but not quite), was to pass in an error pointer and have the function set that on return. This pattern was widely enough used that the Objective-C to Swift translation layer understands it with a given attribute and converts it to a thrown Swift error.

Example:

- (UInt32)filteredSearchSingle:(Float32 const *_Nonnull)vector
                 count:(UInt32)wanted
                filter:(USearchFilterFn)predicate
                  keys:(USearchKey *_Nullable)keys
             distances:(Float32 *_Nullable)distances
                 error:(NSError **)errorPtr __attribute__((swift_error(nonnull_error))){
    search_result_t result = _native->filtered_search(vector, static_cast<std::size_t>(wanted), predicate);

    if (!result) {
        *errorPtr = [NSError errorWithDomain:@"YourErrorDomain" 
                                           code:100 
                                       userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithUTF8String:result.error.release()]}]; 
        return 0;
    }

    std::size_t found = result.dump_to(keys, distances);
    return static_cast<UInt32>(found);
}
do {
    try index.filteredSearchSingle(vec, count: 10, filter: fn, keys: nil, distances: nil)
} catch {
    println(error)
}

@ashvardanian
Copy link
Contributor

ashvardanian commented Jan 16, 2025

@danpalmer, will it still work with the older ObjC code or do we need to add new APIs to avoid breaking changes?

@danpalmer
Copy link
Author

This would be backwards-incompatible, although in my opinion a strong improvement to the ObjC API. From my (outdated?) experience, error passing was more common than NSException, and more idiomatic.

@ashvardanian
Copy link
Contributor

@danpalmer, can you please submit a draft of a breaking change and I'll incorporate it into the next major release?

@danpalmer
Copy link
Author

Drafted here: #555

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants