Are there any possible explicit uses of instances (values) of empty tuples (), i.e., of instances of typealias 'Void'?

后端 未结 2 1645
情书的邮戳
情书的邮戳 2020-12-12 00:42

Question:

  • Are there any possible explicit uses for the empty tuple (), as a value (and not as a type) in Swift 2.x?
2条回答
  •  忘掉有多难
    2020-12-12 01:38

    There are lots of places that () can be useful when playing around with "CS" problems, which often have the form "implement X using Y even though you really already have X." So for instance, I might say, implement Set using Dictionary. Well, a Dictionary is a Key/Value pair. What should the type of the Value be? I've actually seen this done in languages that have Dictionaries but not Sets, and people often use 1 or true as the value. But that's not really what you mean. That opens up ambiguity. What if the value is false? Is it in the set or not? The right way to implement Set in terms of Dictionary is as [Key: ()], and then you wind up with lines of code like:

    set[key] = ()
    

    There are other, equivalent versions, like your Optional<()>. I could also implement integers as [()] or Set<()>. It's a bit silly, but I've done things like that to explore number theory before.

    That said, these are all almost intentionally impractical solutions. How about a practical one? Those usually show up when in generic programming. For example, imagine a function with this kind of form:

    func doThingAndReturn(retval: T, f: () -> Void) -> T {
        f()
        return retval
    }
    

    This isn't as silly as it sounds. Something along these lines could easily show up in a Command pattern. But what if there's no retval; I don't care about the return? Well, that's fine, just pass a () value.

    func doThing(f: () -> Void) {
        doThingAndReturn((), f: f)
    }
    

    Similarly, you might want a function like zipMap:

    func zipMap(funcs: [(T) -> U], vals: [T]) -> [U] {
        return zip(funcs, vals).map { $0($1) }
    }
    

    This applies a series of functions that take T to values of type T. We could use that even if T happens to (), but we'd have to generate a bunch of () values to make that work. For example:

    func gen(funcs: [() -> T]) -> [T] {
        return zipMap(funcs, vals: Array(count: funcs.count, repeatedValue: ()))
    }
    

    I wouldn't expect this to come up very often in Swift because Swift is mostly an imperative language and hides its Void in almost all cases. But you really do see things like this show up in functional languages like Scala when they bridge over into imperative programming.

提交回复
热议问题