Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Most programming languages (both dynamically and statically typed languages) have special keyword and/or syntax that looks much different than declaring variables for declaring functions. I see functions as just as declaring another named entity:

For example in Python:

x = 2
y = addOne(x)
def addOne(number): 
  return number + 1

Why not:

x = 2
y = addOne(x)
addOne = (number) => 
  return number + 1

Similarly, in a language like Java:

int x = 2;
int y = addOne(x);

int addOne(int x) {
  return x + 1;
}

Why not:

int x = 2;
int y = addOne(x);
(int => int) addOne = (x) => {
  return x + 1;
}

This syntax seems more natural way of declaring something (be it a function or a variable) and one less keyword like def or function in some languages. And, IMO, it is more consistent (I look in the same place to understand the type of a variable or function) and probably makes the parser/grammar a little bit simpler to write.

I know very few languages uses this idea (CoffeeScript, Haskell) but most common languages have special syntax for functions (Java, C++, Python, JavaScript, C#, PHP, Ruby).

Even in Scala, which supports both ways (and has type inference), it more common to write:

def addOne(x: Int) = x + 1

Rather than:

val addOne = (x: Int) => x + 1

IMO, atleast in Scala, this is probably the most easily understandable version but this idiom is seldom followed:

val x: Int = 1
val y: Int = addOne(x)
val addOne: (Int => Int) = x => x + 1

I am working on my own toy language and I am wondering if there are any pitfalls if I design my language in such a way and if there are any historical or technical reasons this pattern is not widely followed?

share|improve this question
    
I know in the case of scala, def is not equivalent to val with a function. It does some things when it compiles that allow things like overloading and generic type arguments, which are not usable in anonymous functions assigned to a value. That being said, several functional languages do use the same syntax for defining values and functions. Take Haskell, where it's equally valid to say x = 10 as a top-level value, and addOne x = x + 1 as a top-level function. –  KChaloux 12 hours ago
    
related (possibly a duplicate): How do programming languages define functions? –  gnat 12 hours ago
7  
The reason is likely historical. Whoever did it first did it that way, and everyone else copied. But I doubt we can know for sure. –  Snowman 12 hours ago
11  
I think it is because a function or method simply is not just another named entity. In functional languages, they are (you can pass them around etc.) but in other languages (like Java) a function or method is something entirely different from a simple variable and cannot be treated as such (I admit Java 8 kind of weakens this statement), so it makes sense to define functions/methods differently, since they behave differently. –  11684 11 hours ago
1  
@DocSalvager The cause of the shellshock bug is improper mixing of data and code, nothing more. –  delnan 9 hours ago

9 Answers 9

It's because it's important for humans to recognize that functions are not just "another named entity". Sometimes it makes sense to manipulate them as such, but they are still able to be recognized at a glance.

It doesn't really matter what the computer thinks about the syntax, as an incomprehensible blob of characters is fine for a machine to interpret, but that would be nigh-impossible for humans to understand and maintain.

It really is the same reason as why we have while and for loops, switch and if else, etc, even though all of them ultimately boil down to a a compare and jump instruction. The reason is because it's there for the benefit of the humans maintaining and understanding the code.

Having your functions as "another named entity" the way you are proposing will make your code harder to see, and thus harder to understand.

share|improve this answer
    
I disagree that treating functions as named entities necessarily makes code harder to understand. That almost certainly true for any code that follows a procedural paradigm, but it may not be true for code that follows a functional paradigm. –  Kyle Strand 9 hours ago
3  
"It really is the same reason as why we have while and for loops, switch and if else, etc, even though all of them ultimately boil down to a a compare and jump instruction." +1 to that. If all programmers were comfortable with machine language, we wouldn't need all these fancy programming languages (high or low level). But the truth is: everybody has a different comfort level as to how close to the machine they want to write their code. Once you find your level, you just have to stick with the syntax given to you (or write your own language specs and compiler if you're really bothered). –  Hoki 9 hours ago
2  
+1. A more concise version might be "Why do all natural languages distinguish nouns from verbs?" –  msw 5 hours ago

I think the reason is that most popular languages either come from or were influenced by the C family of languages as opposed to functional languages and their root, the lambda calculus.

