4
$\begingroup$

What makes it hard for compilers/interpreters that we need to tag the function definition with keyword fn/fun/func/function?

I can understand that types for numbers: int, int32, float32, float64... are required. Otherwise, how will one figure out difference between 1 and 1.0 and "1" and so on.

But functions are only defined as function name(param-list) { body } and called as name(args); With programming languages differing on what to put in the signature/declaration line (what is that called?)

fn sayHi() { }
fun sayHi() { }
func sayHi() { }
function sayHi() { }

Why cannot we have:

sayHi() {}

What makes this complicated or impossible?

$\endgroup$
8
  • 1
    $\begingroup$ In sh, you can't have a function keyword and have to define functions like you describe with just the name. bash and zsh added the ability to also use function keyword to make the code clearer to read. $\endgroup$
    – Chris Dodd
    Sep 29 at 11:51
  • $\begingroup$ Is it worth pointing out that in some languages like C you can just say void MyFunction() {} and it recognises it as a function. So I don't think it's hard for a compiler/interpreter to parse a function, it just might not be as readable on some languages. $\endgroup$ Sep 29 at 12:58
  • $\begingroup$ @Seggan I don't think it does; OP isn't asking about using the return type as a prefix, they're asking about having no prefix at all, which is much different. $\endgroup$ Sep 29 at 13:30
  • 1
    $\begingroup$ @TomTsagk: Just because one language did it doesn't mean it's not a terrible idea. In fact, the syntax of C -- and notably of function declarations -- is fairly problematic in general, requiring the maintenance of a symbol table when parsing, and leading to the Most Vexing Parse issue. $\endgroup$ Sep 29 at 13:41
  • $\begingroup$ @RydwolfPrograms the answers there can be mostly applied here too $\endgroup$
    – Seggan
    Sep 29 at 14:05

6 Answers 6

11
$\begingroup$

The short answer here is that we don't need to tag functions in the way you described. The C family of languages, for example, typically does something like

type functionName(args...) {...}

where there is no fn, function, func, or anything similar.

Some languages, like Haskell and OCaml, allow for an even more terse syntax. In both languages, you can create a function with something like

let myFn arg1 arg2 ... argN = ...

and you could call it later just by writing

myFn 10 11 12 ... 50

(imagine our function accepts natural numbers).

Depending on the language and the grammar, the function keyword might be there to avoid ambiguities and simplify parsing. Given enough engineering effort, though, I would assume it to be possible for many languages to get rid of their respective function keywords. So, in my opinion, the answer boils down to this: those keywords are there to help you, not the compiler.

Here is another example, in the untyped lambda calculus. I am going to leave out the $\lambda$ symbol (which is equivalent to fn or func in other languages, but not necessary for parsing). You try to tell me what is going on.

n.f.x.n(g.h.h(g f))(u.x)(u.u)

