Is duplicate syntax for defining named functions a bad language design decision

language-designscala

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.

Best Answer

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.

Related Topic