Why is it possible to declare a function without parentheses?
proc f: Int = 5
It can only be called with parentheses:
echo f()
#this raises an error
#echo f
Maybe it is a waste having to write () for param-less procs? If your proc doesn't need pragmas you don't need to write an empty {. .} either for it.
A separate thing is the language allowing omitting parentheses in proc calls when they are not needed. For instance:
proc double(a: int): int = a * 2
echo 5.double
Here not only I'm avoiding the parentheses, I'm also using the method call syntax which makes it look as if integers were class objects (in other languages) with a built-in double method. And I'm also avoiding an explicit call to the $ stringify proc.
You can omit parentheses were it makes sense. echo is a special proc because it uses varargs with a type conversion proc, so it may not be the best example to play with omitting parentheses. In your example, proc's are first class functions, so the $ conversion proc is looking for a way to convert the proc itself to a string, and fails because there is none. Hence the requirement to pass the parenthesis, that implies a function call to a proc and $ knows how to stringify the integer returned by that proc.
The slides from the Strangeloop conference explain how much trickery goes into echo to avoid dynamic binding.
PS. Try the following example and see what it does:
proc `$`(f: proc(): int): string =
"A proc without params returning an integer"
proc f: Int = 5
echo f
Thanks for your help, but I still don't get it.
proc f: int = 5
let s: string = $f()
doesn't work without parentheses either. Therefore it doesn't have anything to do with varargs. And there is no ambiguity with the method call syntax.
Btw, I just found out that
echo([""])
does not compile. Is there an operator that tells the compiler to use the explicitly passed array as the varargs array?
Ah, the example you write compiles for me fine, so I guess the development version I'm using has different precedence rules from the one you have. I'd say your version treats $ with higher precedence than () and therefore you would need to write $(f()) instead.
Don't know about any operator to pass the array directly as the varargs.
The issue is more the opposite of what you are suspecting. Nimrod needs to disambiguate between using a standalone f as a procedure call and a procedure reference. This is done by requiring parentheses to turn it into a call -- note that in the case of using dot notation (x.f), where there is no such ambiguity, no parentheses are required. But this is something that occurs at the call site, not where the procedure is defined. You can still use f as a reference without parentheses:
proc f: int = 5
let h: proc: int = f
echo h()
Alternatively, one could choose a syntax where f on its own would be a procedure call and obtaining a reference to f would require a special notation.
Alternatively, one could choose a syntax where f on its own would be a procedure call and obtaining a reference to f would require a special notation.
Bertrand Meyer (Eiffel's designer) advocated this design in his book OOSC: his point was that a caller shouldn't have to care whether a class use function or an attribute(variable) to implement things. I think that this is quite convincing, I'm curious: what are the reasons for choosing the other way? I don't see any advantage..
renoX: Bertrand Meyer (Eiffel's designer) advocated this design in his book OOSC: his point was that a caller shouldn't have to care whether a class use function or an attribute(variable) to implement things. I think that this is quite convincing, I'm curious: what are the reasons for choosing the other way? I don't see any advantage.
First, Eiffel is different from Nimrod in that it does not have parameterless functions. There's always the implicit Current parameter (what is called self or this in other object-oriented languages), even if that parameter can be optimized away in a lot of cases (such as for a lot of functionality inherited from ANY.)
If there's an object, Nimrod does allow you to use x.f to both refer to a function call f(x) and access to field f of x.(Though I'm not sure why you can't use x.f() in the latter case.)
You can make an argument that this should also hold for top level modules in languages with a separate module system (in Eiffel, classes are modules). But here, the case is weaker, because many of the concerns that hold for objects are not very important for modules (such as the use case of simple small objects that are then burdened with boilerplate for setter/getter functions), and global variables in top level modules traditionally are not exposed at all insofar as they even exist. Personally, I would still have done it differently from Nimrod, but you can make a good argument either way.