Are there any possible explicit uses for instances (values) of empty tuples (), that is, instances of type "Void"?

Question

  • Are there any possible explicit uses for empty set () as a value (and not as a type) in Swift 2.x?

I know that these empty tuples can be used in the standard sense to define void functions. When I mistakenly defined a variable with an empty value tuple var a = () (of type () ), I began to wonder if these empty tuple values ​​can be used in some context. Does anyone know about such an application?


Example: a possible application with an array and options?

As an example, we can create an optional array of empty tuples, which, of course, can only contain nil or () :

 /* Optionals */ var foo: ()? = () print(foo.dynamicType) // Optional<()> var arr : [()?] = [foo] for i in 2...8 { if i%2 == 0 { arr.append(nil) } else { arr.append(foo) } } print(arr) // [Optional(()), nil, Optional(()), ... ] 

With a small amount of memory in an empty tuple, this may seem neat for managing micro-memory for “logical zero / non-zero”, but since the Bool type has the same small area, I can't see any direct use here, even in the script (unlike) that we really need to optimize bit-low in our operations.


Maybe I'm just chasing my own tail with some unusable applications, but anyway: are there any possible explicit uses for these creatures void () (as instances, not types)?

+2
source share
2 answers

There are many places that () can be useful when playing with "CS" issues, which often take the form "implement X using Y, even if you really have X." So, for example, I can say implement Set using Dictionary. Well, a dictionary is a key / value pair. What should be the type of value? I actually saw this in languages ​​with dictionaries, but not with sets, and people often use 1 or true as their value. But this is not exactly what you mean. This opens up ambiguity. What if the value is false? Is it bundled or not? The correct way to implement Set in terms of a dictionary is [Key: ()] , and then you end the lines of code, for example:

 set[key] = () 

There are other equivalent versions, for example your Optional<()> . I could also implement integers like [()] or Set<()> . It's a little stupid, but I did such things to research number theory earlier.

However, these are all almost intentionally impractical decisions. How about practical? Usually they appear when developing common programs. For example, imagine a function with this form:

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

This is not as stupid as it seems. Something along these lines can easily be displayed in the Command pattern. But what if there is no retval; I don't care about returning? Well, that’s fine, just pass the value () .

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

Similarly, you may need a function like zipMap :

 func zipMap<T, U>(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 this even if T happens to () , but we need to create a bunch of () values ​​for this to work. For instance:

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

I would not expect this to happen very often in Swift, because Swift is basically an imperative language and hides its Void almost all cases. But you really see things that appear in functional languages ​​like Scala when they go into imperative programming.

+2
source

Suppose you have two functions that overload the same name:

 func foo() func foo() -> Int 

The first returns nothing, the second returns some value. Attempting to call any of them in most cases will lead to a compiler error about ambiguity.

 foo() let a = foo() 

You think that the compiler would know that the first call uniquely refers to the first function, because it does not accept any return value. But in reality, the return type of the function without the declared return type is Void or () . So, the first call is actually more like this:

 let _ = foo() 

And if there is no annotation for the discarded lvalue, the compiler cannot deduce for which foo to call. You can use explicit type annotations to disambiguate:

 let b: Void = foo() let c: Int = foo() 

Well, this is not a very large or common use case for Void , because this is a situation in which you tend to avoid getting hit first. But you asked to use ... and use () as the value, not just the type, because you can get it from b after the assignment (for all the good things you do).

Just beware when you dig deep into Void , Void also looks at you. Or something like that.

+2
source

All Articles