Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename 'param'? #5066

Closed
bradcray opened this issue Dec 17, 2016 · 24 comments
Closed

Rename 'param'? #5066

bradcray opened this issue Dec 17, 2016 · 24 comments

Comments

@bradcray
Copy link
Member

bradcray commented Dec 17, 2016

'param' in Chapel is the keyword used to introduce a compile-time constant that can be computed and reasoned about by the compiler. Since the introduction of the keyword, there has been discomfort with the name, in part because it seems unintuitive and in part because of potential confusion with the notion of "function parameters" (which we very carefully try to always call "arguments" in Chapel to avoid confusion). I believe that the choice of 'param' was taken from Fortran and since the introduction of the keyword, we've struggled to come up with a worthy replacement, yet have failed to ever replacement. This issue is designed as a place to capture some of the best counter-proposals, as our ability to change it gets smaller each year.

My preferred replacement keyword for 'param' would be 'value' since I believe that term means very much what our notion of 'param' means today -- a value (in this case, named) which the compiler can reason about and compute on. It's also a term that makes good sense in both the declaration and argument-passing contexts:

value numDims = 3;
proc foo(value rank, x, y) { ... }

At times, we've discussed using 'val' instead of 'value' as shorter, unambiguous, and symmetric with 'var'. Concern has arisen at times that 'val' and 'var' may be too close to each other, introducing the potential for simple mistakes, not to mention confusion for non-native English speakers who may have trouble distinguishing the L and R sounds. To that end, here I'm proposing 'value' which has an equal number of characters as 'param' and is more visibly and audibly distinguishable from 'var'.

The main downside to this approach that I can see is the same downside as any change we might make: This is a feature that's been around for a long time and permeates our code. That said, I think that it remains somewhat regrettable and that if we don't change it now, we won't ever be able to.

The second downside gives me a bit more pause, and that's an argument that at times we've discussed wanting the compiler to not only have a notion of compile-time constants (what 'param' is today) but also compile-time variables that could be re-assigned over compilation. If we went down this path, it might suggest replacing 'param' with some sort of modifier on 'var' and 'const' like:

compiler const numDims = 3;
compiler var x = 0;

On the plus side, a prefix-based modifier like this has the benefit of more orthogonally capturing [compile-time vs. run-time] x [constant vs. variable]. But on the minus side, it seems less natural in the argument passing context. I.e.,

proc foo(compiler const rank, x, y) { ... }

To that end, I continue to think that 'value' as a sibling to 'const' and 'var' has value (ha ha) and that if/when we introduce a notion of a compile-time variable, we seek another term for it.

(I'll also note that some on the team might argue that compile-time vs. run-time are things that are regrettable to emphasize in a language more than necessary, and while I typically am not strongly in that camp, I do think that 'value' has an attractively more context-free meaning than 'compiler const' while also being a much more self-defining term than 'param').

@bradcray
Copy link
Member Author

Note: This came up for me today as I was trying to introduce 'param' in the users guide and felt myself bristling once again at how hard it is to rationalize the choice of keyword to non-Fortran programmers.

Note 2: This is the type of issue I'd throw a 'design' or 'language design' label onto if we had one. None of the existing labels seem quite right.

@mppf
Copy link
Member

mppf commented Dec 19, 2016

I think the 1st code example means to use 'value' instead of 'param'.

Separately, I don't think that 'param' is so bad. I don't really like 'value' is any better. I'm fairly neutral about the 'compiler const' proposal, but I agree it seems too tied to the compiler's current structure. At least with 'param', it's a strange term (or was for me) that didn't already have meaning. But 'value' might be mis-interpreted to include runtime values, which would make it a worse choice of keyword in my opinion.

@psahabu
Copy link

psahabu commented Dec 19, 2016

I like the idea of compiler x {const, var} but agree that it's verbose. Might this be one of the few times that a sigil makes sense? Something like @const, %const, or &const would be visually significant and concise.

@bradcray
Copy link
Member Author

bradcray commented Jan 3, 2017

But 'value' might be mis-interpreted to include runtime values, which would make it a worse choice of keyword in my opinion.

What does "runtime value" mean? I thought that programming languages typically defined a 'value' as something that is unchanging. I.e., a variable 'x' might take on values 2 or 3 or 42 over its lifetime, and a constant 'c' might be initialized to the value '2', but the value '2' will never become the value '3'. This is similar to the nature of 'param's which is why it seems like precisely the right keyword to me.

@mppf
Copy link
Member

mppf commented Jan 3, 2017

Re. 'value' - for example in

proc f(x:int) {
  const y = x;
}

the variable x is unchanging because it is const, but it is known only at runtime.

Also, note that in Scala, you can declare a variable with val which appears to be more or less equivalent to our const. Of course, val means value in Scala... and can refer to a runtime value.

@bradcray
Copy link
Member Author

bradcray commented Jan 3, 2017

In that example, I wouldn't consider 'x' to be a value but rather an argument (a 'const in' argument to be more precise) that will hold some value on each invocation of 'f()'. x and y each hold a value and that value isn't known until runtime, but neither x nor y are values.

The possibility for confusion for Scala users is a reasonable objection, though for me there's a question as to whether there are enough Scala users in the world (who are unwilling to think differently about 'value' in a different language) for that to be a reason to avoid it, particularly given the ongoing confusion over 'param' vs. '[function] parameter' and general lack of enthusiasm among users for 'param'.

@mppf
Copy link
Member

mppf commented Jan 3, 2017

Sorry, I meant to say the variable y is unchanging. Anyway, the point was that y holds a value that isn't known until runtime (in your terms). So I don't think it makes sense to redefine "value" to mean compile-time value.

I'm also not so bothered by the current situation and I'd like too see more proposals if we want to think seriously about changing it. Even define would work better for me than value.

@bradcray
Copy link
Member Author

bradcray commented Jan 3, 2017

I don't think I'm redefining "value" to mean compile-time value vs. runtime value. Unless I don't understand PL terminology (and I very well might not), '2' is a value and '3' is a value, but an integer variable or constant (invariant variable) is not a value; rather, it's an identifier whose associated memory can store a copy of a value. In contrast, params do not define storage, but act as aliases for values -- they are essentially a different way of referring to the core abstract value itself. This forms a pretty strong analogy with the type aliases that Chapel's 'type' keyword creates and also sets up a nice duality between types and values (the abstract concepts and the keywords) that seems to mirror their English definitions in the programming language context (again, assuming I've got my understanding of common terminology at all straight).

