Is an address sometimes referred to as an 'l-value' - c++

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.)

Related

Is the term "method" defined by the C++ Standard?

The term "method" is often used to discuss C++ code. Does the standalone term have a well-defined meaning in C++ or is it ambiguous? Is it acceptable to use the term by itself, or should it be qualified (e.g. a "class method" or "virtual method"), or should it be simply avoided altogether?
The term method is not defined in the C++ standard. The terminology uses member function instead.
Bjarne Stroustrup however defines the term method in his own glossary as virtual member function. So this shows evidence that the term is acceptable.
I would avoid this term entirely, as it is clear what you mean by "member function", but not "method" - that you asked this question is proof enough.
However, normative appearances of the word "method" in the C++14 standard are
In the content list:
17.5 Method of description (Informative)
This is repeated in the title of that section.
[basic.compound]:
These methods of constructing types can be applied recursively;
[cpp.include]
The method by which a sequence
of preprocessing tokens between a < and a > preprocessing token pair or a pair of " characters is combined
into a single header name preprocessing token is implementation-defined.
[library.general]
The following subclauses describe the definitions (17.3), method of description (17.5), [..]
In table 32, FLT_EVAL_METHOD is mentioned.
In stage 2 of num_get's do_get:
For arithmetic types, punct.thousands_sep() characters are inserted
into the sequence as determined by the value returned by
punct.do_grouping() using the method described in 22.4.3.1.2
[forwardlist.modifiers]:
Otherwise, inserts sz - distance(begin(), end()) elements at the end of
the list such that each new element, e, is initialized by a method equivalent to calling allocator_traits<allocator_type>::construct(get_allocator(), std::addressof(e), c).
[filebuf.virtuals]:
Behaves according to the description of
basic_streambuf<charT,traits>::uflow(), with the specialization that a
sequence of characters is read from the input with the same method as
used by underflow.
The term is clearly never referring to a "member function".
The C++ standard makes no mention of the term method. It should be noted that the official C++ FAQ does make use of this term, but to describe a virtual function; a simple Google search reveals more occurrences of this term.
I've never seen the term method in an IDE (Visual Studio), but I've seen the term member function. In my opinion method is a 'one size fits all' term.
The term method had been historically used as a synonym of the procedure of an object. Considering, an object has both data and behaviour, it is this behaviour which was referred as method.
Tracing backward, I could find a reference to the usage of the term method when referring to an MIT ALGOL version, AED-0
Quoting wikipedia
MIT ALGOL version, AED-0, linked data structures ("plexes", in that
dialect) directly with procedures, prefiguring what were later termed
"messages", "methods", and "member functions".
Over the years method had been an integral part of Object Oriented Analysis and Design and Object-oriented programming. Now C++ evolved as a procedural language where it extended C a procedural language to have object oriented capabilities. C had the concept of structure, and the data elements were called members. Refer Methods in C++.
To not break the lineage, C++ continued to call the elements of structured and the newer genre class as members.
Now, to differentiate between data and functions, instead of introducing a new terminology, it extended this terminology to call data members and member functions. Member functions which supported dynamic binding were called virtual functions.
So, strictly speaking, official references refrains from using the terminology methods when referring to member functions. The terminology is most prevalent among the people who have a more Object Oriented background. So if you want to remain unambiguous, it is best to use the terminology as
data member
member function
virtual functions
Here my analysis regarding the word method.
I did a scan on official documentation (standards, specifications, etc.) on several programming languages.
http://componentsprogramming.com/using-the-right-terms-method/
Adequate taxonomy (not dependent on any programming languages) will be published in a future article.
Regarding to C++, the correct terminology is: member/non-member function.
Some people use member/free functions.

Is C++ considered weakly typed? Why?

