[swift-build-dev] Namespacing SPM modules (was Re: [swift-dev] Right list?)

Erica Sadun erica at ericasadun.com
Mon Feb 29 12:42:41 CST 2016


> On Feb 29, 2016, at 9:59 AM, Daniel Dunbar <daniel_dunbar at apple.com> wrote:
> 
> Yup!
> 
>  - Daniel
> 
>> On Feb 29, 2016, at 8:53 AM, Erica Sadun <erica at ericasadun.com <mailto:erica at ericasadun.com>> wrote:
>> 
>> I'll try writing up a proposal. Does everything work the same for swift-build-dev as -evolution?
>> 
>> -- E


First draft: https://gist.github.com/erica/c6553a5f6f35e7462074 <https://gist.github.com/erica/c6553a5f6f35e7462074>

Looking forward to feedback, questions, and corrections. -- E


Disambiguating SPM Naming Conflicts

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>
Status: TBD
Review manager: TBD
 <https://gist.github.com/erica/c6553a5f6f35e7462074#introduction>Introduction

I propose to modify Swift's SPM PackageDescription to allow developers to assign local module names to avoid module conflicts. Namespacing supports a decentralized packaging ecosystem that handles the rare case of name overlaps without requiring a central package registry.

This proposal was discussed on the Swift-Dev and Swift-Build-Dev lists in the "Right List? <http://article.gmane.org/gmane.comp.lang.swift.devel/1149>" thread.

 <https://gist.github.com/erica/c6553a5f6f35e7462074#motivation>Motivation

Swift offers a built in mechanism for distinguishing symbol conflicts. When working with NSView, I take care to differentiate Swift.print, which outputs text to the console or stream from NSView's  print, which creates a print job. Swift does not yet offer a solution for conflicting module names.

Like many other Swift developers, I have spent considerable time building utility packages. Mine use obvious names like SwiftString and SwiftCollections. Simple clear naming is a hallmark of Swift design. At the same time, this style introduces the possibility of package name conflicts. 

import SwiftString // mine
import SwiftString // someone else's. oops.
My SwiftString or StringUtility package can't be used alongside someone else's SwiftString or StringUtilitypackage. Moving back to Cocoa-style ESSwiftString namespacing feels ugly and antithetical to Swift design. Swift should encourage recognizable, easy-to-understand module names.

 <https://gist.github.com/erica/c6553a5f6f35e7462074#original-design>Original Design

I first considered namespacing using reverse domain naming in Package declarations. This offers a traditional approach to identify a module's source:

import PackageDescription

let package = Package(
    name:   "SwiftString"
    origin: "org.sadun"
)
Reverse domain names

are relatively short
are already well established for Apple app distribution
do not rely on a web address that may change should the repo move
are less likely to conflict with user names across repo hosts 
However concise, using reverse domain names bring unnecessary verbiage to name conflicts. Consider the following example.

import org.sadun.SwiftString
import com.other.SwiftString

...

// Use my implementation of countSyllables
let count = org.sadun.SwiftString.countSyllables(myString)
In this example, org.sadun.SwiftString.countSyllables places a burden both on writing and reading code. Surely there has to be a better solution.

Adapting import statements resolves symbols but has negative side effects:

import org.sadun.SwiftString as SadunString
import com.other.SwiftString as OtherString

...

// Use my implementation of countSyllables
let count = SadunString.countSyllables(myString)
This approach requires Swift language modification
Import redeclarations may be required across multiple files
Joe Groff suggested a simpler approach: allow package manifests to take responsibility for mapping dependencies to source-level module names.

 <https://gist.github.com/erica/c6553a5f6f35e7462074#revised-design>Revised Design

Under the revised solution, renaming occurs when declaring dependencies. This is what package descriptions looks like under the current system:

import PackageDescription
let package = Package (
    name: "myutility",
    dependencies: [
    .Package(url: "https://github.com/erica/SwiftString.git",
                 majorVersion: 1),
    .Package(url: "https://github.com/bob/SwiftString.git",
                 majorVersion: 1),
    ]
)
Under this proposal, the Package dependency gains an optional localName parameter. When localName is omitted, a package imports as the name declared in Package.name.

import PackageDescription
let package = Package (
    name: "myutility",
    dependencies: [
    .Package(url: "https://github.com/erica/SwiftString.git",
                 majorVersion: 1, localName: "SadunString"), // import SadunString
    .Package(url: "https://github.com/bob/SwiftString.git",
                 majorVersion: 1, localName: "BobString"), // import BobString
    .Package(url: https://github.com/erica/SwiftCollections.git",
                 majorVersion: 1), // import SwiftCollections
    ]
)
 <https://gist.github.com/erica/c6553a5f6f35e7462074#alternatives-considered>Alternatives Considered

Swift names should be as simple and elegant as possible without overlapping with built-in keywords. Other suggestions brought up in-discussion included:

Using GitHub or Bitbucket usernames as namespacing prefixes, e.g. erica.SwiftString. This would not be resilient across cross-repo username conflicts.
Using repo URLs to resolve namespacing conflicts. This would be fragile if repos moved and does not address local module name resolution.
Introducing a registration index for packages.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-build-dev/attachments/20160229/520072dd/attachment.html>


More information about the swift-build-dev mailing list