And in these languages, functions are not just another value:

  • In C++, C# and Java, you can overload functions: you can have two functions with the same name, but different signature.
  • In C, C++, C# and Java, you can have values that represent functions, but function pointers, functors, delegates and functional interfaces all are distinct from functions themselves. Part of the reason is that most of those are not actually just functions, they are a function together with some (mutable) state.
  • Variables are mutable by default (you have to use const, readonly or final to forbid mutation), but functions can't be reassigned.
  • From a more technical perspective, code (which is composed of functions) and data are separate. They typically occupy different parts of memory, and they are accessed differently: code is loaded once and then only executed (but not read or written), whereas data is often constantly allocated and deallocated and is being written and read, but never executed.

    And since C was meant to be "close to the metal", it makes sense to mirror this distinction in the syntax of the language too.

  • The "function is just a value" approach that forms the basis of functional programming has gained traction in the common languages only relatively recently, as evidenced by the late introduction of lambdas in C++, C# and Java (2011, 2007, 2014).

share|improve this answer

The reasons that I can think of are:

  • Easier for the compiler to know what we declaring
  • It's important for us to know (in a trivial way) whether this is a function or a variable, functions are usually black boxes and we don't care about there internal implementation, I dislike type inference on return types in Scala, because I believe that its easier to use a function that has a return type, it is often the only documentation provided.
  • And the most important one, is the *following the crowd* strategy that is used in designing programming languages, C++ was created to steal C programmers, and Java was designed in a way that doesnt scare C++ programmers, and C# to attract Java programmers. Even C# which I think is a very modern language and with an amazing team behind it, copied some mistakes from Java or even from C
share|improve this answer

You mentioned Java and Scala as examples. However, you overlooked an important fact: those aren't functions, those are methods. Methods and functions are fundamentally different. Functions are objects, methods belong to objects.

In Scala, which has both functions and methods, there are the following differences between methods and functions:

  • methods can be generic, functions can't
  • methods can have no, one or many parameter lists, functions always have exactly one parameter list
  • methods can have an implicit parameter list, functions can't
  • methods can have optional parameters with default arguments, functions can't
  • methods can have repeated parameters, functions can't
  • methods can have by-name parameters, functions can't
  • methods can be called with named arguments, functions can't
  • functions are objects, methods aren't

So, your proposed replacement simply doesn't work, at least for those cases.

share|improve this answer
    
"Functions are objects, methods belong to objects." Is that supposed to apply to all languages (like C++)? –  svick 2 hours ago
    
"methods can have by-name parameters, functions can't" - this isn't a fundamental difference between methods and functions, it's just a quirk of Scala. Same with most (all?) of the others. –  immibis 1 hour ago

Turning the question around, if one isn't interested in trying to edit source code on a machine which is extremely RAM-constrained, or minimize the time to read it off a floppy disk, what's wrong with using keywords?

Certainly it's nicer to read x=y+z than store the value of y plus z into x, but that doesn't mean that punctuation characters are inherently "better" than keywords. If variables i, j, and k are Integer, and x is Real, consider the following lines in Pascal:

k := i div j;
x := i/j;

The first line will perform a truncating integer division, while the second will perform a real-number division. The distinction can be made nicely because Pascal uses div as its truncating-integer-division operator, rather than trying to use a punctuation mark which already has another purpose (real-number division).

While there are a few contexts in which it can be helpful to make a function definition concise (e.g. a lambda which is used as part of another expression), functions are generally supposed to stand out and be easily visually recognizable as functions. While it might be possible to make the distinction much more subtle and use nothing but punctuation characters, what would be the point? Saying Function Foo(A,B: Integer; C: Real): String makes it clear what the function's name is, what parameters it expects, and what it returns. Maybe one could shorten it by six or seven characters by replacing Function with some punctuation characters, but what would be gained?

Another thing to note is that there is an most frameworks a fundamental difference between a declaration which will always associate a name with either a particular method or a particular virtual binding, and one which creates a variable which initially identifies a particular method or binding, but could be changed at runtime to identify another. Since these are very semantically very different concepts in most procedural frameworks, it makes sense that they should have different syntax.

share|improve this answer
    
