On Mon, Feb 1, 2016 at 1:10 PM, Nate Cook via swift-evolution < swift-evolution@swift.org> wrote:
This is a concurring opinion with Drew's review, agreeing that we should
reconsider removing the "NS" prefix but providing my own reasons. The
proposal as a whole is exciting and far-reaching, but this particular
change is misguided. My objections are:
*1) The change will elide the different semantic expectations for
Foundation and Swift standard library types.*
Prefix-less Foundation types will blur the different norms and
expectations for Foundation types vs what we have in the Swift standard
library, particularly in regards to value vs reference semantics of
collection types.
The Swift standard library defines Array, Set, and Dictionary as
collection types with value semantics that operate quite differently from
their peers in Foundation. This change will introduce OrderedSet,
CountedSet, HashTable, MapTable, and others, all of which use reference
semantics and therefore don't provide the same set of guarantees about
ownership and immutability.
As an example, the seemingly similar Set and CountedSet types produce
different results from nearly identical code. Swift's Set type has value
semantics, so changes to a copy don't affect the original Set instance:
let simpleSet = Set(["one", "two", "three"])
var copiedSimpleSet = simpleSet
copiedSimpleSet.remove("one")
copiedSimpleSet.contains("one") // false
simpleSet.contains("one") // true
CountedSet (née NSCountedSet), on the other hand, uses reference
semantics, so changes to a copy of an instance. This is true whether the
copy is an explicit one made via assignment or the implicit copy made when
calling a function with CountedSet as a parameter. This example shows how
nearly code nearly identical to the above produces very different results:
let countedSet = CountedSet(array: ["one", "two", "three"])
var copiedCountedSet = countedSet
copiedCountedSet.remove("one")
copiedCountedSet.contains("one") // false
countedSet.contains("one") // false!
Collections constructed from immutable/mutable class clusters (like
OrderedSet and MutableOrderedSet) pose the same problems, since you may be
using a mutable instance of the "immutable" collection. We clearly are
already dealing with this difference today, but eliminating the "NS" prefix
implies that Foundation types are on the same level as the standard
library. This makes the confusion more pronounced and significantly
increases both the learning curve of the Swift & Foundation APIs and the
risk of errors when using different collection types.
*2) The change may stifle the development of more Swift-oriented APIs.*
Foundation types were developed in and for a language that uses reference
semantics and subclassing, rather than value semantics and a
protocol-oriented approach. The designs therefore use and reinforce norms
that relate better to Objective-C than to Swift—class clusters of
non-final, immutable types with mutable subclasses, immutable types with
separate but related mutable counterparts, etc.
A Swift-native CountedSet (and other collections) would surely have value
semantics built in. What about other types—do the new
Calendar/Date/DateComponents types look like the system that we would
design from the ground up in Swift? How about URL and URLComponents?
Dropping the "NS" prefix would make it more difficult to gradually expand
the standard library to encompass bridging versions of these and other
common types.
*3) The change will make it harder to find information about the revised
APIs.*
Excellent search-ability is an unintended benefit of the "NS" prefix, and
can be understood as a way that these types avoid collisions in the vast
namespace-less sea of Internet search results. Searching for help with URL
and Calendar will be much more difficult than their NS'ed counterparts.
Especially given the challenges that this proposal will pose for code
sourced from tutorials, blog posts, Stack Overflow answers, etc., keeping
at least the class names as sign posts seems valuable.
*4) We'll still be using prefixes after the change.*
While the removal of "NS" is far-reaching, prefixes will still be a common
occurrence in code written in Swift. UIKit and AppKit, along with all the
various frameworks, will still retain their prefixes, so removing prefixes
in the case of Foundation types will be more the exception than the norm.
As such, any benefit of the removal would be mitigated by the continued use
of prefixes for the rest of the first-party types we rely on.
In sum, the change would make the language and its APIs more confusing and
more difficult to use today, would make it more difficult to migrate to
modern designs in the future, and would ultimately provide a very minor
benefit. I encourage the Swift core team to reconsider the "Strip the "NS"
prefix from Foundation APIs" portion of the proposal.
Nate
On Jan 30, 2016, at 5:01 PM, Drew Crawford via swift-evolution < > swift-evolution@swift.org> wrote:
I am in favor of this proposal on balance, and I leave the bulk of this to
people who interop with Objective-C more often than I do.
I would like to confine my remarks to one corner where I think we are
making a very serious mistake.
The removal of the "NS" prefix for the Foundation module (or other
specifically identified modules) is a mechanical translation for all global
symbols defined within that module that can be performed in the Clang
importer.
As I understand it (and I am no Cocoa historian) the NS prefix was
originally introduced because Objective-C lacks namespacing.
The thinking seems to be that since Swift has proper namespacing, this
historicism is no longer necessary. I find this argument very flimsy.
Of course Swift has stronger namespacing if one's frame of reference is
Objective-C or C. But for those of us coming from other language
backgrounds, namespacing means something much stronger than Swift's concept
of it. I don't mean to suggest that Swift's design is wrong exactly (less
is sometimes more), but I do mean to say that if we propose to undo a
decision that worked for several decades and break every Swift project in
existence on the theory that Swift's namespacing is strong enough we had
better be right.
For those unfamiliar, I will explain some of the namespacing tools Swift
lacks relative to other languages. First, many languages have a
"hierarchical" namespace system, where one can say
import Foundation.Net.URL
let s = Session(...)
instead of for example
import Foundation
let s = NSURLSession(...)
Some form of this is used in Rust, Python, and C#, as far as I know. I
believe Swift has some counterfeit version of this, as the book mentions
you can import a "submodule
<The Swift Programming Language: Redirect,
but I do not know what that is, do not know how to make one, have never
seen anyone use one, the book suggests it goes only 2 levels deep, and
perhaps as a consequences of some of these problems nobody thought of using
this for Foundation.
A closely related difference is the use of so-called "selective" imports,
where we import only a single symbol (or a list of explicitly-identified
symbols) into the scope. We might express this as
from Foundation.Net.URL import Session, HTTP //import two classes only
let s = Session(...)
Again I think Swift technically supports some way to avoid importing a
whole gigantic namespace like Foundation, but I am not aware of any actual
uses of this feature, and certainly the convention is not to write code
this way. Meanwhile, let's check in with the Python community, who
standardized the following guidance on these "wildcard" imports as part of
their language evolution process:
Wildcard imports ( from <module> import * ) should be avoided, as they
make it unclear which names are present in the namespace, confusing both
readers and many automated tools. There is one defensible use case for a
wildcard import...
When a language has a robust namespacing system, which we do not, there
are many follow-on consequences. One is that an import statement is much
more of a scalpel than a bludgeon; each import statement only introduces a
handful of new names (even if it is a so-called "wildcard" import that
grabs all children of some namespace, most of those children are themselves
namespaces), unlike importing Foundation which contains thousands of direct
child types that are injected into the local scope.
Another consequence is that class names become quite short, shadow each
other, and nobody bats an eye. I searched the C# standard library for
"Session", and found some 12 classes with that name:
<Screen Shot 2016-01-30 at 3.44.23 PM.png>
These "standard library" classes not only potentially shadow
programmer-defined types, *they also shadow each other*. But because the
C# language has a robust namespacing system, the chances of there being
more than one thing called "Session" in scope in your program (or for that
matter, when developing the standard library itself) is quite small, so
it's a non-issue.
Now we return to the question of dropping the NS prefix, which will rename
thousands of classes in a typical program that has `import Foundation`, in
a way that potentially (let's be honest. More like "probably") shadows one
or more programmer-defined classes. Our review criteria is:
Is the problem being addressed significant enough to warrant a change to
Swift?
No, the elimination of 2 characters is not significant enough of a problem
to break all Swift programs, let alone to introduce literally thousands of
new opportunities for shadowing.
To its credit, the proposal acknowledges this, and offers a concession:
Note that this removal can create conflicts with the standard library. For
example, NSString and NSArray will become String and Array, respectively,
and Foundation's versions will shadow the standard library's versions. In
cases where the Swift 3 names of standard library entities conflict with
prefix-stripped Foundation entities, we retain the NS prefix. These
Foundation entities are: NSArray, NSDictionary, NSInteger, NSRange, NSSet,
and NSString.
But of course this needlessly draws a distinction between NSString et al
and the "normal" Foundation types, and what's more it draws that
distinction based on the present composition of the Swift standard library
and the present composition of Foundation. But we have already decided not
to guarantee the source compatibility of the standard library, so what
happens when that composition changes? Will we then go back and tweak
which classes get NS prefixed to them again?
In my view, if Swift's namespacing is not good enough to let us drop the
NS in NSString it is not good enough to drop any prefix. If we believe
that a programmer will struggle to distinguish between Swift String and
Foundation String then we should expect them to struggle for any two
classes in any two frameworks, and this is special pleading on the part of
Foundation. C#'s libraries declare **twelve** different `Session`s and
nobody bats an eye, but we have two types share a name and everybody loses
their minds? Our namespacing is not good enough to kill the prefix, period.
We should either drop these prefixes or we should not; because the claimed
motivation–that we have "good enough" namespacing in the language now–is
either true or it is not. This proposal admits that it is not, and tries
to drop the prefixes anyway. I believe that is a mistake.
I certainly support the goal of eliminating these prefixes, they are ugly,
they need to be killed, and namespacing is the right solution. But we must
not jump out of the plane until we are very sure our parachute is in
order. In Swift 3 it is not.
I do think the bulk of the proposal is fine, and I apologize for using
quite stark language for such a small paragraph in an otherwise reasonable
proposal, but I think the problem buried in here is quite serious and is
being overlooked.
Drew
On Jan 22, 2016, at 3:02 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
Hello Swift community,
The review of SE-0005"Better Translation of Objective-C APIs Into Swift"
begins now and runs through January 31, 2016. The proposal is available
here:
https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md
Reviews are an important part of the Swift evolution process. All reviews
should be sent to the swift-evolution mailing list at
https://lists.swift.org/mailman/listinfo/swift-evolution
or, if you would like to keep your feedback private, directly to the
review manager. When replying, please try to keep the proposal link at the
top of the message:
Proposal link:
https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md
Reply text
Other replies
<GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.
goes into a review?
The goal of the review process is to improve the proposal under review
through constructive criticism and, eventually, determine the direction of
Swift. When writing your review, here are some questions you might want to
answer in your review:
- What is your evaluation of the proposal?
- Is the problem being addressed significant enough to warrant a
change to Swift?
- Does this proposal fit well with the feel and direction of Swift?
- If you have used other languages or libraries with a similar
feature, how do you feel that this proposal compares to those?
- How much effort did you put into your review? A glance, a quick
reading, or an in-depth study?
More information about the Swift evolution process is available at
https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,
-Doug Gregor
Review Manager
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution