Interesting discussions on Swift Evolution

Thought I’d share a few highlights:

newtype

One proposal suggests Swift introduces a newtype keyword that adds an extensible derived type that is otherwise identical to the original. For example,

newtype Currency = NSDecimal

creates a Currency type that has all the behaviors of NSDecimal. However, you can’t sum together a Currency with an NSDecimal so there’s type checking, and you can extend the Currency type. It’s specialization without subclassing or adding new storage.

Another spin on newtype creates a kind of type currying:

newtype Counter<A> = Dictionary<A, Int>

The type is partially specified so behavior can be implemented through extensions that applies generically across various dictionaries with arbitrary keys and Int values.

I’m looking forward to seeing where this discussion leads.

self

Another proposal suggested that self be instated as a mandatory prefix instead of permitting context inference. Greg Parker wrote in response:

Note that the `self.property` access in Objective-C was not the preferred design.

The first choice was for bare `property` to work. That turned out to be ambiguous too often because of identically-named ivars. Swift doesn’t have that problem.

The second choice was for bare `property` to access the property, requiring `self->ivar` to access an identically-named ivar. That was not feasible because it was incompatible with too much existing source code. Swift doesn’t have that problem either.

precondition vs assert

Dave Abrahams responded to a proposal about renaming assert and precondition with some insights that I immediately bookmarked in my notes file:

Here’s some rationale that may be missing.  The two functions have distinct roles:
– assert: checking your own code for internal errors.
– precondition: for checking that your clients have given you valid arguments.

It’s actually important to distinguish these two cases because the second one demands public documentation while the first does not.

For example: in Swift’s standard library we promise never to allow memory errors unless you call (Obj)C code or use an explicitly labeled “unsafe” construct.  On the occasions where we need to do a check on the client’s parameters to avoid causing a memory error when we’re given invalid arguments, we document the requirements on the arguments as a precondition, and use (our equivalent of) precondition() to check it.  We also have a bunch of internal sanity checks to make sure our assumptions about our own code, where the type system doesn’t already guarantee them, are correct.  For those, we use (our equivalent of) assert(), because we don’t want to slow down *your* code as an artifact of our development process (the use of sanity checks).

Here are a couple of concrete examples:

/// A collection whose elements are all identical `Element`s.

public struct Repeat<Element> : CollectionType {
  ...
  /// Access the element at `position`.
  ///
  /// - Requires: `position` is a valid position in `self` and
  ///   `position != endIndex`.
  public subscript(position: Int) -> Element {
    _precondition(position >= 0 && position < count, "Index out of range")
    return repeatedValue
  }
}
extension String.UTF8View {
  ...
 private func _encodeSomeContiguousUTF16AsUTF8(i: Int) -> (Int, UTF8Chunk) {
    _sanityCheck(elementWidth == 2)
    _sanityCheck(!_baseAddress._isNull)
 
    let storage = UnsafeBufferPointer(start: startUTF16, count: self.count)
    return _transcodeSomeUTF16AsUTF8(storage, i)
  }
}

In the first example, we have a precondition that the client doesn’t index past the end of the collection. In this case we’re not strictly bound to check it because we’re not avoiding a memory error,* but we do check it as a service to our clients; it will help them find their bugs sooner.

In the second example, this is a private function that is meant to be called only on a code path where we’ve ensured elementWidth == 2 and _baseAddress is not null (_sanityCheck is the stdlib’s equivalent of assert). That is in fact how it is being used, but we want to ensure that ongoingly. For example, we don’t want someone to add code later that uses it incorrectly. Since we run our tests in both debug and release and we have decent test coverage, the assertions are very likely to fire if that should happen.

You might think from the above that assert() only gets used in private methods and precondition() only gets used in public methods, but that’s not the case; you could inline any private method into the body of the public method it implements, and doing sanity checks there would still make sense. Precondition checks occasionally appear in private methods, too. The simplest example is where duplicated precondition checking code is factored out of a bunch of public methods and into a single private helper.

*  Note that some preconditions actually can’t be checked, so having a rule that all preconditions must be checked isn’t tenable.

14 Comments

  • I’m loving these and would be delighted if you kept it up. Just the basic formatting you’ve added is a nice touch too. That said, any chance you could add the footnote references by the asterisk?

    • 1 Added

  • I could get behind the mandatory “self.”-prefix, not just for properties but functions as well. At my last client, it was part of the coding standard; we figured it would make it very clear what was and wasn’t a class member. It’s a bit Java-esque. It does make for more verbose code, though.

    • I think it works better as a voluntary practice than a language-mandated feature

      • Agreed. If it’s made mandatory, they need to put a “self” key on the keyboard.

        • IMO, it should be automatic. i.e. if you start using the name of a property, auto-complete should prefix it with “self.”. And/or present a disambiguation fix when there is a local var or parameter of the same name.

          The problem with making this optional is that too many options (and too many keywords) make for a mess of a language. Good form needs rules. Look at the mess C++ is in… everyone’s code looks entirely differently.

          When you use ‘self.myProperty’ it is absolutely unequivocal. Anyone reading it knows ‘whatProperty’ is, and who it belongs to. There’s no extra scan required, and the code becomes not just more readable, but more understandable. The reader is able to form a much better mental picture of the processes, and that’s really what the code should be about.

      • While I’m wish-listing… I’d love to see a formal, easy way to visually mark private methods in such a way that they can be seen in code for what they area. Underscores are obviously undesirable. (Also: they are devil-tools.)

        Again, being able to quickly and accurately form a mental image of the algorithm/process is vital. And we all know that writing code is easier than reading it.

        I’ve been doing the following in Obj-C for a long time. It’s not the ideal solution, but it’s the lesser of evils. And it lets me know immediately what I’m working with:

        [self priv_DoSomething];

        as opposed to:

        [self doSomething]; // Where does this come from? This file? This project? A library? Alpha Centauri?

        Obviously, something more formal and standardised than this would help.

        (FWIW, IDE highlighting isn’t enough. IMO, the ability to distinguish between public and private code should be built in to the text itself, visible in any text editor, not just as an adornment in a particular IDE.)

  • I’m all in favour of mandatory ‘self.’ prefixing. Clearly differentiating between local vars and properties/ivars is a basic requirement for writing solid, readable, maintainable code. I shouldn’t have to go check my list of properties or make assumptions, just to be able to read code. The use of ‘self’ makes it clear what I am doing.

  • On first impression I like the idea of newtype. There are times when subclassing a class or extending a type may not be the right approach. But what happens if you extend the original type after creating the newtype? Do they go their separate ways after the newtype is created?

  • […] Erica Sadun quotes Dave Abrahams: […]

  • Erica, Thanks for collecting these! This is a great little reference. Any chance you could link to the mailing list discussions you reference here? I’d love to dive deeper on these topics.

  • […] Sadun, 原文链接 […]