For me, 'define' has the problem that it works well in the declaration context, but not so well in the argument context:

proc foo(define rank, x, y) { ... }

This has been one of the main problems that's plagued most counterproposals to 'param'

@mppf
Copy link
Member

mppf commented Jan 4, 2017

I do appreciate the symmetry between 'type' and 'value' but I continue to be hung-up on the definition of 'value'.

Looking around in my PL books and online, it seems that there are divergent definitions of value:

  • "possible final results of evaluation" (Pierce, from SO) or "an expression which cannot be evaluated any further" (Wikipedia, at the moment)
  • "The value of a variable is the contents of the memory cell or cells associated with the variable" (Sebesta, "Concepts of Programming Languages") - I've also seen people informally describe "the bits stored in a variable" on SO.

I think which of these two styles of definition makes sense depends on whether or not we're talking about a functional language. I think that the first definition makes more sense for functional languages and the second makes more sense for imperative languages with mutable variables.

Naturally, a param cannot be mutated, and so the 1st definition makes sense there. Does the 2nd definition make sense, though? Is a param just a variable with associated memory at compile-time? Or is a param not considered a variable at all?

I think I consider a param to be a "compile-time variable" ie a variable with memory that exists during compile time. I think this is why I'm uncomfortable with the proposal to rename it to value since a variable has a value, but a variable is not a value.

I suspect that you do not consider a param to be a "variable" at all.

Lastly, I think the current situation is better if we think of param as referring to parameterized type rather than function parameter. Anyway, looking at Wikipedia, it seems that what others call a function parameter we would call a argument formal or formal argument or just formal. I personally prefer the these terms to parameter in the context of function arguments. That is probably why I am not bothered by the two meanings of "parameter". I suspect each language definition chooses between "actual/formal argument" terminology or "argument/parameter" terminology. It appears that C uses "actual argument" and "formal parameter". Python, Ruby, and Swift appear to use argument/parameter. I don't remember previously being aware of this distinction between 'argument' and 'parameter' - I think I have probably wrongly used the terms interchangeably.

Edit: Cecil uses "formal argument" and "actual argument".

@bradcray
Copy link
Member Author

bradcray commented Jan 5, 2017

I also generally consider argument and parameter to be interchangeable terms in the function argument context, though in Chapel I'm very careful to always use "[formal|actual] argument" to avoid confusion. But users who haven't been trained this way often use "parameter" for arguments which then results in confusion as to whether they mean a param or an argument (or a param argument? a param parameter?)

You're right that I don't think of Chapel's params as compile-time variables (and/or am advocating for moving in that direction). I have probably referred to them as compile-time constants, but I don't think of them as implying storage (e.g., an r-value or l-value) nor as necessarily being the compile-time equivalent of 'const's. Do you consider '2' to be a compile-time variable? To imply storage?

Interpreting 'param' as 'parameterized type' seems justifiable when it's a field of a class/record, but less so in the standalone setting. I.e., I don't see how:

param two = 2;