I don't think this question is about conciseness. Especially since for example void f() {} is actually shorter than the lambda equivalent in C++ (auto f = [](){};), C# (Action f = () => {};) and Java (Runnable f = () -> {};). The conciseness of lambdas comes from type inference and omitting return, but I don't think that's related to what this questions asks. –  svick 7 hours ago

There is a very simple reason to have such a distinction in most languages: there is a need to distinguish evaluation and declaration. Your example is good: why not like variables? Well, variables expressions are immediately evaluated.

Haskell has a special model where there is no distinction between evaluation and declaration, which is why there is no need for a special keyword.

share|improve this answer
    
But some syntax for lambda functions also solves this, so why not use that? –  svick 9 hours ago

Personally, I see no fatal flaw in your idea; you may find that it's trickier than you expected to express certain things using your new syntax, and/or you may find that you need to revise it (adding various special cases and other features, etc), but I doubt you'll find yourself needing to abandon the idea entirely.

The syntax you've proposed looks more or less like a variant of some of the notation styles sometimes used to express functions or types of functions in mathematics. This means that, like all grammars, it will probably appeal more to some programmers than others. (As a mathematician, I happen to like it.)

However, you should note that in most languages, the def-style syntax (i.e. the traditional syntax) does behave differently from a standard variable assignment.

  • In the C and C++ family, functions aren't generally treated as "objects", i.e. chunks of typed data to be copied and put on the stack and whatnot. (Yes, you can have function pointers, but those still point at executable code, not at "data" in the typical sense.)
  • In most OO languages, there's special handling for methods (i.e. member functions); that is, they're not just functions declared inside the scope of a class definition. The most important difference is that the object on which the method is being called is typically passed as an implicit first parameter to the method. Python makes this explicit with self (which, by the way, is not actually a keyword; you could make any valid identifier the first argument of a method).

You need to consider whether your new syntax accurately (and hopefully intuitively) represents what the compiler or interpreter is actually doing. It may help to read up on, say, the difference between lambdas and methods in Ruby; this will give you an idea of how your functions-are-just-data paradigm differs from the typical OO/procedural paradigm.

share|improve this answer

Functions are declared differently from literals, objects, etc. in most languages because they are used differently, debugged differently, and pose different potential sources of error.

If a dynamic object reference or a mutable object is passed to a function, the function can change the value of the object as it runs. This kind of side effect can make it difficult to follow what a function will do if it is nested within a complex expression, and this is a common problem in languages like C++ and Java.

Consider debugging some sort of kernel module in Java, where every object has a toString() operation. While it may be expected that the toString() method should restore the object, it may need to disassemble and reassemble the object in order to translate its value to a String object. If you're trying to debug the methods that toString() will be calling (in a hook-and-template scenario) to do its work, and accidentally highlight the object in the variables window of most IDE's, it can crash the debugger. This is because the IDE will try to toString() the object which calls the very code you're in the process of debugging. No primitive value ever does crap like this because the semantic meaning of primitive values is defined by the language, not the programmer.

share|improve this answer

This might be useful on dynamic languages where the type is not that important, but it's not that readable in static typed languages where always you want to know the type of your variable. Also, in object-oriented languages it's pretty important to know the type of your variable, in order to know what operations it supports.

In your case, a function with 4 variables would be:

(int, long, double, String => int) addOne = (x, y, z, s) => {
  return x + 1;
}

When I look at the function header and see (x, y, z, s) but I do not know the types of these variables. If I want to know the type of z which is the third parameter, I'll have to look at the beginning of the function and start counting 1, 2, 3 and then to see that the type is double. In the former way I look directly and see double z.

share|improve this answer
3  
Of course there's that wonderful thing called type inference, which allows you to write something like var addOne = (int x, long y, double z, String s) => { x + 1 } in a non-moronic statically typed language of your choice (examples: C#, C++, Scala). Even the otherwise very limited local type inference used by C# is completely sufficient for this. So this answer is merely criticizing a specific syntax that's dubious in the first place, and not actually used anywhere (although Haskell's syntax has a very similar problem). –  amon 11 hours ago
    
@amon His answer may be criticizing the syntax, but it also points out that the purposed syntax in the question may not be "natural" to everyone. –  jmstoker 7 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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