Admittedly, this would be difficult to unpack in normal lambda calculus, but in this form, it is even harder. (It is the predecessor function for Church encoded numerals, if you're curious).

Anyway. It is there to help you, not the compiler.

$\endgroup$
4
  • $\begingroup$ λ is the name of the function. The name is anonymous. Thus λx.t takes in x as a param and returns t. Similar case in javascript would be x2t(x) { return t; } or x2t = x => t. I am talking about using a tag for describing "what follows is a function" which haskell, ocaml already don't have. If those languages had such a tag it would be something like f(λx.t) and then you would be omitting f because that denotes a function. $\endgroup$
    – Anubhav
    Sep 29 at 20:13
  • 3
    $\begingroup$ @Anubhav I'm not sure what you mean. If $\lambda$ was the name of the function, then it could not be anonymous by definition. The $\lambda$ is just syntax, and quite literally means that what follows is an anonymous function. Also, both Haskell and OCaml do have symbols for just this purpose; OCaml uses fun, and Haskell uses \ (because it looks similar to a $\lambda$ if you squint a little). Its just that you don't actually need to use those to define functions. $\endgroup$ Sep 29 at 20:56
  • $\begingroup$ Take toString for example. Takes a number, returns the string representation of the number, somthing like toString :: num -> string Suppose f is used to mark a piece of code in haskell as a function. Then the example above will become, f toString :: num -> string. I am talking about can haskell do without f (which I think it alread does). This but in languages like JS, Go, Kotlin, Rust.... $\endgroup$
    – Anubhav
    Sep 29 at 21:36
  • $\begingroup$ @Anubhav JS, Go, Kotlin, Rust, and others could remove the f. It would not make it too difficult for the compilers. It may introduce some difficult parsing edge cases, but that is a problem we already deal with. I believe the reason language designers keep the f is to make the language more readable for you, the programmer. $\endgroup$ Sep 29 at 21:57
3
$\begingroup$

Your code

sayHi() {}

does work in C. That's a function that returns an integer. It also works in sh if the body is not empty. More complicated languages usually don't support this, probably only because of ambiguity. It's too similar to something like:

while(1) {}

Actually, many languages, even if once required a function keyword, now supports something like this:

sayHi = () => {}

But someone could argue that two operators may not be simpler than one keyword. It is supported because we have more possible "differences" now, that is the option to not assign a function to a name.

As more features are made into programming languages, there could be more variations of functions, say generators, virtual, inline, ... I don't think anyone would want to go back and think of removing every tag. They only simplify a tag to an operator because it is used too frequently. But if someone really wants so, I'd argue something that is consist of a name, a list and a body isn't intuitively only possibly a function. Languages with the simplified syntax may have excluded the other possibilities in the design. Many languages have high order functions, but some simple languages may choose to never support them. And using = in place of something like => may mix the definition with array element assignment, but that's not a problem in functional programming languages. And I think ambiguity is the only valid reason.

$\endgroup$
1
  • $\begingroup$ while is a keyword. 1 is an arg not a param. $\endgroup$
    – Anubhav
    Sep 29 at 20:05
2
$\begingroup$

Generally speaking, error reporting is much better if you have function definition keywords. The reason is that the compiler can use them as anchor and do better guesswork what a malformed input likely should have meant.

In some languages, it is simply not possible in general to disambiguate field and function definitions without the keyword, because they can have forms that are, otherwise, completely identical. Tyr is such a language. It offers, inspired by Scala, a function definition syntax that uses a = followed by a single expression. Thus, the syntax for fields and functions without parameters is exactly the same except for the leading keyword. If one would drop such syntax, the parser would simply need to perform a lookahead and use the { equivalent as keyword for functions. It does not really make a difference.

$\endgroup$
4
  • 1
    $\begingroup$ JS doesn't need function in class methods or object fields. $\endgroup$
    – Anubhav
    Sep 29 at 20:06
  • 1
    $\begingroup$ @Anubhav: What syntax would allow writing a function in JS without using either either the keyword function or the token sequence => which is a shorthand that is used exclusively for writing functions? $\endgroup$
    – supercat
    Oct 3 at 17:31
  • 1
    $\begingroup$ const obj = { add(a, b) { return a + b; } }; class Human { constructor() {} squeak() { return "meh!"; } } both of these don't require function keyword. $\endgroup$
    – Anubhav
    Oct 5 at 11:45
  • $\begingroup$ How long have those constructs been in JS? Having an object initializer use braces as the outer delimiter but use a member name that isn't followed by a colon seems like a gratuitous syntactic variation with which to burden implementations. $\endgroup$
    – supercat
    Oct 5 at 19:32
2
$\begingroup$

Generally, languages which require this do so for one of two reasons:

  • The grammar would be ambiguous if function definitions didn't include a keyword like this,
  • Otherwise, if the grammar wouldn't actually be ambiguous, it would constrain future additions to the language syntax, and be harder for people to read.

Consider Javascript: the following code cannot define a function, because it is instead a sequence of statements (a function call, then a block):

foo()
{
    bar();
}

Consider Python: the following code cannot define a function, because it is instead a statement (a function call) which has a type annotation (which is allowed to be an arbitrary expression):

foo(): bar()

If this had been allowed as a function definition in Python originally, then it would have created this problem when the designers later wanted to add type annotation syntax to the language.

$\endgroup$
3
  • $\begingroup$ What are you talking about? foo() { ... } is a definition. bar(); is an execution because a) ; and b) no following {} $\endgroup$
    – Anubhav
    Sep 29 at 21:31
  • 2
    $\begingroup$ @Anubhav: In javascript, the semicolons at the end of the line are optional. $\endgroup$
    – Chris Dodd
    Sep 29 at 21:51
  • 1
    $\begingroup$ @Anubhav Try it online. $\endgroup$
    – kaya3
    Sep 29 at 22:00
0
$\begingroup$

First off, general purpose languages are always a multitude of trade offs. In some esoteric language, you might not have have functions, let named functions.

Function identifiers are a trade off between brevity and easy identification (for both humans and parsers). I would suggest that ease of identification by humans is, for most languages, not of extreme importance, but at the very least highly important.

$\endgroup$
-2
$\begingroup$

As others point out, we don't need to. All you need is $\lambda x.M$. Syntax like

$$\mathsf{let}\ x\ =\ M\ \mathsf{in}\ N$$ is just convenient syntax for $(\lambda x.N)M$, and, likewise, $$\mathsf{fun}\ f(x_1, ..., x_n)\ =\ M\ \mathsf{in}\ ...$$ is just convenient syntax for $\mathsf{let}\ f\ =\ \lambda x_1. ... \lambda x_n.M\ \mathsf{in}\ ...$ So it's all just about readability and convention.

$\endgroup$
5
  • 1
    $\begingroup$ The $\lambda$ symbol serves the same purpose as a keyword like function. So this doesn't answer the question: why do you need the lambda? Or the let, for that matter? $\endgroup$
    – kaya3
    Sep 30 at 12:43
  • $\begingroup$ @kaya3 You need some syntax to distinguish every syntactic form, that's inevitable. Rather than $\lambda x.M$ one might also just use $x.M$ and then the dot disambiguates. The point I was trying to make is that introduction of functions can be simpler, for example functions can be anonymous. $\endgroup$ Sep 30 at 13:23
  • 1
    $\begingroup$ What makes $\lambda$ inherently simpler than function? $\endgroup$
    – kaya3
    Sep 30 at 14:44
  • $\begingroup$ @kaya3 Lambda does not need to name the function. $\endgroup$ Sep 30 at 15:07
  • $\begingroup$ Neither does function, e.g. in Javascript function() { ... }. $\endgroup$
    – kaya3
    Sep 30 at 17:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .