Fixing modules that contain a type with the same name

I have found that typealias can be used to work around this sort of problem; just set up typealiases in a file that imports one of the modules but not the other. So, for the case in the OP, you would have a file in the project looking something like:

import BTree

typealias BTreeOrderedSet = OrderedSet

Then you can use BTreeOrderedSet in the rest of the project to refer to the BTree module's version of OrderedSet.

@VladimirS already proposed this syntax:

Module::Type

Smells C++ (what's wrong with that?) and I quite like it :smile:

An elegant syntax that deserves serious consideration.

It can also be applied to other entities in top level in a module.

For example:

Swift::print (...)
2 Likes

Would the :: syntax allow you to qualify operators as well? I discovered in another thread that you can't say Swift.&& or Swift.`&&` , but perhaps Swift::&& could work.

How difficult would it be for Swift to just interpret the conflicting name as both a module and a type? Without looking at the compiler source, I'd imagine something like the AST containing something like SimpleModuleOrTypeIdentifier(name: "BTree") (instead of SimpleTypeIdentifier(name: "BTree")) . Then in a later compilation step, the compiler would first check if the member syntax makes sense (compiles) as a module, and if not check if it makes sense as a type, and if neither spit out a error message like:

Taking “BTree” as a module name:
    «as-module error(s)»
Taking “BTree” as type name ‘BTree.BTree’:
    «as-type error(s)»

What I'm suggesting is probably the most amount of work and changes to the Swift codebase compared to other suggestions, but also completely additive and non-breaking with no new syntax for end-users to learn or adapt to.

Worked for me, but unfortunately I also had to create a wrapper framework target in my project— my app project embeds and imports the wrapper (e.g. TwiftWrapper framework), and the wrapper embeds and imports the original lib (e.g. Twift framework) and has a single file with typealiases to prefixed names (e.g. public typealias TwiftUser = User).

The reason why a single file in the app target didn't work was because my app and the offending library (Twift: GitHub - daneden/Twift: 🐦 An async Swift library for the Twitter v2 API 🚧 WIP) both declare User types, so Swift thinks I'm instantiating MyProject::User when I want Twift::User, and of course, typing Twift.User is interpreted as a non-existent Twift::Twift.User type.

TL;DR Lack of ability to resolve types specifically to a module can lead to nasty “namespace” pollution, not easily solved by a single separate typealias(es) source file.

@CharlesS Nevermind, I was able to get it to work with multiple extension files in my app target using the import class Twift.Twift syntax + typealiases. Still a PitA.

This is because qualified import syntax is not intended to import a subset of identifiers, it is specifically to break ambiguities in name lookup. So,

import Foundation // defines Data
import DataModel // defines Data
import struct Foundation.Data // prefer Foundation.Data

What I’m saying is that if you want the behavior you are expecting here it will take an evolution proposal. There is not a bug here. A qualified import will drag whatever identifiers into scope are required to break the ambiguity and present the full interface of the type and its members. Changing that is likely source-breaking.

1 Like

Have ran into this problem again today. This is a good solution if two different modules have the same type. I've encountered a situation where the app source code contains the name so it's not possible to declare a separate file and not have the compiler be confused.