I've always considered C++ to be one of the most strongly typed languages out there.
So I was quite shocked to see Table 3 of this paper state that C++ is weakly typed.
Apparently,
C and C++ are considered weakly typed since, due to type-casting, one can interpret a field of a structure that was an integer as a pointer.
Is the existence of type casting all that matters? Does the explicit-ness of such casts not matter?
More generally, is it really generally accepted that C++ is weakly typed? Why?
That paper first claims:
In contrast, a language is weakly-typed if type-confusion can occur silently (undetected), and eventually cause errors that are difficult to localize.
And then claims:
Also, C and C++ are considered weakly typed since, due to type-casting, one can interpret a field of a structure that was an integer as a pointer.
This seems like a contradiction to me. In C and C++, the type-confusion that can occur as a result of casts will not occur silently -- there's a cast! This does not demonstrate that either of those languages is weakly-typed, at least not by the definition in that paper.
That said, by the definition in the paper, C and C++ may still be considered weakly-typed. There are, as noted in the comments on the question already, cases where the language supports implicit type conversions. Many types can be implicitly converted to bool, a literal zero of type int can be silently converted to any pointer type, there are conversions between integers of varying sizes, etc, so this seems like a good reason to consider C and C++ weakly-typed for the purposes of the paper.
For C (but not C++), there are also more dangerous implicit conversions that are worth mentioning:
int main() {
int i = 0;
void *v = &i;
char *c = v;
return *c;
}
For the purposes of the paper, that must definitely be considered weakly-typed. The reinterpretation of bits happens silently, and can be made far worse by modifying it to use completely unrelated types, which has silent undefined behaviour that typically has the same effect as reinterpreting bits, but blows up in mysterious yet sometimes amusing ways when optimisations are enabled.
In general, though, I think there isn't a fixed definition of "strongly-typed" and "weakly-typed". There are various grades, a language that is strongly-typed compared to assembly may be weakly-typed compared to Pascal. To determine whether C or C++ is weakly-typed, you first have to ask what you want weakly-typed to mean.
"weakly typed" is a quite subjective term. I prefer the terms "strictly typed" and "statically typed" vs. "loosely typed" and "dynamically typed", because they are more objective and more precise words.
From what I can tell, people generally use "weakly typed" as a diminutive-pejorative term which means "I don't like the notion of types in this language". It's sort of an argumentum ad hominem (or rather, argumentum ad linguam) for those who can't bring up professional or technical arguments against a particular language.
The term "strictly typed" also has slightly different interpretations; the generally accepted meaning, in my experience, is "the compiler generates errors if types don't match up". Another interpretation is that "there are no or few implicit conversions". Based on this, C++ can actually be considered a strictly typed language, and most often it is considered as such. I would say that the general consensus on C++ is that it is a strictly typed language.
Of course we could try a more nuanced approach to the question and say that parts of the language are strictly typed (this is the majority of the cases), other parts are loosely typed (a few implicit conversions, e. g. arithmetic conversions and the four types of explicit conversion).
Furthermore, there are some programmers, especially beginners who are not familiar with more than a few languages, who don't intend to or can't make the distinction between "strict" and "static", "loose" and "dynamic", and conflate the two - otherwise orthogonal - concepts based on their limited experience (usually the correlation of dynamism and loose typing in popular scripting languages, for example).
In reality, parts of C++ (virtual calls) impose the requirement that the type system be partially dynamic, but other things in the standard require that it be strict. Again, this is not a problem, since these are orthogonal concepts.
To sum up: probably no language fits completely, perfectly into one category or another, but we can say which particular property of a given language dominates. In C++, strictness definitely does dominate.
In contrast, a language is weakly-typed if type-confusion can occur silently (undetected), and eventually cause errors that are difficult to localize.
Well, that can happen in C++, for example:
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
#include <limits>
void f(char n) { std::cout << "f(char)\n"; }
void f(int n) { std::cout << "f(int)\n"; }
void g(int n) { std::cout << "f(int)\n"; }
int main()
{
float fl = M_PI; // silent conversion to float may lose precision
f(8 + '0'); // potentially unintended treatment as int
unsigned n = std::numeric_limits<unsigned>::max();
g(n); // potentially unintended treatment as int
}
Also, C and C++ are considered weakly typed since, due to type-casting, one can interpret a field of a structure that was an integer as a pointer.
Ummmm... not via any implicit conversion, so that's a silly argument. C++ allows explicit casting between types, but that's hardly "weak" - it doesn't happen accidentally/silently as required by the site's own definition above.
Is the existence of type casting all that matters? Does the explicit-ness of such casts not matter?
Explicitness is a crucial consideration IMHO. Letting a programmer override the compiler's knowledge of types is one of the "power" features of C++, not some weakness. It's not prone to accidental use.
More generally, is it really generally accepted that C++ is weakly typed? Why?
No - I don't think it is accepted. C++ is reasonably strongly typed, and the ways in which it has been lenient that have historically caused trouble have been pruned back, such as implicit casts from void* to other pointer types, and finer grained control with explicit casting operators and constructors.
Well, since the creator of C++, Bjarne Stroustrup, says in The C++ Programming Language (4th edition) that the language is strongly typed, I would take his word for it:
C++ programming is based on strong static type checking, and most techniques aim at achieving a high level of abstraction and a direct representation of the programmer’s ideas. This can usually be done without compromising run-time and space efficiency compared to lower-level techniques. To gain the benefits of C++, programmers coming to it from a different language must
learn and internalize idiomatic C++ programming style and technique. The same applies to programmers used to earlier and less expressive versions of C++.
In this video lecture from 1994 he also states that the weak type system of C really bothered him, and that's why he made C++ strongly typed: The Design of C++ , lecture by Bjarne Stroustrup
In General:
There is a confusion around the subject. Some terms differ from book to book (not considering the internet here), and some may have changed over the years.
Below is what I've understood from the book "Engineering a Compiler" (2nd Edition).
1. Untyped Languages
Languages that have no types at all, like for example in assembly.
2. Weakly Typed Languages:
Languages that have poor type system.
The definition here is intentionally ambiguous.
3. Strongly Typed Languages:
Languages where each expression have unambiguous type. PL can further categorised to:
A. Statically Typed: when every expression is assigned a type at compile time.
B. Dynamically Typed: when some expressions can only be typed at runtime.
What is C++ then?
Well, it's strongly typed for sure. And mostly it is statically typed.
But as some expressions can only be typed at runtime, I guess it falls under the 3.B category.
PS1: A note from the book:
A strongly typed language, that can be statically checkable, might be implemented (for some reason) just with runtime checking.
PS2: Third Edition was recently released
I don't own it, so I don't know if anything had changed on this regard.
But in general, the "Semantic Analysis" Chapter had changed both title and order in Table of Contents.
Let me give you a simple example:
if ( a + b )
C/C+= allows an implicit conversion from float to int to Boolean.
A strongly-typed language would not allow such an implicit conversion.

