Having -> denote a return variable has the benefit that you the syntax "a -> b" is non-ambiguously a function type.
For example, a function that accepts a function as an argument can be written:
fn foo(f: int -> string)
Or if the argument name isn't needed in this context (e.g. think interface declarations):
fn foo(int -> string)
If you see ":" as meaning "has type", then using it for a return type isn't necessarily more consistent, because it's not the function that has a type.
In functional programming (the origin of this syntax),
add(a: int, b: int): int
can be read as a function 'add' when applied to the parameter tuple (a: int, b: int) has type int, I believe Ocaml, SML, actually support this syntax, whereas '->' (arrow) is a function type constructor in functional programming with 'A -> B' denoting a function from A to B. The type of add by itself in a language like Haskell would be:
You can certaintly have tupled function arguments in SML/Ocaml, in fact that seems to have been the more common style there, whereas Haskell uses curried functions more commonly.
As far as the original sugestion, using '->' (arrow) to denote a return type (like Rust) is nonsense in a functional language and kind of butchering the functional inherited syntax IMHO.
I've never heard of OCaml tuples being more common in arguments. If anything, my impression is they're discouraged (in OCaml, not SML) as a replacement for curried arguments. E.g. see [1].
> is nonsense in a functional language
SML/OCaml and Haskell all use ->, so I'm not sure what you mean by this?
It's not inconsistent, just terser. You could say that "fn" declares a function by name; the type of foo is int -> str.
In Haskell, this is written:
foo :: int -> str
Of course, Haskell is based on lambda calculus, so multiple arguments are just a generalization of partial function application:
foo :: int -> int -> str
(A function taking two int arguments and returning a string, which is indistinguishable from a function that takes a single int and returns a function that takes a single int and returns a string.)
I don't think it makes sense to say `fn read(s: string) -> int` as in Rust though. If an arrow were used in such a function declaration, it should probably look something more like:
fn read: (s: string) -> int
As another commenter has indicated, `fn read(s: string): int` states that `read(s)` is of type `int`, which is logical.
The thing about adopting the ASCII Art pseudo arrow is that it bakes in an assumption that the dash character lines up vertically with the point on the angle bracket character. This simply isn't the case in plenty of fonts. So it often looks like crap if you pay attention.
Which fonts does it not look good in? Haskell, Rust, Swift, Ocaml, and I'm sure some others, all use this notation. And I've never seen the '->' look odd in any font I've ever used.
I just went to the Rust homepage and clicked until I found an example of a function. It's being presented in Monaco where the dash is noticeably higher than the centre of the angle bracket.
Depends on the language but in Haskell, the (->) arrow is a function type constructor (i.e. constructs function at type level) where a -> b constructs a function type from a to b.
This is often chained to produce functions that 'take multiple arguments'. i.e. a -> b -> b. I put that in quotations because in reality all functions take only one argument, this is called currying. It gives functions flexibility in that you can partially apply them at will.
In languages like Rust and Swift, the syntax is (a: A, b: B) -> B. Because these languages are "uncurried", they use the syntax of uncurried functions. Meaning, they cannot be readily partially applied.