I am modelling a programming language for fun, and the syntax is heavily influenced by Scala - specifically function definitions.
I have encountered a design problem because my language does not differentiate between functions defined via the def
syntax (class methods) and anonymous functions assigned to values (created using =>
) - it removes the differences in both implementation and behaviour.
The result is that the following two definitions mean the same thing:
def square(x: Int) = x*x
val square = (x: Int) => x*x
There is no reason for the latter form (immediate anonymous function assignment) to be used in any normal situation - it's simply possible to use it instead of the def
form.
Would having such duplicate syntax for defining named functions hurt the orthogonality of the language or some other design aspect?
I prefer this solution because it allows for short and intuitive definitions of methods and named functions (via def
), and short definitions of anonymous functions (using =>
).
Edit: Scala does differentiate between the two - anonymous functions are not the same as methods defined with def
in Scala. The differences are relatively subtle though - see the posts I linked before.
3 Answers 3
I think that having two constructs that mean the same thing but look different should be kept to an absolutely minimum in a language. Any duplication increases how difficult it is to read (and thus write/modify code in ) your language. Eliminating all duplication is unavoidable in a language that can create arbitrary constructs (for example, the equivalence of iteration vs recursion).
So in this case, I think it could be designed better here. A single way to define functions makes the most sense to me. In this case, it sounds like the two scala statements you have actually do have slightly different implications, which again is probably not good design (probably best to have something clear that states what the differences, like a keyword).
In fact, you can apply this principle not only to named functions, but to any function. Why have any difference in defining named functions and anonymous functions? In Lima, functions are always defined like this: fn[<arguments>: <statements>]
. If you want it to be "named" you can assign it to a variable: var x = fn[<arguments: <statements>]
, and if you want to pass it in to another function anonymously: function[fn[<arguments: <statements>]]
. If you want it hoisted, make it constant const var x = fn[<arguments: <statements>]
. The single form makes it obvious that they mean the same thing.
-
That's quite interesting that
const
causes hoisting, but it makes perfect sense. In JSfunction myFunc
causes hoisting, butvar myFunc =
does not, which is perhaps a bit less intuitive because they behave pretty much the same otherwise.mpen– mpen2016年04月12日 05:52:34 +00:00Commented Apr 12, 2016 at 5:52 -
1@mpen Yeah, actually javascript essentially does the same thing. the
function fnName()...
form does in fact create a constant, which is what makes hoisting a valid thing to do with it. Javascript makes things pretty confusing tho when you use the formvar fn = function anotherFnName()...
since that makes the nameanotherFnName
not hoist, even tho its clearly constant.B T– B T2016年04月12日 21:36:06 +00:00Commented Apr 12, 2016 at 21:36
What you've posted is valid scala and works fine.
Given that the doubling hasn't caused issues with scala (to my knowledge), I'm going to say that it won't be a problem for your language either.
-
1It is valid in Scala, it mostly works the same, but it does not mean the same thing - and if you'd make more complex examples (type polymorphism is not available for anonymous functions e.g.) - the differences would become more apparent.jcora– jcora2014年06月21日 08:19:20 +00:00Commented Jun 21, 2014 at 8:19
I've found a fundamental difference between lambdas and def
methods in Scala - that I am still not sure whether I want to implement. I have to do further research on it and then I'll report back on my decision.
Essentially, only methods can return
- and when the keyword is used from a lambda, it actually returns from the encompassing method.
As I've said, I'm not sure whether I want this. But it could be justification enough for this syntax. Or maybe too dangerous because subtle differences can unexpectedly cause harm.
However, assigning existing functions
seems to be missing the end of the sentenceval
notation?fun
to define a recursive function.def
is. It's just a side effect of the fact that an anonymous function, say(x : Int) => x + 1
is an object, and objects can be assigned to values withval f = ...
. The language designers would have had to go out of their way to disallow the syntax. It's not quite the same as explicitly putting in the effort to support two different syntaxes that do (approximately) the same thing.