Why cannot C type-generic expressions be compatible with C++?

I seem to recall hearing vague comments from a few reliable sources (i.e. committee members speaking in non-official channels) that C type-generic expressions will not be added to C++ because they cannot be.
As far as I can tell, type-generic expressions are very limited compared to C++ templates and overloading, but there is no potential for interaction that would need to be defined as a special case.
A type-generic expression consists of a controlling expression, and a series of "associations" between types and subexpressions. A subexpression is chosen based on the static type of the controlling expression and the types listed for the subexpressions, and it is substituted in place of the TGE. Matching is based on the C concept of type compatibility, which as far as I can tell is equivalent to C++ identity of types with extern linkage under the one-definition rule (ODR).
It would be nice if a derived class controlling expression would select a base class association in C++, but since C doesn't have inheritance, such nicety isn't needed for cross-compatibility. Is this considered to be a stumbling block anyway?
Edit: As for more specific details, C11 already provides for preserving the value category (lvalue-ness) of the chosen subexpression, and seems to require that the TGE is a constant expression (of whatever category) as long as all its operands are, including the controlling expression. This is probably a C language defect. In any case, C++14 defines constant expressions in terms of what may be potentially evaluated, and the TGE spec already says that non-chosen subexpressions are unevaluated.
The point is that the TGE principle of operation seems simple enough to be transplanted without ever causing trouble later.
As for why C++ TGE's would be useful, aside from maximizing the intersection of C and C++, they could be used to essentially implement static_if, sans the highly controversial conditional declaration feature. I'm not a proponent of static_if, but "there is that."
template< typename t >
void f( t q ) {
auto is_big = _Generic( std::integral_constant< bool, sizeof q >= 4 >(),
std::true_type: std::string( "whatta whopper" ),
std::false_type: "no big deal"
);
auto message = _Generic( t, double: "double", int: 42, default: t );
std::cout << message << " " << is_big << '\n';
}
"Cannot be" is perhaps too strong. "Uncertain whether it's possible" is more likely.
If this feature were to be added to C++, it should be fully specified including all interactions with existing C++ features, many of which were not designed with _Generic in mind. E.g. typeid doesn't exist in C, but should work in C++. Can you use a _Generic expression as a constexpr? As a template parameter? Is it an lvalue ? Can you take its address and assign that to a function pointer, and get overload resolution? Can you do template argument deduction? Can you use it with auto? Etc.
Another complication is that the primary usecase for _Generic is for macro's, which don't play nice with C++ namespaces. The acos example from tgmath is a clear example. C++ already banned C's standard macro's and required them to be functions, but that won't work with tgmath.h.

