关于Swift 进化的趣味探讨

原文链接=http://ericasadun.com/2015/12/15/interesting-discussions-on-swift-evolution/
作者=Erica Sadun
原文日期=2015/12/15
译者=小袋子
原始翻译文章发布在:swift.gg


记得我曾分享过一些想法和建议,比如:
newtype


一个是建议 Swift 推出一个 newtype 的关键词,它可以添加完全不同于原生的可扩展的派生类型。例如:

newtype Currency = NSDecimal

创建一个拥有所有 NSDecimal行为的 Currency 类型。然而,你不能通过NSDecimalCurrency 加起来,这样就有类型检测了,并且你可以扩展 Currency 类型。这样看起来就更加专业化,因为不需要子类化或者添加新存储。

newtype 的另一个特性是创建一类类型的局部套用:

newtype Counter = Dictionary

类型是部分指定的,因而它的行为能够通过扩展被继承,适用于通过任意的键和 Int 值穿过不同的字典。

我期待这个讨论会带来些什么。

self

另外一个提议是将 self 作为一个强制的前缀,取代上下文的语境推理。Greg Parker在回复中写道:

注意到在 Objective-C 存储 self.property 并不是优选的设计。

最好的选择是让 property 单独工作。这往往由于同名的变量而变得有歧义。而 Swift 没有这样的问题。

第二种选择是暴露property去访问属性,这需要self->ivar去访问同名变量。这是不可行的,因为在有太多源代码的情况下会产生冲突。Swift 没有这样的问题。

前置条件与断言

Dave Abrahams 回复了一个有关于重命名断言和前置条件的建议,我立刻将其中的一些深刻见解记在笔记本上:

这里是一些可能丢失的逻辑依据。这两个函数有不同的规则:
– assert:检查你内部的错误代码
– precondition:为了检查你客户端已经给你的有效参数

分辨两者的区别是很重要的,因为第二个需要公共文档而第一个不需要。

例如:在 Swift 的标准库中,我们保证永远不会出现内存错误,除非你调用 (Obj)C
代码,除非你使用一个明确地标着“unsafe”的结构。我们需要去检验客户端参数,为了避免给了非法的参数引起内存泄露,我们要在参数中文档化这些需求作为前置条件,并且使用(我们相当于)precondition() 去检验它。我们还有一系列的内部合理检查,用以确定我们代码假定的正确性,而类型系统还不能保证这个代码的假定。由于这些原因,我们使用(我们相当于)assert(),因为我们不想把降低你的代码速度作为我们开发过程的一部分(使用合理的检查)。

下面是几个具体的例子:

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

public struct Repeat : 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)
  }
}

在第一个例子中,我们有一个判断客户的 collection 没有越界的前置条件。在这个例子中,我们没有进行严格地检查,因为我们没有避免内存错误,但是我们确实把这个作为客户端的一项服务;这可以让他们快速发现他们的 bug 。

在第二个例子中,这是一个私有的函数,它只能在我们保证 elementWidth == 2 和 _baseAddress 不为 null 的条件下调用(_sanityCheck 在 stdlib 下等价于assert)。这就是它实际上如何被使用的,但是我们想要确保持续性。例如,我们不想要一些人在之后添加错误使用的代码。因为我们在 debug 和 release 的环境下运行我们的测试,并且我们有得体的测试覆盖,因此断言很可能在某处被调用。

你可能从上面的文章得出 assert()只能在私有方法中使用,而 pecondition() 只能在公共方法中使用,但是事实却不是这样的;你可以内联任何私有方法到继承的公有方法的方法体内,那么合理的检查依然会有意义。前置条件检查也会偶尔在私有方法中使用。最简单的例子是复制的前置条件检查代码是一系列公有方法的一部分,并且成为单个的私有助手。

*应注意一些前置条件确实不能被检查,因此所有前置条件都应该被检查的规则是不可能存在的。

你可能感兴趣的:(关于Swift 进化的趣味探讨)