Without delving into any specific language, one first reason would probably be ease of implementation (in the compiler/interpreter). It is much much more simple to have a single "internal" data type of objects to pass around, than having to have two different ones.
Functions are a relatively complex data type, compared to integers, strings and whatever "native" data types a language usually has. They have arguments, return values, possibly other attributes. All of that needs to be represented somehow. Then, for a strongly and/or statically typed language like Java, to make a function a real first class citizen, you'd have to implement some kind of inheritance concept for functions; i.e. the same way you can assign any object to a variable of the type Object
, but not to a variable of the type Person
, you'd probably want to have some feature of this kind for functions as well. Be it some templating scheme or whatever you can think about. Purely functional languages do not have that problem because they start with a concept for exactly this, and then model everything else around it.
Finally, there is nothing wrong with representing a function as an object! In a good object-oriented language, everything is an object, including a function, and everything will then flow together nicely. For example, in Ruby, this is exactly the case: there is nothing that is not an object. Classes are objects. Modules (stateless collections of methods) are objects. All "native" data types like integers etc. are objects. You can define functions dynamically/anonymously and pass them around like variables - because they are also objects (which happen to have a call
method).
This means you can write code like this (this is an interactive session, but you could use the same code in actual programs):
# Define a method (lambda/proc in Ruby terms) and assign it to variable fn
irb(main):001:0> fn = -> (arg) { puts arg }
=> #<Proc:0x007faf00413398@(irb):1 (lambda)>
# Call the function (there are syntactic sugars for that if one prefers to make it look like a "normal" method call)
irb(main):002:0> fn.call("hello")
hello
# Ask about the arity
irb(main):003:0> fn.arity
=> 1
# Ask where the definition (the code) is
irb(main):004:0> fn.source_location
=> ["(irb)", 1]
# Ask for the parameter definition
irb(main):005:0> fn.parameters
=> [[:req, :arg]]
# Use it in an array
irb(main):024:0> arr = [1, 2, 3, fn, 4]
=> [1, 2, 3, #<Proc:0x007faf00413398@(irb):1 (lambda)>, 4]
# Ask which class the object has
irb(main):012:0* fn.class
=> Proc
To stick with this, if you check out the documentation for the Proc
class you see that there are a lot of very interesting, cool and powerful ways that open up once you make functions first-class-citizen objects (here, Proc
includes a closure (or "binding" in Ruby terms). You can literally do whatever you want with it, including extending the definition of the Proc
class to add more features on the fly. Or you could create an instance of class Method
which is an object that represents a method call on a given object and otherwise behaves very similarly to a Proc
.
If at all, I would ask why these older languages you mention do not have a full-fledged object-representation of functions and methods - and the answer would simply be that that was not en vogue when those languages were designed, or there were pre-existing constraints which would have made it too hard. Languages develop over the decades. Modern versions of Java (and presumably C#) have added more functional features, but it is completely understandable why they shied away from it at the beginning - people were still very used to the silly low-level function-pointer-hell from C or old C++.