<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jun 29, 2017, at 4:39 PM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jun 29, 2017, at 16:35, Daniel Dunbar <<a href="mailto:daniel_dunbar@apple.com" class="">daniel_dunbar@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jun 29, 2017, at 10:43 AM, Jordan Rose via swift-dev <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">Thanks for following through on this, Gonzalo! (The two of us talked about this briefly at WWDC.) My idea was a little less clever than yours: just always include the internal members in the main header <i class="">unless</i> you provide the name of a second header to put them in. (I called this flag -emit-objc-internal-header-path.) That's not quite as flexible, but does remove all the guesswork, at least for generated headers.</div></div></div></blockquote><div class=""><br class=""></div>Doesn't that mean downstream Obj-C clients get bogus code completion results?</div></div></div></blockquote><div class=""><br class=""></div><div class="">I’m not sure what you mean by this.</div></div></div></div></blockquote><div><br class=""></div>I simply misunderstood what you were proposing -- your comments were specifically about using a category to extend; not about adding both members to the existing public header.</div><div><br class=""></div><div> - Daniel</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""> Frameworks will always generate both headers, apps and unit tests will always generate one header. The only problem is if someone custom-builds a library target and is relying on that not including internal decls…which, admittedly, can happen. But the current logic is a patchwork of guesswork.</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">I filed a bug to track this work: <a href="https://bugs.swift.org/browse/SR-5221" class="">SR-5221</a>.</div></div></div></blockquote><div class=""><br class=""></div>Cool, this sounds like a nice feature to me, I have heard several complaints about needing to mark things public unnecessarily.</div><div class=""><br class=""></div><div class=""> - Daniel</div><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">Jordan</div><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Jun 29, 2017, at 06:35, Gonzalo Larralde via swift-dev <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">I wanted to bring a few points into attention to discuss potential improvements on Mixed Frameworks support. The current status for Mixed Frameworks present some challenges, one specifically being how the Swift compiler generates the ObjC Interface Header. <br class=""></div><div class=""><br class=""></div><div class="">At this moment, there's a detection procedure based on the presence of an entry point definition (either using the main file argument, or @UIApplicationMain). The ObjC Interface Header writer (swift/lib/PrintAsObjC/PrintAsObjC.cpp) is using this detection to determine if the minimum accessibility level to be exported is either `internal` (for app targets) or `public` (for framework targets). This can be observed here: <a href="https://github.com/apple/swift/blob/master/lib/FrontendTool/FrontendTool.cpp#L652-L657" class="">https://github.com/apple/swift/blob/master/lib/FrontendTool/FrontendTool.cpp#L652-L657</a></div><div class=""><br class=""></div><div class="">The result of this is a difference on how default visibility is exposed to ObjC code in the same compilation scope.</div><div class=""><br class=""></div><div class="">Having this initial piece of code:</div><div class=""><br class=""></div><div class="">```</div><div class="">public class Test: NSObject {</div><div class=""><span style="white-space:pre" class="">        </span>public foo() {}</div><div class=""><span style="white-space:pre" class="">        </span>func bar() {}</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class="">results on the following Interface Header for Main App targets</div><div class=""><br class=""></div><div class=""><target-name>-swift.h</div><div class="">```</div><div class="">@interface Test : NSObject</div><div class="">- (void)foo;</div><div class="">- (void)bar;</div><div class="">@end</div><div class="">```</div><div class=""><br class=""></div><div class="">and the following for Frameworks</div><div class=""><br class=""></div><div class=""><target-name>-swift.h</div><div class="">```</div><div class="">@interface Test : NSObject</div><div class="">- (void)foo;</div><div class="">@end</div><div class="">```</div><div class=""><br class=""></div><div class="">This is clearly correct for the publicly visible interface of the framework, but not quite the expected result for the ObjC code compiled in the same target. In that scenario it would make more sense to me that all the `internal` methods are visible.</div><div class=""><br class=""></div><div class="">A potential solution for this problem is to generate two Interface Headers, one that exports all the `public` and `open` entities and members, and an additional header exposing internal entities and declaring categories to public entities and exposing internal members.</div><div class=""><br class=""></div><div class="">Something like:</div><div class=""><br class=""></div><div class=""><target-name>-swift-internal.h</div><div class="">```</div><div class="">@interface Test (InternalMembers)</div><div class="">- (void)bar;</div><div class="">@end</div><div class="">```</div><div class=""><br class=""></div><div class="">After that it'll be Xcode's responsability to create both files, and mark them as Public and Project in the Headers Build Phase.</div><div class=""><br class=""></div><div class="">An initial implementation that I think would make sense in case this solution is accepted could be modifying the signature of `swift::printAsObjC` to require the list of access levels to export as a bitmask instead of just getting the minimum. That will enable the exporter to create the following set of files:</div><div class=""><br class=""></div><div class="">* Internal, Public, Open > <target-name>-swift.h for app targets</div><div class="">* Public, Open > <target-name>-swift.h for framework targets</div><div class="">* Internal > <target-name>-swift-internal.h for the internal entities and members on framework targets.</div><div class=""><br class=""></div><div class="">To make this happen a new argument needs to be passed to the compiler call. When it's not passed the default behaviour would remain the same, but when it is the behaviour needs to be explicitly defined. One option is to just get the explicit list of access levels to export (something like `-export=internal,public,open`) or export levels to be defined (0 for app targets, 1 for public framework targets and 2 for the internal header framework targets for example)</div><div class=""><br class=""></div><div class="">I hope this feature proposal is complete enough to properly define the scope and discuss the viability of a possible solution. Otherwise please let me know.</div><div class=""><br class=""></div><div class="">Thanks.</div><div class=""><div class="gmail_signature"><br class="">--<br class="">Slds,<br class=""><br class="">Gonzalo.</div></div>
</div>
_______________________________________________<br class="">swift-dev mailing list<br class=""><a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-dev" class="">https://lists.swift.org/mailman/listinfo/swift-dev</a><br class=""></div></blockquote></div><br class=""></div>_______________________________________________<br class="">swift-dev mailing list<br class=""><a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-dev" class="">https://lists.swift.org/mailman/listinfo/swift-dev</a><br class=""></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></body></html>