reflects the phrase "parameterized type." It is much more clear to me how it could be considered to be providing a compile-time name for the value 2. I can also see how a class with 'value' and 'type' fields could be considered a "generic type parameterized by some types and values." But that doesn't suggest to me that 'param' is a good keyword for the values any more than using 'param' in place of 'type' would.

I don't know whether @vasslitvinov has been tracking this conversation or not, but I'm tagging him here because it was something he said years ago that first triggered this proposal for me (though, admittedly, he was then completely unenthused by it at that time for reasons I forget... maybe it just didn't seem interesting or important to him).

@mppf
Copy link
Member

mppf commented Jan 5, 2017

To answer your question, I don't consider '2' to be a compile-time variable but I would consider two in param two = 2 to be a compile-time variable. I personally think of it as occupying memory space, during compilation, yes.

I think we've iterated on this topic enough for now and I expect it's best to wait for some other viewpoints.

@bradcray
Copy link
Member Author

bradcray commented Jan 5, 2017

In essence what I'm asking you is "Would you be open to changing your perspective as to what you think 'param' means?" Or perhaps "What do you think would be lost in changing your perspective?"

@mppf
Copy link
Member

mppf commented Jan 5, 2017

Yeah, I'm open to it. What I think would be lost is the mental short-cut of thinking of a "variable" as "one of those things I gave a name to". E.g. in 'param two', I gave 'two' a name so I'd normally think of it as a "variable". But as I said I think I'm ready to hear another viewpoint.

@bradcray
Copy link
Member Author

bradcray commented Jan 5, 2017

I'd like to hear other viewpoints too, but continue to find your comments valuable to discuss and understand. When you say 'type age = int;' you gave "age" a name, so do you think of it as a variable? As having storage? If not, are you be open to thinking of types and values/params as being similar to one another in that they name things for the compiler without resulting in storage; while consts and vars are similar to one another in that they name things for the execution and (typically) do result in storage? Does that go against anything about how params work today?

@psahabu
Copy link

psahabu commented Jan 9, 2017

I am in agreement with Michael here, in that param is not deficient enough to warrant changing it to value, at least not as a straight replacement.

I would also like to reiterate my support for compiler const and compiler var, but I also think that is too verbose. If there is a way to shorten the compiler part, perhaps with a sigil to create something like @const and @var, then I am in favor of it.

@vasslitvinov
Copy link
Member

I feel convinced by Brad's arguments in favor of "value". Which I
would summarize like this:

(A) "Value" has a specific meaning in Chapel spec:

  • A "value" is something that a "variable" stores at any given point
    during execution.

  • Ex. the spec says "A class value is either a reference to an
    instance of a class or nil."
    Or, an array "variable" is a map from indices to "variables" of
    the array index type, whereas an array "value" is a map from indices
    to "values" of the index type.
    Again, an array variable stores an array value.

  • Each "type" corresponds to a set of "values".

(B) So it makes sense to consider the declaration "value two = 2"
as giving the name "two" to the value "2".

BTW Chapel's "value", as I see it, fits both definitions of "value"
that Michael quotes as "divergent".

I can see that Michael thinks of a "variable" as "a name for something".
I suggest instead to call that a "symbol", or, perhaps less PL-y, a "name".

I like presenting Chapel like a "variable" is storage that at any
moment stores a "value" of that variable's "type". Whereas a "symbol"
is a name for a type, value, variable, function.

FWIW when I just learned it, I was coming from C and my reaction was:
"they got it wrong, 'const' should mean 'compile-time constant'".

If we rename "param" to "value", we will need to find a good name
for today's "param functions". Calling them "value functions" would
be too close to "returning by value" which means something different.

@mppf
Copy link
Member

mppf commented Jan 10, 2017

A related issue: right now we might mean two things by "type function" - myType.someFunction() or a function returning a type. I think we should have a name for those compile-time functions that return a param or a type (no matter whether or not we rename 'param').

@ghost
Copy link

ghost commented Jan 15, 2018

I feel convinced by Brad's arguments in favor of "value". Which I
would summarize like this:

(A) "Value" has a specific meaning in Chapel spec:

A "value" is something that a "variable" stores at any given point
during execution.......

A variable in mathematics is a symbol that has multiple values, in other words the value of it varies depending on conditions.
A parameter (usually t or u signifying time) is very similar to a variable in that the value also varies (but is normally defined as being within a certain area), however a parameter is a 'link' between two other variables.
Now, what - in medicine - is Cardiac Output, CO: a variable, i.e. the value of it varies depending on conditions (you might say!), or a parameter, i.e. 'link' between two other variables - CO is 'linking' heart rate and stroke volume. And you may ask is heart rate a parameter or a variable, stroke volume likewise. Add to this that variables evidently can be dependent or independent.
Source :-researchgate

I agree with Michael that param shouldn't be replaced.

@bradcray
Copy link
Member Author

A parameter (usually t or u signifying time) is very similar to a variable in that the value also varies (but is normally defined as being within a certain area), however a parameter is a 'link' between two other variables.

Your description suggests to me that the term parameter would more naturally describe "an argument to a function", e.g. in f(t), t would be a parameter rather than "an identifier whose value must be known/computable at compile-time." To me, nothing about the English definition of the term "parameter" suggests "known at compile-time" which is why I'm interested in replacing it.

@mppf
Copy link
Member

mppf commented Jan 15, 2018

To be clear, I don't have a strong feeling that we need to keep param - but I'm still hesitant to use value as a replacement for it.

@ghost
Copy link

ghost commented Jan 15, 2018

Your description suggests to me that the term parameter would more naturally describe "an argument to a function", e.g. in f(t), t would be a parameter rather than "an identifier whose value must be known/computable at compile-time." To me, nothing about the English definition of the term "parameter" suggests "known at compile-time" which is why I'm interested in replacing it.

Yes, you are right.

@damianmoz
Copy link

Chapel has a way to specify what can be done to a identifier of data by labelling it is as a

a) var[iable] : to which is assigned a run-time computable expression which is mutable thereafter
b) con[stant] : to which is assigned a run-time computable expression which is immutable thereafter
c) param[eter] : to which is assign a compile-time computable expression which is immutable forever

