Merge: Default arguments
authorJean Privat <jean@pryen.org>
Sun, 19 Apr 2015 00:07:12 +0000 (07:07 +0700)
committerJean Privat <jean@pryen.org>
Sun, 19 Apr 2015 00:07:12 +0000 (07:07 +0700)
commit3357f3cf0c4c2a9687e52821441f25664077031d
tree029769749ebea037537902fb4151f876197d06a5
parentcea8021e4ad737a6c437d0a57ce69e1ed99c15f3
parent2399e75c518684086c10d3745a952e24f3f5e9ef
Merge: Default arguments

Default arguments (aka parameters with a default value) are often a nice way to provide a complex operation with a lot of variations but allow the client to use it in a simple form when no complexity is required.
Also, it allows to extends the signature of existing operations while being API-compatible with previous versions.

This PR introduces default arguments to Nit as another tool in the toolbox of library designers.

The specification is quite simple:

* a nullable parameter can be ignored, the value of the argument will default to null

~~~nit
fun foo(a: Int, b: nullable Int) do ...
foo(1)
foo(1, null)  # equivalent thing
~~~

* default parameters can be anywhere (not necessarily at the end)

~~~nit
fun foo(a: nullable Int, b: Int) do ...
foo(1)
foo(null, 1)  # equivalent thing
~~~

* when there is multiple possible associations between arguments and parameters, arguments will be associated to the leftmost (first) parameter first.

~~~nit
fun foo(a, b: nullable Int) do ...
foo(1)
foo(1, null)  # equivalent thing
~~~

* if there is a vararg, all other parameters are mandatory (no default)

~~~nit
fun foo(a: Int..., b: nullable Int) do ...
foo(1) # Error: minimum 2 arguments (we chose that varargs require a minimum of 1 argument, but this old choice is a different issue)
foo(1, 2) # OK
foo([1]..., 2) # equivalent thing
~~~

* the last parameter of an assignment method (that is the right value of the assignment) is never default. For POLA reasons, the last argument is distinguished and syntactically mandatory, so the association with the parameter is always direct and unambiguous.

~~~nit
fun foo=(a, b: nullable Int) do ...
foo = 1
foo(null) = 1 # equivalent thing
~~~

I chose this specification because it uses the nullable facility of Nit in a nice way and is somewhat semantic: `null` means nothing to say, or keep it blank.
I prefer it over the specification of other languages that is to declare a specific default value on the declaration of parameters.

* no need not to update the grammar
* no need to specify the language of the default value (any expressions? only literal? other?)
* no need to specify when and by who the default value is evaluated (and what is the value of self? are the other parameters usable in the expression? etc.)
* no need to specify how to deal with default values on redefinitions in a OO point of view (do I inherit the default value? can I `super` the default value?)
* no need to expose the expressions used as default values in the metamodel
* no need to expose the expressions used as default values in the doc

Most of these things make the language less KISS (obviously), and less POLA because whatever spec we can choose for these points, 1) not 100% of user will find them obvious; and 2) for some cases the wanted behavior will not be the specified one.

Note that in Python, while they allow to define a specific default value on parameters, they recommend to use `null` as a default to avoid most of these aforementioned problems.

Note2: this PR was unlocked by #1269 and #1268

Pull-Request: #1280
Reviewed-by: Etienne M. Gagnon <egagnon@j-meg.com>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Ait younes Mehdi Adel <overpex@gmail.com>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>