google / j2objc

A Java to iOS Objective-C translation tool and runtime.
http://j2objc.org
Apache License 2.0
5.99k stars 965 forks source link

Feature request:NS_SWIFT_NAME (--swift-friendly) #753

Open Buggaboo opened 8 years ago

Buggaboo commented 8 years ago

It would also be nice, if the NS_SWIFT_NAME macro could be generated:

source: docs

example:

// winded.h
@interface LongWinded
#pragma mark Public
// - (instance...)init(...
- (SomeOtherType*)LongWinded_functionCompoundedWithMoreCruft
    :(MoreCruft*)moreCruft:andSomeMore:(*SomeMore)someMore
    NS_SWIFT_NAME(crufty(moreCruft:someMore:));
@end
// winded.swift
let lw = LongWinded()
lw.crufty(MoreCruft(), SomeMore())

"crufty" by default should be the original java method name. This should only apply to publicly declared methods.

p.s. I am fully aware that --mapping exists to alleviate some of this pain, but to define the mappings is a pain by itself. Also, I know I can declare an extension or Category to "rename" a method, but this shouldn't be necessary.

Thanks!

p.p.s. There are other macros like: NS_REFINED_FOR_SWIFT, NS_SWIFT_UNAVAILABLE but I'm not really sure how to apply those automatedly

tomball commented 8 years ago

We currently support the ObjectiveCName annotation, which j2objc will use instead of name-mangling the method. We could do something similar with a separate SwiftName annotation. It won't be magic, though, as each Java method being renamed needs a separate annotation.

It would also be useful to support Swift names in mapping declarations somehow.

Buggaboo commented 8 years ago

Oh, I didn't know about that annotation. Very cool.

The @ObjectiveCName annotation, might even suffice. Since, method names translations from objc to swift are idempotent. I was using the @Property("...") annotation and I noticed that these also translate nicely to swift, since they don't get mangled with cruft.

Now what would be supernice, are type translations like these, e.g. in method signatures:

java -> objc -> swift :
String[] -> IOSStringArray   -> [String]
char[]   -> IOSCharArray     -> [Character]
byte[]   -> IOSByteArray      -> [UInt8] 
long[]   -> IOS(Long?)Array -> [UInt64] // signedness could be an issue...
...
List<Integer> -> ? -> [UInt32]

Java generics mapped to swift generics. I had to do something awkward with id<Type*> casted to a swift AnyObject-type.

Right now, I have to write plenty of boilerplate for method signature type conversion, so I can mimic the swift way of doing things.

sarsonj commented 6 years ago

Hi, I wanted to report same feature request to find out, that there is one already. I vote for swiftName annotation using NS_SWIFT_NAME, because when ObjectiveC one works fine in most cases, in some not.

Swift is trying to be too clever sometimes, when translating ObjectiveC method definitions to Swift. For example, objectiveC method:

is automatically translated into Swift as

func fileName(for: UInt) -> String?

which is not much clear, what function does. When using macro NS_SWIFT_NAME(fileName(forPageAtIndex:))

we got much better function declaration:

func fileName(forPageAtIndex pageIndex: UInt) -> String?

blazek commented 1 year ago

+1 for swiftName annotation.

Is there any trick to get NS_SWIFT_NAME into header file? I had no success with /*-HEADER[ ]-*/.

tomball commented 1 year ago

In theory, one could declare the ObjC method twice, once j2objc-generated without the NS_SWIFT_NAME, then the same declaration with the annotation in a header block. The contents of a header block is copied verbatim, so for this (horrible) hack to work, it needs to be inside the class declaration:

public class Test {
  public String name(String s) { return s; }

/*-HEADER[
- (NSString *)nameWithNSString:(NSString *)s NS_SWIFT_NAME(swiftName(s:));
]-*/
}

This generates the snippet:

@interface Test : NSObject
- (NSString *)nameWithNSString:(NSString *)s;
- (NSString *)nameWithNSString:(NSString *)s NS_SWIFT_NAME(swiftName(s:));
@end

which compiles without warnings. I don't know what the Swift importer will do, so try it and see -- if it doesn't work, try moving the header block in front of the Java method.

tomball commented 1 year ago

FYI, this would be a great project for an external contributor, as it should just involve finding where the ObjectiveCName is referenced in j2objc/translator/src/main/java/ and making similar changes for a SwiftName annotation. It would actually be simpler, since I don't think it needs support for package annotations.

The spec is defined using unit tests where tiny Java sources get translated and the expected output verified. Again, using the existing ObjectiveCName tests as a guide should make the test writing easy. The part we can't easily do is coming up with the complete set of Java => NS_SWIFT_NAME transformations which the Swift importer will accept.

blazek commented 1 year ago

Thank you for quick answer!

If the /*-HEADER[]-*/ block is placed after the java method, Xcode complains "Multiple declarations of method ':' found and ignored" and it is not available in Swift.

The same if it is placed before the java method as it is written to header file after all methods.

tomball commented 1 year ago

It compiled for me with the j2objcc script, so my suspicion is that Xcode has additional warning flags set.