What does "top-level evaluation" mean?
This term was not defined in the text it was mentioned in. I do not want to tell the specific context, because I am interested only in generic explanations.
It might have multiple meanings depending on the context, but I think it means the evaluation of the top-level expression. For example, the entire body of the main function in a Haskell program, is one expression (of type IO ()) and is the top-level expression of the program, so evaluating that expression would constitute top-level evaluation.
Related
Studying for an exam in my programming languages class. Came across this excerpt in the textbook.
"The address of a variable is sometimes called its l-value, because the address is what is required when the name of a variable appears in the left side of an assignment."
I've been studying C++ on my own time for some years outside of college, and at the very least the topic of value categories is complex enough that I've had to review it many times to get it somewhat well down in my head, and still have to pull up the cppreference page to review the newer categories. At the very least this seems like a massive over-simplification. Is this simply false? Or is this use of l-value just something I've never come across?
EDIT:
The textbook is on Programming languages in general, not specifically C or C++. Apologies for the confusion.
The meaning of "lvalue" or "l-value" has a long and complex history. In some older definitions of the term, that sentence is correct -- but it's not consistent with the way the C++ standard defines it. If your textbook was discussing C++, that passage is questionable. If it was discussing programming in general, it's probably OK.
In C++ (and also in C), an lvalue is not a value. It is a kind of expression, i.e., a construct that can appear in C++ source code. It is the expression itself, not the result of evaluating it.
The definition in the C++11 standard is:
An lvalue (so called, historically, because lvalues could appear on
the left-hand side of an assignment expression) designates a function
or an object.
That definition is in the context of categorizing expressions.
When the terms "lvalue" and "rvalue" were first invented, they referred to things that can appear on the left ('l') or right ('r') side of an assignment. In the original meaning an expression like x could be "evaluated for its lvalue", meaning that it identifies the object named x, or "evaluated for its rvalue", meaning that it retrieves the value currently stored in x. The C and C++ standards have changed the meanings of the terms so that an "lvalue" is an expression, not the result of evaluating it.
(Having said that, the section of the C++11 standard that discusses all this can be a little vague, and there is wording that could suggest that an lvalue might be the result of evaluating an expression.)
In Clojure context, some define the term form as “any valid code,” and some as “any valid code that returns a value.” So both the numeral 1729 and the string Hello! is a form. Likewise (fn is not a form. Is an undefined symbol, say my-val, a form?
What is the difference between an expression and a form?
What is the difference between an expression and a function?
There are some good answers to this question at Are Lisp forms and Lisp expressions same thing?
The key thing to think about is that there are different points in the lifecycle. We start with text "(+ 1 2)" which is then read into Clojure data (a list containing a symbol and two numbers). Often in Lisps "expression" is used to mean the former and "form" is used to mean the latter. In practice, I do not find that people are at all consistent with this usage and often use both terms for both things.
If you take "form" to mean "something which can be evaluated", then 1729 or "Hello!" or the symbol my-val are all forms. When my-val is evaluated it is resolved in the current namespace, perhaps to a function instance, which is invokable. Functions are really important only at evaluation time, when they can be invoked.
Another interesting aspect are macros, which allow you to create new syntax. Note that macro expansion happens after reading though, which means that while you can create new syntax, it still must follow some basic expectations that are encoded into the reader (namely that invocations follow the pattern (<invokable> <args...>)). Note that macros work on read but unevaluated forms (data, not text) and must produce new forms.
What is the difference between an expression and a form?
In my opinion form in a context of Clojure is something a compiler deals with. Some forms are valid expressions while others are "special" forms (i.e. macros).
What is the difference between an expression and a function?
Any function is an expression.
Is an undefined symbol, say my-val, a form?
I would say it is a valid expression (hence form) which yields to a compile time exception.
Likewise (fn) is not a form
It seems like you are referring to some source, where this was declared, could you provide a link?
in C++, there is no such thing as an assignment statement or function-call statement.
An assignment is an expression; a function-call is an expression; this is coming straight from Bjarne Stroustrup in his book "The C++ Programming Language".
I know an expression computes a value, which has me wondering if this applies to void functions, since they don't return a value.
I'd like to know if functions with a return type of void still count as expressions, and if so, why?
C++14 standard:
§5 Expressions:
1 An expression is a sequence of operators and operands that specifies
a computation. An expression can result in a value and can cause side
effects
So the "main" purpose/scope of an expression is to specify a computation, not to compute a value. Some computations may result in a value and some may have side effects.
In addition to this (or actually first of all), "expressions" and "statements" are used in defining the grammar of C and C++. It would be a syntactically impossible to make functions that don't return a value not an "expression". And adding that distinction at a semantic level would be an unnecessary overly-complication.
Yes functions returning no value (declared as returning void) still counts as expressions when you call them. That limits their use in other expressions though, for example such calls can not be on either side of an assignment.
As for "why"? Well, a function call is a function call is a function call. Adding special rules for functions that don't return a value would make the language design much more complicated. C++ already have enough special rules and exceptions.
Yes, void function call is also an expression. The definition in C++ Standard says:
An expression is a sequence of operators and operands that specifies a
computation. An expression can result in a value and can cause side
effects.
A function call is a postfix expression followed by parentheses
containing a possibly empty, comma-separated list of expressions which
constitute the arguments to the function.
Also in MSDN C++ Language Reference:
A postfix-expression followed by the function-call operator, ( ),
specifies a function call.
Function Call = expression-statement… even functions of type void?
no. But that's because a function call is this:
do_stuff()
and that's an expression_opt. It's an expression, not a statement. You can use this expression in compound expressions, but it's not a statement by language logic.
You can quickly convert that expression_opt to a expression-statement by giving it a semicolon:
do_stuff();
is now a full statement.
The difference becomes clear if you think about something like
if(good_thing() || do_stuff())
{
....
}
do_stuff() and good_thing() are expressions, which can/will be evaluated. Semicolons after () would break that if clause.
I've been lately using templates and macros, but i have to say i have barely found information about these important types. This is my superficial understanding:
typed/expr is something that must exists previously, but you can use .immediate. to overcome them.
untyped/stmt is something that doesn't to be defined previously/one or more statements.
This is a very vague notion of the types. I'd like to have a better explanation of them, including which types should be used as return.
The goal of these different parameter types is to give you several increasing levels of precision in specifying what the compiler should accept as a parameter to the macro.
Let's imagine a hypothetical macro that can solve mathematical equations. It will be used like this:
solve(x + 10 = 25) # figures out that the correct value for x is 15
Here, the macro just cares about the structure of the supplied AST tree. It doesn't require that the same tree is a valid expression in the current scope (i.e. that x is defined and so on). The macro just takes advantage of the Nim parser that already can decode most of the mathematical equations to turn them into easier to handle AST trees. That's what untyped parameters are for. They don't get semantically checked and you get the raw AST.
On the next step in the precision ladder are the typed parameters. They allow us to write a generic kind of macro that will accept any expression, as long as it has a proper meaning in the current scope (i.e. its type can be determined). Besides catching errors earlier, this also has the advantage that we can now work with the type of the expression within the macro body (using the macros.getType proc).
We can get even more precise by requiring an expression of a specific type (either a concrete type or a type class/concept). The macro will now be able to participate in overload resolution like a regular proc. It's important to understand that the macro will still receive an AST tree, as it will accept both expressions that can be evaluated at compile-time and expressions that can only be evaluated at run-time.
Finally, we can require that the macro receives a value of specific type that is supplied at compile-time. The macro can work with this value to parametrise the code generation. This is realm of the static parameters. Within the body of the macro, they are no longer AST trees, but rather ordinary well typed values.
So far, we've only talked about expressions, but Nim's macros also accept and produce blocks and this is the second axis, which we can control. expr generally means a single expression, while stmt denotes a list of expressions (historically, its name comes from StatementList, which existed as a separate concept before expressions and statements were unified in Nim).
The distinction is most easily illustrated with the return types of templates. Consider the newException template from the system module:
template newException*(exceptn: typedesc, message: string): expr =
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
## to `message`. Returns the new exception object.
var
e: ref exceptn
new(e)
e.msg = message
e
Even thought it takes several steps to construct an exception, by specifying expr as the return type of the template, we tell the compiler that only that last expression will be considered as the return value of the template. The rest of the statements will be inlined, but cleverly hidden from the calling code.
As another example, let's define a special assignment operator that can emulate the semantics of C/C++, allowing assignments within if statements:
template `:=` (a: untyped, b: typed): bool =
var a = b
a != nil
if f := open("foo"):
...
Specifying a concrete type has the same semantics as using expr. If we had used the default stmt return type instead, the compiler wouldn't have allowed us to pass a "list of expressions", because the if statement obviously expects a single expression.
.immediate. is a legacy from a long-gone past, when templates and macros didn't participate in overload resolution. When we first made them aware of the type system, plenty of code needed the current untyped parameters, but it was too hard to refactor the compiler to introduce them from the start and instead we added the .immediate. pragma as a way to force the backward-compatible behaviour for the whole macro/template.
With typed/untyped, you have a more granular control over the individual parameters of the macro and the .immediate. pragma will be gradually phased out and deprecated.
As I study different sections in the C++ standard ( Where do I find the current C or C++ standard documents? ), I would like to refer back to the "Terms and definitions", §1.3.
However, the terms and definitions are provided in a form that I cannot adequately understand or interpret, and there is no explanation given in the text regarding how to interpret them.
Consider the very first term that is defined in the "Terms and definitions" section of the standard:
1.3.1 [defns.argument]
argument
actual argument
actual parameter
<function call expression> expression in the comma-separated list
bounded by the parentheses
What does [defns.argument] refer to?
What is the meaning and purpose of the lines actual argument and actual parameter?
Does <function call expression> refer to a different "term or definition"? If so, it's not defined in the "Terms and definitions" section - why not? If not, what does it refer to? (NOTE: I am not asking what "function call expression" means, because I already know; instead, I am asking how to read and interpret the "Terms and definitions" section of the C++ standard using this simple example.)
What does [defns.argument] refer to?
[defns.argument] is the section tag; it is intended to be used for editorial purposes as it is invariant under section renumbering (e.g. in response to insertion, removal or reordering of sections). It can also be used in referring to the standard, but section numbers (relative to a published version of the standard) are more concise.
What is the meaning and purpose of the lines actual argument and actual parameter?
"actual argument" and "actual parameter" are aliases for the term "argument". You will see below under 1.3.14 [defns.parameter] that "formal argument" and "formal parameter" are aliases for the term "parameter".
The terms "actual argument" and "actual parameter" only appear in [defns.argument]; "formal argument" is described as an alias in 8.3.5p11, and "formal parameter" is used in approximately 13 places, a small fraction of the number of places where "parameter" is used.
Does <function call expression> refer to a different "term or definition"?
The angle-bracketed term is the context in which this definition applies. For example, "argument" has a different meaning in the context of a "function call expression" to in the context of a "function-like macro".
What does [defns.argument] refer to?
That's an alternative way of referring to the section (1.3.1). It should remain the same in future versions of the standard (unless it's removed), while the numbering may change.
What is the meaning and purpose of "actual argument" and "actual parameter"?
They are other terms that you might see, that mean the same thing. I believe that old versions of the spec. used "formal argument" and "actual argument" where the modern spec. uses "parameter" and "argument".
Does <function call expression> refer to a different "term or definition"?
That's the context in which "argument" has this meaning - the following sections give it different meanings in other contexts. Function call expressions are defined in 5.2.2; within such an expression, "argument" means "expression in the comma-separated list bounded by the parentheses".