> On 28 Feb 2017, at 01:50, Daniel Dunbar <daniel_dun...@apple.com> wrote: > > Hi David, > > We discussed the leading-dot & capitalization issue today again... this was > already something we weren't really happy about, but had chosen to live with > (using the "identity" rule to determine what was a type and what wasn't). > However, as we talked it over more we: > 1. Felt that for the product types, using .library vs .Library would be > reasonable and consistent with a user model of thinking of these like enums > (even though they won't actually be in practice, we will use factory > functions on Product to make the dot work and keep the space extensible). > 2. Realized that using .target would be a useful change to make now if we > ever ended up needing to make the Targets array polymorphic (not something we > plan to do now, but it never hurts to have it be extensible). > so we decided to go ahead and revise to a model where we use leading-dot + > lowercase for everything (except Package), including reverting > SystemPackageProvider to the `.brew(...)` style syntax.
Sounds great! When you send it through proposal, can you include an example Package with all properties set so we can see the new API in use? Thanks! > Thanks for the feedback! > - Daniel > >> On Feb 27, 2017, at 2:21 AM, Ankit Aggarwal via swift-build-dev >> <swift-build-...@swift.org> wrote: >> >> Hi David, >> >> Thanks for the feedback! Comments inline: >> >> >>> On Sun, Feb 26, 2017 at 5:08 AM, David Hart via swift-build-dev >>> <swift-build-...@swift.org> wrote: >>> Was looking forward to this :) here are my comments: >>> >>>> On 25 Feb 2017, at 01:35, Rick Ballard via swift-evolution >>>> <swift-evolution@swift.org> wrote: >>>> >>>> Hi all, >>>> >>>> Ankit, Daniel, Anders, Boris and I have a draft proposal in progress for a >>>> Package.swift manifest API redesign for the Package Manager. We'll welcome >>>> comments or discussion at this time. My hope is that we can get this >>>> polished up and ready for evolution within the next week or so, but we'll >>>> see how the conversation goes! >>>> >>>> You can see the proposal in progress at >>>> https://github.com/aciidb0mb3r/swift-evolution/blob/manifest-api-redesign/proposals/xxxx-package-manager-manifest-api-redesign.md. >>>> I'm also including the current version inline in this email. >>>> >>>> Thanks, >>>> >>>> - Rick >>>> >>>> # Package Manager Manifest API Redesign >>>> >>>> * Proposal: [SE-XXXX](xxxx-package-manager-manifest-api-redesign.md) >>>> * Author: [Ankit Aggarwal](https://github.com/aciidb0mb3r) >>>> * Review Manager: TBD >>>> * Status: **Discussion** >>>> >>>> ## Introduction >>>> >>>> This is a proposal for redesigning the `Package.swift` manifest APIs >>>> provided >>>> by Swift Package Manager. >>>> This proposal only redesigns the existing public APIs and does not add any >>>> new functionality; any API to be added for new functionality will happen in >>>> separate proposals. >>>> >>>> ## Motivation >>>> >>>> The `Package.swift` manifest APIs were designed prior to the [API Design >>>> Guidelines] (https://swift.org/documentation/api-design-guidelines/), and >>>> their >>>> design was not reviewed by the evolution process. Additionally, there are >>>> several small areas which can be cleaned up to make the overall API more >>>> "Swifty". >>>> >>>> We would like to redesign these APIs as necessary to provide clean, >>>> conventions-compliant APIs that we can rely on in the future. Because we >>>> anticipate that the user community for the Swift Package Manager will grow >>>> considerably in Swift 4, we would like to make these changes now, before >>>> more packages are created using the old API. >>>> >>>> ## Proposed solution >>>> >>>> Note: Access modifier is omitted from the diffs and examples for brevity. >>>> The >>>> access modifier is `public` for all APIs unless specified. >>>> >>>> * Remove `successor()` and `predecessor()` from `Version`. >>>> >>>> These methods neither have well defined semantics nor are used a lot >>>> (internally or publicly). For e.g., the current implementation of >>>> `successor()` always just increases the patch version. >>>> >>>> >>>> <details> >>>> <summary>View diff</summary> >>>> <p> >>>> ```diff >>>> struct Version { >>>> - func successor() -> Version >>>> >>>> - func predecessor() -> Version >>>> } >>>> ``` >>>> </p></details> >>>> >>>> * Make all properties of `Package` and `Target` mutable. >>>> >>>> Currently, `Package` has three immutable and four mutable properties, >>>> and >>>> `Target` has one immutable and one mutable property. We propose to make >>>> all >>>> properties mutable to allow complex customization on the package object >>>> after initial declaration. >>>> >>>> <details> >>>> <summary>View diff and example</summary> >>>> <p> >>>> >>>> Diff: >>>> ```diff >>>> final class Target { >>>> - let name: String >>>> + var name: String >>>> } >>>> >>>> final class Package { >>>> - let name: String >>>> + var name: String >>>> >>>> - let pkgConfig: String? >>>> + var pkgConfig: String? >>>> >>>> - let providers: [SystemPackageProvider]? >>>> + var providers: [SystemPackageProvider]? >>>> } >>>> ``` >>>> >>>> Example: >>>> ```swift >>>> let package = Package( >>>> name: "FooPackage", >>>> targets: [ >>>> Target(name: "Foo", dependencies: ["Bar"]), >>>> ] >>>> ) >>>> >>>> #if os(Linux) >>>> package.targets[0].dependencies = ["BarLinux"] >>>> #endif >>>> ``` >>>> </p></details> >>>> >>>> * Change `Target.Dependency` enum cases to lowerCamelCase. >>>> >>>> According to API design guidelines, everything other than types should >>>> be in lowerCamelCase. >>>> >>>> <details> >>>> <summary>View diff and example</summary> >>>> <p> >>>> >>>> Diff: >>>> ```diff >>>> enum Dependency { >>>> - case Target(name: String) >>>> + case target(name: String) >>>> >>>> - case Product(name: String, package: String?) >>>> + case product(name: String, package: String?) >>>> >>>> - case ByName(name: String) >>>> + case byName(name: String) >>>> } >>>> ``` >>>> >>>> Example: >>>> ```diff >>>> let package = Package( >>>> name: "FooPackage", >>>> targets: [ >>>> Target( >>>> name: "Foo", >>>> dependencies: [ >>>> - .Target(name: "Bar"), >>>> + .target(name: "Bar"), >>>> >>>> - .Product(name: "SwiftyJSON", package: "SwiftyJSON"), >>>> + .product(name: "SwiftyJSON", package: "SwiftyJSON"), >>>> ] >>>> ), >>>> ] >>>> ) >>>> ``` >>>> </p></details> >>>> >>>> * Add default parameter to the enum case `Target.Dependency.product`. >>>> >>>> The associated value `package` in the (enum) case `product`, is an >>>> optional >>>> `String`. It should have the default value `nil` so clients don't need >>>> to >>>> write it if they prefer using explicit enum cases but don't want to >>>> specify >>>> the package name i.e. it should be possible to write `.product(name: >>>> "Foo")` instead of `.product(name: "Foo", package: nil)`. >>>> >>>> If >>>> >>>> [SE-0155](https://github.com/apple/swift-evolution/blob/master/proposals/0155-normalize-enum-case-representation.md) >>>> is accepted, we can directly add a default value. Otherwise, we will >>>> use a >>>> static factory method to provide default value for `package`. >>>> >>>> * Upgrade `SystemPackageProvider` enum to a struct. >>>> >>>> This enum allows SwiftPM System Packages to emit hints in case of build >>>> failures due to absence of a system package. Currently, only one system >>>> package per system packager can be specified. We propose to allow >>>> specifying multiple system packages by replacing the enum with this >>>> struct: >>>> >>>> ```swift >>>> public struct SystemPackageProvider { >>>> enum PackageManager { >>>> case apt >>>> case brew >>>> } >>>> >>>> /// The system package manager. >>>> let packageManager: PackageManager >>>> >>>> /// The array of system packages. >>>> let packages: [String] >>>> >>>> init(_ packageManager: PackageManager, packages: [String]) >>>> } >>>> ``` >>>> >>>> <details> >>>> <summary>View diff and example</summary> >>>> <p> >>>> >>>> Diff: >>>> ```diff >>>> -enum SystemPackageProvider { >>>> - case Brew(String) >>>> - case Apt(String) >>>> -} >>>> >>>> +struct SystemPackageProvider { >>>> + enum PackageManager { >>>> + case apt >>>> + case brew >>>> + } >>>> + >>>> + /// The system package manager. >>>> + let packageManager: PackageManager >>>> + >>>> + /// The array of system packages. >>>> + let packages: [String] >>>> + >>>> + init(_ packageManager: PackageManager, packages: [String]) >>>> +} >>>> ``` >>>> >>>> Example: >>>> >>>> ```diff >>>> let package = Package( >>>> name: "Copenssl", >>>> pkgConfig: "openssl", >>>> providers: [ >>>> - .Brew("openssl"), >>>> + SystemPackageProvider(.brew, packages: ["openssl"]), >>>> >>>> - .Apt("openssl-dev"), >>>> + SystemPackageProvider(.apt, packages: ["openssl", >>>> "libssl-dev"]), >>>> ] >>>> ) >>>> ``` >>>> </p></details> >>> >>> Why not keep the enum and change the associated type to a String array? >>> >> >> True, we could do that but we'd be repeating that information in every >> SystemPackager we add. Converting to a struct makes it easier to scale. >> >>>> * Remove implicit target dependency rule for test targets. >>>> >>>> There is an implicit test target dependency rule: a test target >>>> "FooTests" >>>> implicity depends on a target "Foo", if "Foo" exists and "FooTests" >>>> doesn't >>>> explicitly declare any dependency. We propose to remove this rule >>>> because: >>>> >>>> 1. It is a non obvious "magic" rule that has to be learned. >>>> 2. It is not possible for "FooTests" to remove dependency on "Foo" while >>>> having no other (target) dependency. >>>> 3. It makes real dependencies less discoverable. >>>> 4. It may cause issues when we get support for mechanically editing >>>> target >>>> dependencies. >>>> >>>> * Introduce an "identity rule" to determine if an API should use an >>>> initializer >>>> or a factory method: >>> >>> Could you explain this rule in more detail. What is an identity in this >>> case? I'm confused. >> >> >> This is similar to the rule we use to decide if something should be a struct >> or a class. If you're forming a concrete object, that would be an identity. >> Consider these two examples: >> >> 1. Target and its dependencies: >> >> Target(name: "Foo", dependencies: [.target(name: "Bar")]) >> >> Here the target Foo is being constructed, so an initializer is used. The >> target Bar is being referred in Foo's dependencies so that uses a factory >> method. >> >> 2. Product and product dependencies in targets: >> >> When constructing the product, the initializer should be used: >> .Library(name: "FooLib", targets: ["Foo", "Utility"]) >> >> And while referring to the product, like in target dependency, factory >> method should be used: >> Target(name: "Foo", dependencies: [.product(name: "FooLib")]) >> >>>> Under this rule, an entity having an identity, will use a type >>>> initializer >>>> and everything else will use factory methods. `Package`, `Target` and >>>> `Product` are identities. However, a product referenced in a target >>>> dependency is not an identity. >>>> >>>> This means the `Product` enum should be converted into an identity. We >>>> propose to introduce a `Product` class with two subclasses: `Executable` >>>> and `Library`. These subclasses will be nested inside `Product` class >>>> instead of being a top level declaration in the module. The major >>>> advantage of nesting is that we get a namespace for products and it is >>>> easy >>>> to find all the supported products when the product types grows to a >>>> large >>>> number. A downside of nesting is that the product initializers will >>>> have to >>>> used with the dot notation (e.g.: `.Executable(name: "tool", targets: >>>> ["tool"])`) which is a little awkward because we expect factory methods >>>> to >>>> use the dots. >>>> >>>> They will be defined as follow: >>>> >>>> ```swift >>>> /// Represents a product. >>>> class Product { >>>> >>>> /// The name of the product. >>>> let name: String >>>> >>>> /// The names of the targets in this product. >>>> let targets: [String] >>>> >>>> private init(name: String, targets: [String]) { >>>> self.name = name >>>> self.targets = targets >>>> } >>>> >>>> /// Represents an executable product. >>>> final class Executable: Product { >>>> >>>> /// Creates an executable product with given name and targets. >>>> override init(name: String, targets: [String]) >>>> } >>>> >>>> /// Represents a library product. >>>> final class Library: Product { >>>> /// The type of library product. >>>> enum LibraryType: String { >>>> case `static` >>>> case `dynamic` >>>> } >>>> >>>> /// The type of the library. >>>> /// >>>> /// If the type is unspecified, package manager will >>>> automatically choose a type. >>>> let type: LibraryType? >>>> >>>> /// Creates a library product. >>>> init(name: String, type: LibraryType? = nil, targets: [String]) >>>> } >>>> } >>>> ``` >>>> >>>> <details> >>>> <summary>View example</summary> >>>> <p> >>>> >>>> Example: >>>> >>>> ```swift >>>> let package = Package( >>>> name: "Foo", >>>> target: [ >>>> Target(name: "Foo", dependencies: ["Utility"]), >>>> Target(name: "tool", dependencies: ["Foo"]), >>>> ], >>>> products: [ >>>> .Executable(name: "tool", targets: ["tool"]), >>>> .Library(name: "Foo", targets: ["Foo"]), >>>> .Library(name: "FooDy", type: .dynamic, targets: ["Foo"]), >>>> ] >>>> ) >>>> ``` >>>> </p></details> >>> >>> This API looks very weird: the leading dog is usually used for enum cases >>> and static members. Using it with a type means that the capitalization >>> looks very out of place. >>> >> >> Yes, as mentioned in the proposal we think the dot and capitalization >> following it looks out of place here but we really think that the products >> should be under a namespace because the types supported product might grow >> to a substantial number in future. Adding namespace using nesting solves >> this issue nicely. >> >> Another advantage would be getting free autocomplete support for products in >> IDEs or text editors which supports SourceKit. Right now there is none which >> supports autocomplete for the manifest file but since SourceKit is cross >> platform, it should be possible to create a plugin in future. >> >>>> * Special syntax for version initializers. >>>> >>>> A simplified summary of what is commonly supported in other package >>>> managers: >>>> >>>> | Package Manager | x-ranges | tilde (`~` or `~>`) | caret >>>> (`^`) | >>>> >>>> |-----------------|---------------|-------------------------|---------------| >>>> | npm | Supported | Allows patch-level changes if a >>>> minor version is specified on the comparator. Allows minor-level changes >>>> if not. | patch and minor updates | >>>> | Cargo | Supported | Same as above | Same as >>>> above | >>>> | CocoaPods | Not supported | Same as above | Not >>>> supported | >>>> | Carthage | Not supported | patch and minor updates | Not >>>> supported | >>>> >>>> Some general observations: >>>> >>>> * Every package manager we looked at for this supports the tilde `~` >>>> operator in some form. >>>> * The widely accepted suggestion on how to constrain your versions is >>>> "use >>>> `~>`, it does the right thing". >>>> * It's not clear to us why this has so much traction as "the right >>>> thing", as it can >>>> prevent upgrades that should be compatible (one minor version to next >>>> minor version). >>>> * Most users may not really understand `~`, and just use it per >>>> recommendations. >>>> See e.g. how Google created a [6-minute instructional >>>> video](https://www.youtube.com/watch?v=x4ARXyovvPc) >>>> about this operator for CocoaPods. >>>> * A lot of people even explicitly set a single exact version simply >>>> because >>>> they don't know better. This leads to "dependency hell" (unresolvable >>>> dependencies >>>> due to conflicting requirements for a package in the dependency >>>> graph). >>>> * The Swift Package Manager will probably have many novice users, >>>> because it >>>> comes built-in to Swift. >>>> * We think caret `^` has the right behaviour most of the time. That is, >>>> you >>>> should be able to specify a minimum version, and you should be >>>> willing to let >>>> your package use anything after that up to the next major version. >>>> This policy >>>> works if packages correctly follow semantic versioning, and it >>>> prevents "dependency >>>> hell" by expressing permissive constraints. >>>> * We also think caret `^` is syntactically non-obvious, and we'd prefer >>>> a syntax >>>> that doesn't require reading a manual for novices to understand, even >>>> if that >>>> means we break with the syntactic convention established by the other >>>> package managers which >>>> support caret `^`. >>>> * We'd like a convenient syntax for caret `^`, but to still support the >>>> use >>>> case that tilde `~` is used for; but tilde `~` (or a single exact >>>> version) should >>>> be less convenient than caret `^`, to encourge permissive dependency >>>> constraints. >>>> >>>> What we propose: >>>> >>>> * We will introduce a factory method which takes a lower bound version >>>> and >>>> forms a range that goes upto the next major version (i.e. caret). >>>> >>>> ```swift >>>> // 1.0.0 ..< 2.0.0 >>>> .package(url: "/SwiftyJSON", from: "1.0.0"), >>>> >>>> // 1.2.0 ..< 2.0.0 >>>> .package(url: "/SwiftyJSON", from: "1.2.0"), >>>> >>>> // 1.5.8 ..< 2.0.0 >>>> .package(url: "/SwiftyJSON", from: "1.5.8"), >>>> ``` >>>> >>>> * We will introduce a factory method which takes `VersionSetSpecifier`, >>>> to >>>> conveniently specify common ranges. >>>> >>>> `VersionSetSpecifier` is an enum defined as follows: >>>> >>>> ```swift >>>> enum VersionSetSpecifier { >>>> case exact(Version) >>>> case range(Range<Version>) >>>> >>>> /// Creates a specifier for an exact version. >>>> static func only(_ version: Version) -> VersionSetSpecifier >>>> >>>> /// Creates a specified for a range starting at the given lower >>>> bound >>>> /// and going upto next major version. >>>> static func uptoNextMajor(_ version: Version) -> >>>> VersionSetSpecifier >>>> >>>> /// Creates a specified for a range starting at the given lower >>>> bound >>>> /// and going upto next minor version. >>>> static func uptoNextMinor(_ version: Version) -> >>>> VersionSetSpecifier >>>> } >>>> ``` >>>> >>>> Examples: >>>> >>>> ```swift >>>> // 1.5.8 ..< 2.0.0 >>>> .package(url: "/SwiftyJSON", .uptoNextMajor("1.5.8")), >>>> >>>> // 1.5.8 ..< 1.6.0 >>>> .package(url: "/SwiftyJSON", .uptoNextMinor("1.5.8")), >>>> >>>> // 1.5.8 >>>> .package(url: "/SwiftyJSON", .only("1.5.8")), >>>> ``` >>>> >>>> * This will also give us ability to add more complex features in future: >>>> >>>> Examples: >>>>> Note that we're not actually proposing these as part of this proposal. >>>> >>>> ```swift >>>> .package(url: "/SwiftyJSON", >>>> .uptoNextMajor("1.5.8").excluding("1.6.4")), >>>> >>>> .package(url: "/SwiftyJSON", .only("1.5.8", "1.6.3")), >>>> >>>> ``` >>>> >>>> * We will introduce a factory method which takes `Range<Version>`, to >>>> specify >>>> arbitrary open range. >>>> >>>> ```swift >>>> // Constraint to an arbitrary open range. >>>> .package(url: "/SwiftyJSON", "1.2.3"..<"1.2.6"), >>>> ``` >>>> >>>> * We will introduce a factory method which takes >>>> `ClosedRange<Version>`, to specify >>>> arbitrary closed range. >>>> >>>> ```swift >>>> // Constraint to an arbitrary closed range. >>>> .package(url: "/SwiftyJSON", "1.2.3"..."1.2.8"), >>>> ``` >>>> >>>> * We will remove all of the current factory methods: >>>> >>>> ```swift >>>> // Constraint to a major version. >>>> .Package(url: "/SwiftyJSON", majorVersion: 1), >>>> >>>> // Constraint to a major and minor version. >>>> .Package(url: "/SwiftyJSON", majorVersion: 1, minor: 2), >>>> >>>> // Constraint to an exact version. >>>> .Package(url: "/SwiftyJSON", "1.2.3"), >>>> >>>> // Constraint to an arbitrary range. >>>> .Package(url: "/SwiftyJSON", versions: "1.2.3"..<"1.2.6"), >>>> >>>> // Constraint to an arbitrary closed range. >>>> .Package(url: "/SwiftyJSON", versions: "1.2.3"..."1.2.8"), >>>> ``` >>> >>> I'm ver happy with the versioning part of this proposal :-) >>> >> >> Great! >>>> * Adjust order of parameters on `Package` class: >>>> >>>> We propose to reorder the parameters of `Package` class to: `name`, >>>> `pkgConfig`, `products`, `dependencies`, `targets`, >>>> `compatibleSwiftVersions`. >>>> >>>> The rationale behind this reorder is that the most interesting parts of >>>> a >>>> package are its product and dependencies, so they should be at the top. >>>> Targets are usually important during development of the package. >>>> Placing >>>> them at the end keeps it easier for the developer to jump to end of the >>>> file to access them. Note that the compatibleSwiftVersions property >>>> will likely >>>> be removed once we support Build Settings, but that will be discussed >>>> in a separate proposal. >>> >>> I would have liked this proposal to suggest modifying the API so the order >>> is insignificant. While ordering feels important for me when calling a >>> function or initializer with few arguments (like .package(url: "", from: >>> "1.4.5")), the arguments to the Package function seem like a list of >>> configuration options and shouldn't have a fixed order. My suggestion was >>> to remove all arguments but the name and adds a configuration closure: >>> >>> let package = Package(name: "paper") { >>> $0.products = [...] >>> $0.dependencies = [...] >>> } >>> >> >> It will be possible to avoid using the initializer because all the >> properties will be made mutable. However I think if majority of packages >> uses the initializer and thus have a consistent ordering, it will be easier >> for other developers to read manifests on Github (or similar). >> >> PS: The closure syntax can also be added using extension in the manifest >> itself if someone really wants to use it. >> >>>> <details> >>>> <summary>View example</summary> >>>> <p> >>>> >>>> Example: >>>> >>>> ```swift >>>> let package = Package( >>>> name: "Paper", >>>> products: [ >>>> .Executable(name: "tool", targets: ["tool"]), >>>> .Libary(name: "Paper", type: .static, targets: ["Paper"]), >>>> .Libary(name: "PaperDy", type: .dynamic, targets: ["Paper"]), >>>> ], >>>> dependencies: [ >>>> .package(url: "http://github.com/SwiftyJSON", from: "1.2.3"), >>>> .package(url: "../CHTTPParser", .uptoNextMinor("2.2.0")), >>>> .package(url: "http://some/other/lib", .only("1.2.3")), >>>> ] >>>> targets: [ >>>> Target( >>>> name: "tool", >>>> dependencies: [ >>>> "Paper", >>>> "SwiftyJSON" >>>> ]), >>>> Target( >>>> name: "Paper", >>>> dependencies: [ >>>> "Basic", >>>> .target(name: "Utility"), >>>> .product(name: "CHTTPParser"), >>>> ]) >>>> ] >>>> ) >>>> ``` >>>> </p></details> >>>> >>>> * Eliminate exclude in future (via custom layouts feature). >>>> >>>> We expect to remove the `exclude` property after we get support for >>>> custom >>>> layouts. The exact details will be in the proposal of that feature. >>>> >>>> ## Impact on existing code >>>> >>>> The above changes will be implemented only in the new Package Description >>>> v4 >>>> library. The v4 runtime library will release with Swift 4 and packages >>>> will be >>>> able to opt-in into it as described by >>>> [SE-0152](https://github.com/apple/swift-evolution/blob/master/proposals/0152-package-manager-tools-version.md). >>>> >>>> There will be no automatic migration feature for updating the manifests >>>> from v3 >>>> to v4. To indicate the replacements of old APIs, we will annotate them >>>> using >>>> the `@unavailable` attribute where possible. Unfortunately, this will not >>>> cover >>>> all the changes for e.g. rename of the target dependency enum cases. >>>> >>>> All new packages created with `swift package init` command in Swift 4 tools >>>> will by default to use the v4 manifest. It will be possible to switch to v3 >>>> manifest version by changing the tools version using `swift package >>>> tools-version --set 3.1`. However, the manifest will needed to be >>>> adjusted to >>>> use the older APIs manually. >>>> >>>> Unless declared in the manifest, existing packages automatically default >>>> to the Swift 3 minimum tools version; since the Swift 4 tools will also >>>> include >>>> the v3 manifest API, they will build as expected. >>>> >>>> A package which needs to support both Swift 3 and Swift 4 tools will need >>>> to >>>> stay on the v3 manifest API and support the Swift 3 language version for >>>> its >>>> sources, using the API described in the proposal >>>> [SE-0151](https://github.com/apple/swift-evolution/blob/master/proposals/0151-package-manager-swift-language-compatibility-version.md). >>>> >>>> An existing package which wants to use the new v4 manifest APIs will need >>>> to bump its >>>> minimum tools version to 4.0 or later using the command `$ swift package >>>> tools-version >>>> --set-current`, and then modify the manifest file with the changes >>>> described in >>>> this proposal. >>>> >>>> ## Alternatives considered >>>> >>>> * Add variadic overloads. >>>> >>>> Adding variadic overload allows omitting parenthesis which leads to less >>>> cognitive load on eyes, especially when there is only one value which >>>> needs >>>> to be specified. For e.g.: >>>> >>>> Target(name: "Foo", dependencies: "Bar") >>>> >>>> might looked better than: >>>> >>>> Target(name: "Foo", dependencies: ["Bar"]) >>>> >>>> However, plurals words like `dependencies` and `targets` imply a >>>> collection >>>> which implies brackets. It also makes the grammar wrong. Therefore, we >>>> reject this option. >>>> >>>> * Version exclusion. >>>> >>>> It is not uncommon to have a specific package version break something, >>>> and >>>> it is undesirable to "fix" this by adjusting the range to exclude it >>>> because this overly constrains the graph and can prevent picking up the >>>> version with the fix. >>>> >>>> This is desirable but it should be proposed separately. >>>> >>>> * Inline package declaration. >>>> >>>> We should probably support declaring a package dependency anywhere we >>>> support spelling a package name. It is very common to only have one >>>> target >>>> require a dependency, and annoying to have to specify the name twice. >>>> >>>> This is desirable but it should be proposed separately. >>>> >>>> _______________________________________________ >>>> swift-evolution mailing list >>>> swift-evolution@swift.org >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> >>> One thing that still really bothers me about the API is the inconsistency >>> in leading dots and capitalization. Should a novice (or an expert) have to >>> remember the following different writings: >>> >>> Target(name: "Foo", dependencies: ["Utility"]) >>> .package(url: "http://github.com/SwiftyJSON", from: "1.2.3") >>> .Library(name: "Paper", type: .static, targets: ["Paper"]) >>> >>> I understand the arguments brought forward in the proposal. But from a >>> package author point of view, it's not obvious why Target is capitalized, >>> why package is lowercase with a leading dot and why Library is capitalized >>> with a leading dot. It looks confusing and inconsistent, which makes it >>> less pleasant to read and harder to remember. >>> >>> Could we push for more consistency by having everything b lowercased with a >>> leading dot? It does force us to introduce a Target factory method, to >>> revert SystemPackageProvider back to an enum, to revert products back to an >>> enum. But I think it's worth it. >> >> It is true that it might not be obvious when to use what initially, but we >> think this is a good rule to create a distinction between constructing >> things and referring to things. A downside of lowercasing everything would >> be: it might seem like the references support all the parameters that >> constructor supports. e.g. .target(name: "Foo", dependencies: [ >> .target(name: "Bar", dependencies: ["Baz"]) ]) >> >> >> >> >> >> >> _______________________________________________ >> swift-build-dev mailing list >> swift-build-...@swift.org >> https://lists.swift.org/mailman/listinfo/swift-build-dev >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution