crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.41k stars 1.62k forks source link

Be precise about "arguments", "parameters", and "variables" #10374

Open HertzDevil opened 3 years ago

HertzDevil commented 3 years ago

The reference manual and the compiler source use the terms "arguments", "parameters", and "variables" interchangeably, sometimes in a way inconsistent with most other programming languages. There is a clear distinction between the three terms: (quotes taken from Wikipedia)

The argument in computer science is the actual input expression passed/supplied to a function, procedure, or routine in the invocation/call statement, whereas the parameter is the variable inside the implementation of the subroutine. For example, if one defines the add subroutine as def add(x, y): return x + y, then x, y are parameters, while if this is called as add(2, 3), then 2, 3 are the arguments.

A parameter is an (unbound) variable, while the argument can be a literal or variable or more complex expression involving literals and variables.

We should follow the same terminology in Crystal to minimize chances of confusion. (The Eiffel convention of "formal arguments" and "actual arguments" seems rather verbose so I'll use the usual meanings.) An example in the reference manual is Default values and named arguments:

Default values arguments

A method can specify default values arguments for the last arguments parameters: ...

Named arguments

All arguments can also be specified, in addition to their position, by their name. For example: ...

When there are many arguments, the order of the names in the invocation doesn't matter, as long as all required arguments parameters are covered: ...

When a method specifies a splat parameter (explained in the next section), named arguments can't be used for positional parameters. The reason is that understanding how arguments are matched becomes very difficult; positional arguments are easier to reason about in this case.

Another place of misuse is break:

break can also take a parameter an argument which will then be the value that gets returned:

Whereas in the source code, there is #type_vars, which represents all three concepts:

The docs changes are relatively easy, followed by compiler error messages and internal names in the compiler. Names that appear in the macro land are the hardest to replace, and require proper deprecation, but IMO we should do this in the future even if they don't make it for 1.0. For the particular case of #type_vars, perhaps we could:

And Crystal::Macros::Arg should become Param. This affects #class_name directly and I don't know if a deprecation route is possible there.

straight-shoota commented 3 years ago

Sounds good.

However, I'm not sure about the particular first example:

A method can specify default arguments for the last parameters.

This feels odd to me. It should be "default values for the last parameters". They're not arguments passed to the method. The parameters have a default value when the arguments are omitted.

HertzDevil commented 3 years ago

The default arguments are arguments provided at the method definition site rather than at the invocation site. I don't see why these expressions aren't arguments.

straight-shoota commented 3 years ago

They could be seen as arguments, yes. But the values are assigned at the parameter definition. To me it seems less confusing to just talk about values than to pick on the difference between parameters and arguments in this case.

Fryguy commented 3 years ago

"default argument" is a weird turn of phrase. It's not incorrect, but "default value" feels so much more common. "default argument values for the last parameters" is probably the most technically accurate, but that feels a bit verbose. I think "value" and "argument" might be interchangable?

HertzDevil commented 3 years ago

So I tried to gather the reference manuals of a bunch of programming languages to see which terms they use:

"Default argument value" is redundant; the value (or the expression) is the argument.

RespiteSage commented 3 years ago

Though it's a bit wordy, I think "default parameter value" strikes a good balance between accuracy and understandability.

HertzDevil commented 3 years ago

Judging from those languages it seems Ruby's documentation is ironically the loosest one with regard to "arguments" and "parameters", though the Japanese reference is better (it also uses the Eiffel convention):

仮引数にデフォルト式が与えられた場合、メソッド呼び出しで実引数を省略したときのデフォルト値になります。

"If a default expression is supplied to a formal argument, it becomes that argument's default value when the actual argument is omitted in a method call."

oprypin commented 3 years ago

Slight preference for "Default value" for me.

I can understand "default argument" as "argument that's being passed if nothing else is". But an argument is something that a user of the function actively passes, by writing it into parentheses, so to say. But here it's kind of always been there, you don't need to pass it.

It's certainly not wrong, just sounds weird indeed.

In Python, though... oh, this would definitely be wrong. Python has actual default values that just sit there attached to the function as a (mutable!) singleton.

potomak commented 2 years ago

I noticed an incorrect usage use of arg/param terms in the parser’s source code too.

I would suggest to update all variable names used to store param names and values from ‘arg*’ to ‘param*’.

Examples:

straight-shoota commented 2 years ago

For going all the way, we should probably also rename the Crystal::Arg type to Crystal::Param. I'm not sure if that would have any implications that we want to avoid. Leaving Arg in as an alias should probably be good for tools that hook directly into the compiler API (for example ameba).

potomak commented 2 years ago

I was thinking the same and I was also wandering if Crystal has aliases for keeping the backward compatibility. I can publish a PR for renaming the class.

There are also a couple of struct fields that should be renamed.