Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variables of type void

Tags:

types

void

swift

So I know that Void is used to indicate that a function doesn't take or return a value. In Swift, Void is actually a type alias for the empty tuple ().

Interestingly (in Beta 6), you can even declare variables of type Void:

var x: Void
println(x)
x = test()

func test() {}

These statements are all legal. The println() prints "()".

So far I couldn't figure out what else this can be used for. Why would you need a variable that can't hold any value? Does anyone know a practical use for this, or is this just one of the quirks of Swift?

like image 499
Atomix Avatar asked Aug 25 '14 12:08

Atomix


People also ask

What is void * type in C?

The void type, in several programming languages derived from C and Algol68, is the return type of a function that returns normally, but does not provide a result value to its caller. Usually such functions are called for their side effects, such as performing some task or writing to their output parameters.

What is a void variable in Java?

The void keyword specifies that a method should not have a return value.

Can a variable be declared void in C?

You can have a pointer to void ( void * ) but there is no such thing as a void variable.


3 Answers

Note: This is a crosspost of my reply on the cross-posted question in the Apple Dev Forums.

It's because Swift seems to be a little academically favourable (it's one of Swift's plus points for me! :-) ).

A mathematical function is a relation between some inputs (the arguments) and some outputs (the return values). Instead of defining a whole class (e.g. "subroutine" or "procedure") for which this doesn't apply (no output, specifically), Swift simply defines a "procedure" as a relation with some set of inputs (possibly empty) and an empty set of outputs.

There are some benefits to it, though, albeit uncommon (at least until functional programming becomes the more dominant style in the language and the community). A little example:

infix operator ~~ { precedence 10 associativity right }
func ~~(l: A -> B, r: A) -> B {
     return l(r)
}

let productsSoldIn2014 = productOfSales ~~ salesInYears ~~ [2014]
let salespersonsInvolvedIn2014Sales = salespersonsOfSales ~~ salesInYears ~~ [2014]

fireSalespersons ~~ salespersonsOfSales ~~ salesInYears ~~ [2014]   // Awful companies only.

func salesInYears(_ y: [Int]) -> [Sale] { … }
func productsOfSales(_ s: [Sale]) -> [Product] { … }
func salespersonsOfSales(_ s: [Sale]) -> [SalesPerson] { … }
func fireSalespersons(_ s: [SalesPerson]) -> () { … }               // The appended arrow and null tuple can be left out.

I've defined a "chaining" operator ~~ (think of a bending chain) which, right to left, pushes a value through the chain. With some appropriately named functions, we can declaratively define the values we need. (With lazy collections instead of arrays, we approach Haskell paradigms. Unless I'm mistaken, ~~ is here an identity monad. Or it's just a composition operator.)

The third statement (after the two lets) fires the salespersons that sold anything in the year 2014. Note though that ~~ wants to return "fireSalespersons"'s value (to continue the chain on the left, which here isn't present), which in Swift is valid—it's just the null tuple and we discard it. There's no reason why functions without return value shouldn't work with the operator (without overloading it).

By the way, this is also valid:

increaseCEOBonus(35000) ~~ fireSalespersons ~~ salespersonsOfSales ~~ salesInYears ~~ [2014]      // Really awful companies only.
//         () -> ()  ~~  [Salesperson] -> ()  ~~  [Sales] -> [Salesperson] …

func increaseCEOBonus(amount: Int)() { … }

In this example, the leftmost chain is value-less—it's still left after right, but there aren't any values passed to the left. I wouldn't recommend this use though, it's better to simply enumerate each of them on a separate line.

To return to your question, since "nothing" can be consumed (via arguments), it'd be silly to explicitly prohibit "nothing" to be assigned to a variable—arguments are variables.

P.S.: Before anybody asks: yes, I did want to have an excuse to make a contrived example; it was just to test my ability to write complex types.

like image 68
Constantino Tsarouhas Avatar answered Nov 08 '22 21:11

Constantino Tsarouhas


I came across a practical example where this is useful in dealing with generics. I have a generic class which creates a wrapper around async tasks. One of the methods of the class allows for posting of a result.

Breaking it down to a simplified example:

class Foo<T>  {

    var x : T?

    func finishWith(result:T) {
        x = result
        // do more stuff here as a side effect of posting the result
    }
}

The question is if you need a Void result i.e.

var foo = Foo<Void>()

How do you call the finishWith:result method?

You can either create a variable with value of void or use '()' as a literal void value:

foo.finishWith(result: ())
like image 37
Dale Avatar answered Nov 08 '22 19:11

Dale


Probably slightly more useful is the Void? type, which can be used to store e.g. a try? statement that doesn't return a value but you still want to check the success of:

let someString = "foo"
let saved: Void? = try? someString.write(toFile: "somePath", atomically: false, encoding: .utf8)
if (saved == nil) {
    print("didn't save")
}
like image 3
John Montgomery Avatar answered Nov 08 '22 19:11

John Montgomery