0

Why does Swift use this function notation:

func greet(person: String, day: String) -> String {
    return "Hello \(person), today is \(day)."
}

Like, I don't get why it uses the small arrow -> notation to specify return type. func identifier() -> Type instead of something more sensible, like Type identifier().

I have seen similar notation in Haskell, but in Haskell it makes sense to me because Haskell uses curried functions, so the arrow represents function currying. In swift it just seems verbose and superfluous.

What was the reasoning behind this design choice?

  • 3
    What would you use instead? And why do you think -> is related to currying? It's simply the function type constructor in Haskell and it seems to play a similar role in Swift. If I had to guess, they are following (some of) the conventions of (some) functional languages. – Andres F. Dec 15 '16 at 1:52
  • 1
    (BTW, this question seems hard to answer unless we find a design document for Swift and/or one of its designers decides to answer :) ) – Andres F. Dec 15 '16 at 1:56
  • 2
    Also, please do not cross-post to StackOverflow. – Andres F. Dec 15 '16 at 1:57
  • 4
    "something more sensible, like Type identifier()" - more sensible if you only experience C syntax – Caleth Dec 15 '16 at 15:14
  • Assume Swift used the "sensible" Type identifier() notation. How would you write let closure: () -> Type? let closure: Type()? – Alexander Apr 30 '17 at 4:49
5

tl;dr: Mathematical notation.

In Mathematics, a function is map that takes things from one "Space" (a set) to another (another set). i.e. f could be a function taking elements from the natural numbers to the letters in the alphabet. The type of this would be f:Real numbers -> Letters another example might be g(x) = x + 1. the type of this function might be g:R -> R. (where R are the real numbers.)

But theres a reason mathematicians write it like this: its intuitive. The arrows indicate how values are changing. You're going from elements in a first set to elements in a second. so for your example, you might say in your head: greet is a function that takes the tuple of two Strings to another String.

now, why should types come after the variable names? My guess is its for the same reason:

In mathematical proofs you often say things like "let m be any integer" which looks oddly like let m:Int.

That tends to sound better and more formal than the alternate "An Integer m has some value" : int m;

  • You are wrong. In maths, mapping notation is for specifying the image of an input under the mapping, not its "type." f : x —> x + 1 – theonlygusti Dec 15 '16 at 1:02
  • 3
    No, I'm not wrong. You're right too though. You can use the notation for both. en.wikipedia.org/wiki/Function_(mathematics)#Notation – Joe Daniels Dec 15 '16 at 1:04
  • 1
    Domain (X) and Codomain(Y), correct. X and Y are Mathematical sets. I've not a category theorist or type theorist, but the distinction between Types and Sets is negligible for this audience. – Joe Daniels Dec 15 '16 at 1:17
  • 1
    Also, since we're being pedantic, "each element of Y is an image of an element of X under the function f" is the definition of Range, not Codomain. Ex: the codomain Y may contain an element y for which there is no element x within X such that f(x) = y – Joe Daniels Dec 15 '16 at 1:19
  • 2
    @JoeDaniels Types can easily be encoded as Sets, so there is no need for a distinction – Caleth Dec 15 '16 at 15:11
3

Like, I don't get why it uses the small arrow -> notation to specify return type. func identifier() -> Type instead of something more sensible, like Type identifier().

This comment suggests to me that this question is really just meant to bash Swift for not being C/C++/Java. It's quite likely that nothing anyone could answer you will satisfy you.

In Swift, unlike C, C++ and Java, it's very common place (and indeed, actually possible) to return functions (closures) from functions.

Consider this example:

func incrementerMaker(startAt start: Int) -> () -> Int {
    var count = start
    return { count += 1; return count }
}

let incrementer = incrementerMaker(startAt: 0)

print(incrementer()) // 1
print(incrementer()) // 2
print(incrementer()) // 3

For one, take note that this is a curried function. It's not as common in Swift as in Haskell, but it's certainly a possibility.

All instance methods are curried functions. This is pretty handy, because it means you can pass them around without yet binding them to act on a specific instance. Consider the function String.uppercased():

print(type(of: String.uppercased)) //prints: (String) -> () -> String

The type (String) -> () -> String makes it very clear what series of steps the function must undergo until it produces its final result. Firstly, it expects to be invoked with a single String argument. This binds the self instance, and returns an instance method of type () -> String. This tells you it expects to be invoked with no arguments, producing a String result.

How would that type signature for that function look like, given your "sensible" Type identifier() syntax? The function being returned is anonymous, so there's no identifier, and unlike C or C++, it's not a function pointer, so there's no * symbol to be used, either.

  • 2
    Interesting. I haven't yet done any work with swift, but that is a very nice syntax for returning a closure. And a nice way of handling the distinction between bound and unbound instance methods. – Jules Apr 30 '17 at 14:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.