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

[SR-8092] Using a class defined in multiple frameworks by prefixing explicitly #50625

Open
swift-ci opened this issue Jun 25, 2018 · 4 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-8092
Radar None
Original Reporter somu (JIRA User)
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: c892f9ffbf3361730c6c5302e5f40971

Issue Description:

Example:

OperationQueue is a public class that is defined in Foundation framework

Assume a class OperationQueue is also defined in FrameworkA, but is not made public.

Creating a variable by explicitly specifying FrameworkA.OperationQueue refers to Foundation.OperationQueue and doesn't throw a compilation error though FrameworkA.OperationQueue is not accessible.

FrameworkA:

class OperationQueue { //Internal class
    init() {}
}

App:

import UIKit
import FrameworkA

//Even though, it is explicitly mentioned as Framework.OperationQueue,
//it uses Foundation.OperationQueue
let oq = FrameworkA.OperationQueue() //Uses Foundation.OperationQueue

Problem:

  • The above mentioned code doesn't throw a compilation error even when prefixed explicitly as FrameworkA.OperationQueue, though the explicitly mentioned class is inaccessible because it internal.

  • This is misleading to the user, as the user might think it is FrameworkA's class that is used because the user had mentioned explicitly the framework's name.

*

It would be nice if the compiler can throw an error if the class explicitly mentioned is not accessible.

Tested on:

Xcode 9.4

Swift 4.1
iOS 11.4

Links:

Was discussed in Swift Forums: https://forums.swift.org/t/typealias-pointing-to-inaccessible-class-in-framework/13954

@belkadan
Copy link
Contributor

This is behaving as designed, since it turns out in practice people don't know what framework most declarations come from. If the OperationQueue defined in FrameworkA really is internal, then someone referring to FrameworkA.OperationQueue shouldn't even really know about it.

Making this change would also potentially be very source-breaking. I could see it as some kind of linter option instead, once we have a place for checks like that.

@swift-ci
Copy link
Collaborator Author

Comment by Somu (JIRA)

Thanks Jordan for responding quickly, just a few thoughts (I could be wrong)

Since in the code we prefix explicitly ( let oq = FrameworkA.OperationQueue() ) specifying the FrameworkA, I thought it might help if the compiler threw an error since the class is internal and the user has requested for something that is internal explicitly.

If it wasn't prefixed I agree, the class that is visible should be used.

Example2:

For example if a class X was an internal class in FrameworkA and it was explicitly referenced in the code, the following compilation error is thrown.

FrameworkA:

class X {} //Internal class

App:

let x2 = FrameworkA.X() //Module 'FrameworkA' has no member named 'X'

In Example2, the compiler throws an error saying that there is no member X, however it seems to behave differently in Example1 when there is a class defined in multiple frameworks and the user explicitly requests for FrameworkA's class, Foundation's class is used.

I felt some potential bugs could be caught at compile time instead of being surprised at runtime.

Note: These are just my thoughts and I could be wrong.

@belkadan
Copy link
Contributor

The main argument against this is what I said initially: people don't know which module actually contains a declaration. Thus you might expect someone to write UIKit.IndexPath, even though IndexPath actually comes from Foundation. So the prefix isn't a sufficient cue that the user was actually looking specifically in a certain module.

In most cases, this will still be a compiler error because the two types will have different interfaces. That is, both your OperationQueue and the one in Foundation have no-argument initializers, but they probably have very different methods and properties.

@swift-ci
Copy link
Collaborator Author

Comment by Somu (JIRA)

Thanks a lot Jordan for patiently responding, expressing my thoughts on it.

1. I agree the user might not know where a framework is defined, but in some cases the user might want know their own framework and might want something specific, so when a user requests for something specific (almost like forced unwrapping or using unsafe pointers) and if the class user requested for is inaccessible, it would be nice if the compiler throws the error rather than giving something that user didn't request for. I feel that explicitly referencing using the dot operator is there for this specific reason to allow the user to specify which one the user wants.

2. I also agree with regards to the example UIKit.IndexPath, UIKit imports Foundation and eventually it boils down to Foundation.IndexPath.

3. Presently the compiler is throws an error when user specifies an internal class defined in a framework (which is inaccessible), would be nice to be consistent for other class names defined in multiple frameworks when user explicitly specifies the framework name using dot operator.

4. In my case FrameworkA's OperationQueue was actually inheriting Foundation.OperationQueue so it makes it even harder to spot the issue at runtime. So it wasn't caught at compile time and since I didn't add any new methods didn't realise and thought the compiler would give the instance that I requested for. I felt others might encounter this scenario.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

2 participants