condition execution using if or logic

when using objects I sometimes test for their existence
e.g
if(object)
object->Use();
could i just use
(object && object->Use());
and what differences are there, if any?
They're the same assuming object->Use() returns something that's valid in a boolean context; if it returns void the compiler will complain that a void return isn't being ignored like it should be, and other return types that don't fit will give you something like no match for 'operator&&'
One enormous difference is that the two function very differently if operator&& has been overloaded. Short circuit evaluation is only provided for the built in operators. In the case of an overloaded operator, both sides will be evaluated [in an unspecified order; operator&& also does not define a sequence point in this case], and the results passed to the actual function call.
If object and the return type of object->Use() are both primitive types, then you're okay. But if either are of class type, then it is possible object->Use() will be called even if object evaluates to false.
They are effectively the same thing but the second is not as clear as your first version, whose intent is obvious. Execution speed is probably no different, either.
Functionally they are the same, and a decent compiler should be able to optimize both equally well. However, writing an expression with operators like this and not checking the result is very odd. Perhaps if this style were common, it would be considered concise and easy to read, but it's not - right now it's just weird. You may get used to it and it could make perfect sense to you, but to others who read your code, their first impression will be, "What the heck is this?" Thus, I recommend going with the first, commonly used version if only to avoid making your fellow programmers insane.
When I was younger I think I would have found that appealing. I always wanted to trim down lines of code, but I realized later on that when you deviate too far from the norm, it'll bite you in the long run when you start working with a team. If you want to achieve zen-programming with minimum lines of code, focus on the logic more than the syntax.
I wouldn't do that. If you overloaded operator&& for pointer type pointing to object and class type returned by object->Use() all bets are off and there is no short-circuit evaluation.
Yes, you can. You see, C language, as well as C++, is a mix of two fairly independent worlds, or realms, if you will. There's the realm of statements and the realm of expressions. Each one can be seen as a separate sub-language in itself, with its own implementations of basic programming constructs.
In the realm of statements, the sequencing is achieved by the ; at the end of the single statement or by the } at the end of compound statement. In the realm of expressions the sequencing is provided by the , operator.
Branching in the realm of statements is implemented by if statement, while in the realm of expressions it can be implemented by either ?: operator or by use of the short-circuit evaluation properties of && and || operators (which is what you just did, assuming your expression is valid).
The realm of expressions has no cycles, but it has recursion that can replace it (requires function calls though, which inevitable forces us to switch to statements).
Obviously these realms are far from being equivalent in their power. C and C++ are languages dominated by statements. However, often one can implement fairly complex constructs using the language of expressions alone.
What you did above does implement equivalent branching in the language of expressions. Keep in mind that many people will find it hard to read in the normal code (mostly because, once again, they are used by statement-dominated C and C++ code). But it often comes very handy in some specific contexts, like template metaprogramming, for one example.

What is "formal semantics"?