Now (a) and (b) are adjectives which somebody long ago hijacked as a noun. We are stuck with it.
BCPL calls (c), a compile-time computed expression given to an identifier, a manifest constant and qualifies it with simply a keyword manifest, an adjective. The noun manifest is something totally different! English is awful.

Some alternative names for parameter which more accurately describe it:

compiler const

as per @bradcray above or, can I suggest

compiled const

because I want an adjective. If we consider the use of of the word var[iable]s to really mean instead an identifier, then a

var x IS an identifier called x
const x IS a constant identifier called 'x'
param x IS a compiled constant identifier called 'x'

The qualification hierarchy on the right-hand side of each IS above can be written recursively(?) as

compiled [ constant [ identifier ] ] ]

This is really difficult problem where you are ham-strung by history. No wonder it keeps us awake at night.

If you eliminated the concept of 'var' altogether and assume that the default identifier refers to a one which is constant or (read-only) piece of data. Such a concept already applies in many language and in chapel to its procedure arguments. If we allow ourselves to declare a new identifier with some new keyword say say, my take on BCPL's let concept, then the Chapel declariation

say x [ : type expression ] [= expression ]

where you can replace say with a more appropriate word while remembering that let is already taken for something else. We can then optionally qualify the say with any of

defined OR mutable OR def(ined) OR mut(able)

where def(ined) implies that the identifier is defined at compile-time and fixed forever and mutable implies the program computes it at run-time and it can be changed during its scope.

Either 'defined' or 'mutable' or can be qualified by

config[urable]

to mean it can come through as a program arg(ument). The word arg(ument) raises all sorts of issues!
So the syntax is

say [config(urable)] [ def(ined) | mut(able) | <empty> ] x [ : type ] [ = expression ]

One could almost add 'vol(atile) to the mix of def(ined) and mut(able) but that is another discussion.

I realise the above is a big change but it is fully orthogonal. At the very least, it is a discussion (re)starter. I am amazed how few a my programs have truly mutable identifiers, or what we call var(iables). Tell me to pull my head in if the above makes no sense. It may be not viable at this point considering that Chapel is 10 years old.

By the way, if you used the BCPL valof concept for what Chapel calls a let expression, i.e.

x = valof { say x : real = a * b, y = x * x; resultis(1.0/y); };

you free up the let keyword. It also makes the syntax of a proc returning a value a lot easier to write. Why Denis and Ken did not pinch that feature from BCPL is beyond me. Mind you, I jdid ust change the whole way of processing {} back to the original concept of an Algol begin/end block which is non-trivial too.

On a related matter, floating point literals should be accurate to the highest precision of the target architecture of the compiled code and have either no default type, the type of the most accurate floating point an architecture can support, or a type which is a compiler option. All floating point literals should be explicitly typed but that is a personal preference. You need to start doing this or you will be caught with what C now has for long double floating point numbers, a problem which makes it very difficult to do generic programming with floating point numbers.

@mppf
Copy link
Member

mppf commented Feb 5, 2019

@damianmoz - Thanks for your perspective and appreciation for why this is a tricky topic.

Regarding part about floating point literals - let's put that into another issue (while it might be related I think it's different enough). We can continue to link to it from here. I'll leave it to you to create such an issue but am happy to help.

@bradcray
Copy link
Member Author

This hasn't garnered the necessary support to make the change, so I'm closing it. <sob!>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants