How can I disambiguate a type and a module with the same name?
Asked Answered
V

2

67

I'm trying to use Károly Lőrentey's B-tree based OrderedSet in a project. However, I'm running into an issue where I can't declare an unqualified OrderedSet<T> because the name conflicts between Foundation's NSOrderedSet (imported as OrderedSet in Swift 3) and BTree's OrderedSet.

let set = OrderedSet<Int>()
// error: 'OrderedSet' is ambiguous for type lookup in this context
// Found this candidate: Foundation.OrderedSet:3:14
// Found this candidate: BTree.OrderedSet:12:15

To resolve this conflict, you would normally qualify the name, and that would give you BTree.OrderedSet<T>. However, the BTree module also contains a class named BTree. If I write BTree.OrderedSet, Swift thinks that I'm referring to a type named OrderedSet that is nested in the BTree.BTree type.

let set = BTree.OrderedSet<Int>()
// error: reference to generic type 'BTree' requires arguments in <...>

If I don't import BTree, I can't use the BTree name at all.

// no import BTree
let set = BTree.OrderedSet<Int>()
// error: use of undeclared type 'BTree'

How can I resolve this ambiguity between the BTree type and the BTree module?

Verbenia answered 18/6, 2016 at 2:11 Comment(8)
This is a great question. Can you typealias one of them?Accouterment
I can't "typealias away" one of them, typealiases can only create names (OrderedSet will remain a valid, if ambiguous, name for both types). But even to typealias one, I need to be able to refer to it...Verbenia
Since I don't use Foundation in this project, I was able to unblock myself by removing #import <Cocoa/Cocoa.h> in the bridged header. However, that doesn't solve the general (and very real) problem.Verbenia
Sounds like a good bug to report.Owen
This bug has already been reported. I started a thread on swift-evolution to find a design.Verbenia
Is this truly a bug? I'm genuinely curious. Wouldn't you not want anything to clash namespaces--even if it came from Objective-C?Fao
Seems to me that we haven't exhausted possibilities to disambiguate that case and that it would be unfortunate to declare it "by design" until then.Verbenia
Oh I see, thank you for the clarification @VerbeniaFao
V
99

The type can be disambiguated using the little-known import (class|struct|func|protocol|enum) Module.Symbol syntax.

import struct BTree.OrderedSet

From this point on, OrderedSet unambiguously refers to the one in BTree.

If this would still be ambiguous or sub-optimal in some files, you can create a Swift file to rename imports using typealiases:

// a.swift
import struct BTree.OrderedSet
typealias BTreeOrderedSet<T> = BTree.OrderedSet<T>

 

// b.swift
let foo = OrderedSet<Int>() // from Foundation
let bar = BTreeOrderedSet<Int>() // from BTree

There was a new syntax discussed for Swift 3, but it fell through.

Verbenia answered 21/7, 2016 at 15:30 Comment(6)
Thanks! One can also use protocol, enum, i.e., all keywords that define types after the import to import only a specific type.Huxham
Can I import BTree after this? I mean I only want to avoid the conflict only one class but the rest of them are not conflict. If I use this to disambiguated import do I also need to change all other non-conflict class to this?Pigment
@SaintTail, I don’t know off the top of my head. Try it and report your results!Verbenia
@Verbenia Doesn't seem to work 😭. I need to add all the required classes the same way as the conflict one.Pigment
I imported a framework with a protocol that had the same argument type name as an existing type in my project. typealias solved this. Amazing!Caesium
But this only works if you don't require to use the BTree class as well within the same file. Since if you import BTree or import class BTree.BTree after the typealias, you are back at the start as then Swift will consider BTree to refer to the class again, not to the module, even if the typealias was above the second import.Elouise
O
5

I renamed OrderedSet to SortedSet in the Swift 3 version of BTree, which should serve as a workaround while a possible language-level fix is being discussed/implemented.

Orest answered 16/7, 2016 at 23:16 Comment(1)
I brought up the issue again on the mailing list a few minutes ago. Hopefully things get going.Verbenia

© 2022 - 2024 — McMap. All rights reserved.