I'm reading a very silly paper and it keeps on talking about how Giotto defines a "formal semantics".
Giotto has a formal semantics that specifies the meaning of mode switches, of intertask communication, and of communication with the program environment.
I'm on the edge of, but just cannot quite grasp what it means by "formal semantics."
To expand on Michael Madsen's answer a little, an example might be the behaviour of the ++ operator. Informally, we describe the operator using plain English. For instance:
If x is a variable of type int, ++x causes x to be incremented by one.
(I'm assuming no integer overflows, and that ++x doesn't return anything)
In a formal semantics (and I'm going to use operational semantics), we'd have a bit of work to do. Firstly, we need to define a notion of types. In this case, I'm going to assume that all variables are of type int. In this simple language, the current state of the program can be described by a store, which is a mapping from variables to values. For instance, at some point in the program, x might be equal to 42, while y is equal to -5351. The store can be used as a function -- so, for instance, if the store s has the variable x with the value 42, then s(x) = 42.
Also included in the current state of the program is the remaining statements of the program we have to execute. We can bundle this up as <C, s>, where C is the remaining program, and s is the store.
So, if we have the state <++x, {x -> 42, y -> -5351}>, this is informally a state where the only remaining command to execute is ++x, the variable x has value 42, and the variable y has value -5351.
We can then define transitions from one state of the program to another -- we describe what happens when we take the next step in the program. So, for ++, we could define the following semantics:
<++x, s> --> <skip, s{x -> (s(x) + 1)>
Somewhat informally, by executing ++x, the next command is skip, which has no effect, and the variables in the store are unchanged, except for x, which now has the value that it originally had plus one. There's still some work to be done, such as defining the notation I used for updating the store (which I've not done to stop this answer getting even longer!). So, a specific instance of the general rule might be:
<++x, {x -> 42, y -> -5351}> --> <skip, {x -> 43, y -> -5351}>
Hopefully that gives you the idea. Note that this is just one example of formal semantics -- along with operational semantics, there's axiomatic semantics (which often uses Hoare logic) and denotational semantics, and probably plenty more that I'm not familiar with.
As I mentioned in a comment to another answer, an advantage of formal semantics is that you can use them to prove certain properties of your program, for instance that it terminates. As well as showing your program doesn't exhibit bad behaviour (such as non-termination), you can also prove that your program behaves as required by proving your program matches a given specification. Having said that, I've never found the idea of specifying and verifying a program all that convincing, since I've found the specification usually just being the program rewritten in logic, and so the specification is just as likely to be buggy.
Formal semantics describe semantics in - well, a formal way - using notation which expresses the meaning of things in an unambiguous way.
It is the opposite of informal semantics, which is essentially just describing everything in plain English. This may be easier to read and understand, but it creates the potential for misinterpretation, which could lead to bugs because someone didn't read a paragraph the way you intended them to read it.
A programming language can have both formal and informal semantics - the informal semantics would then serve as a "plain-text" explanation of the formal semantics, and the formal semantics would be the place to look if you're not sure what the informal explanation really means.
Just like the syntax of a language can be described by a formal grammar (e.g. BNF), it's possible to use different kinds of formalisms to map that syntax to mathematical objects (i.e. the meaning of the syntax).
This page from A Practical Introduction to Denotational Semantics is a nice introduction to how [denotational] semantics relates to syntax. The beginning of the book also gives a brief history of other, non-denotational approaches to formal semantics (although the wikipedia link Michael gave goes into even more detail, and is probably more up-to-date).
From the author's site:
Models for semantics have not
caught-on to the same extent that BNF
and its descendants have in syntax.
This may be because semantics does
seem to be just plain harder than
syntax. The most successful system is
denotational semantics which describes
all the features found in imperative
programming languages and has a sound
mathematical basis. (There is still
active research in type systems and
parallel programming.) Many
denotational definitions can be
executed as interpreters or translated
into "compilers" but this has not yet
led to generators of efficient
compilers which may be another reason
that denotational semantics is less
popular than BNF.
What is meant in the context of a programming language like Giotto is, that a language with formal semantics, has a mathematically rigorous interpretation of its individual language constructs.
Most programming languages today are not rigorously defined. They may adhere to standard documents that are fairly detailed, but it's ultimately the compiler's responsibility to emit code that somehow adheres to those standard documents.
A formally specified language on the other hand is normally used when it is necessary to do reasoning about program code using, e.g., model checking or theorem proving. Languages that lend themselves to these techniques tend to be functional ones, such as ML or Haskell, since these are defined using mathematical functions and transformations between them; that is, the foundations of mathematics.
C or C++ on the other hand are informally defined by technical descriptions, although there exist academic papers which formalise aspects of these languages (e.g., Michael Norrish: A formal semantics for C++, https://publications.csiro.au/rpr/pub?pid=nicta:1203), but that often do not find their way into the official standards (possibly due to a lack of practicality, esp. difficulty to maintain).