Fundamental Concepts and Definitions Identifier / Symbol / Name These terms are synonymous: they refer to the name given to a programming component. Classes, variables, functions, and methods are the most common named components of a program. Unresolved symbol errors are common during Java program development: ThumbFrame.java:445: cannot resolve symbol symbol : variable paused location: class ThumbFrame paused = false; ^ The error message indicates the file in which the error was found (ThumbFrame.java), the line on which the error occurred (445), and the identifier or symbol in question (paused). If the error refers to a variable (as in the above example), verify that an appropriate variable definition is in scope and that the variable is spelled correctly (including capitalization) in both the definition and in the use. Methods are more challenging: ScrapBook.java:202: cannot resolve symbol symbol : constructor ThumbFrame (java.io.file) location: class ThumbFrame new ThumbFrame(); ^ Although verifying correct spelling is still the first step, there are more aspects of method calls that must be examined. First, verify that number and the type of parameters in the call match the number and the type of the arguments in the definition. Second, in a pure object-oriented language, methods are always defined in a class. Therefore, non-static method calls must be bound to objects and static methods are invoked through the class. Verify that the method is bound to an appropriate caller: caller.method(); If method is non-static, them caller must be an object instantiated from a class that defines method. If method is static, then caller is the name of the defining class. Note that caller can also be the assumed keyword this implying that the calling object is the object bound to the currently executing method. For example, the object that invokes method1 also invokes method2 from the body of method1. public void method1() method2(); public void method2()... Lastly, if the unresolved symbol is a constructor method call (as in the above example), it must be preceded by the new operator (see C++, p. 109). Any of these problems may cause an unresolved symbol error and each must be examined.
Constants Literal A literal constant names its own value. For example: 100 and 3.14159 are numeric literal constants; A is a character constant and Hello is a string constant. Literal constants evaluate to their own value. Symbolic / Named A symbolic or named constant is a value that has been given a name so that it may be referred to symbolically. Symbolic constants evaluate to the value assigned to them when they were created. Compile Time A compile time constant is defined prior to (e.g., by the preprocessor) or at the beginning of program compilation; compile time constants are necessary to statically define arrays in C and C++. (#define and enum s qualify as compile time constants in C and C++; const s may qualify in C++ but never do in C.) Symbolic / Named Constant Examples #define PI 3.14159 C and C++ enum my_constants ERROR, OKAY, PI = 3.14159 ; C and C++; ERROR is 0, OKAY is 1, PI is self explanatory const double PI = 3.14159; C++ but must be defined outside of any function or class for it to be a compile time constant public static final double PI = 3.14159; Java public and static are not required but are typical Definition vs Declaration Many authors do not distinguish between a definition and a declaration. When a distinction is made, it is only relevant in C and C++. Java does not utilize declarations (as defined below) because it is implemented as a multi-pass compiler with dynamic class loading. Therefore, many Java texts will use declaration synonymously with definition. Declaration A declaration is a syntactic construct that associates information with an identifier. It introduces the identifier to the compiler and establishes a scope for it. If it is a variable, then the information associated with the identifier is its data type. If the identifier is a function/method, then the information includes the return type and the number and type of the arguments. In C and C++, functional prototypes (often placed in header or.h files) and variables preceded by the extern keyword are declarations. Definition A definition allocates storage (i.e., memory) for an identifier. If the identifier is a function/method, the definition also causes the compiler to generate machine the code. A definition can also be a declaration if it is the first time that the compiler has encountered the identifier (but a declaration is never a definition).
Variable definitions always include two elements: the data type and the variable name. For example: int counter; Employee manager; Function/method definitions are characterized by having a body; function/method declarations may have all of the components of a definition except the body. public double square(double number) return number * number; The body is enclosed between the braces (i.e., the body is a block). Variables Although somewhat of an over simplification, memory can be viewed as a long linear array or table. A variable is a named region of memory and has two properties: 1. An address; this is a physical property that is determined by the location of the variable in memory and that does not change. A memory address is like a house address, which is determined by its physical location on a street. 2. A content; this is the value that the memory remembers. Each variable stores a value as a bit-pattern of ones and zeros. The data type of the variable specifies the size of the variable (i.e., the number of bits) and how the bits are interpreted (i.e., as a number, a character, a string, etc.). A computer program can change the contents of a variable by storing a new value in to it. In the terms of the house analogy, the house stays in one location year after year, but different families may move in and out of the house. It is because the contents of a variable can change or vary over time that we call small subunits of memory variables. A computer program, while running, accesses variables by address. However, addresses are not convenient for us to use when writing a program so we give each variable a name. This is easier to remember than an address and conveys an idea about what the variable is used for (i.e., about what is stored in the variable). The compiler converts each variable name into an address that computer can use. int count; 10052 73... double radius; 10056 79.175534 char terminal; 10064 \n...
Object Instantiation Every object is an instance of a class. Think of classes as a blueprint or a cookie cutter and objects as the houses created from the blueprints or the cookies stamped out from the cookie cutter. Just as blueprints describe a house, classes describe objects. The class name becomes a type specifier. This means that the class name may be used as a new data type and used to define or instantiate Person -name : char[100] -height : float -weight : int +Person(in n : char*) new variables. C++ supports two object instantiation techniques: static and dynamic. These two techniques can be illustrated in terms of the Person class described by the UML class diagram at the right. Static Instantiation Person suspect( Cranston ); Dynamic Instantiation Person* accomplice = new Person( Snort ); suspect name: weight: height: Cranston accomplice name: weight: height: Snort Static Instantiation. An object (the rectangle) is instantiated statically (i.e., at compile time), memory is allocated and the constructor is called to initialize the allocated memory, which forms an object. The contents of the variable (suspect) is an object (instantiated from class Person). Dynamic instantiation. An object (the large rectangle in the illustration on the right) is instantiated dynamically (i.e., at run time) by the new operator. The new operator performs three tasks: (a) it allocates memory to hold the object, (b) it calls the constructor to initialize the memory, and (c) it returns the address of the new object. The address of the object (returned by new) is often stored in a pointer variable (accomplice the small rectangle in the illustration on the right). The variable accomplice has an address but also contains an address (the address of the new Person object). The name of the pointer variable (accomplice) names the object (i.e., provides a name or handle through which the programmer uses the object). The instantiation may also be performed in two steps: Person* accomplice; accomplice = new Person( Snort ); Java only supports dynamic object instantiation and has a similar syntax: Person accomplice = new Person( Snort ); or Person accomplice; accomplice = new Person( Snort );
Function/Method Call vs Definition When a function/method is defined, the definition includes all typing information: the return type and the type of each parameter. Depending on the language (e.g., Java), the definition may also include modifiers (e.g., public ). This information (everything except the body), is called a signature. Signatures and declarations look similar but serve different purposes. Both indicate how a function/method is defined. However, declarations are programming language statements (usually a declaration and the corresponding definition are in different locations within a program: in different files or the declaration precedes the definition if in the same file). Signatures are descriptive but are not program statements. They are often published as part of the documentation for library routines, API calls, or are used in written and verbal communication. When a function/method is called, no typing information is included in the call. E.g.: double square (double number)... y = square(x); // definition // call Function/methods defined in a class (i.e., a member function in C++ and all methods in Java) must be bound to an object when called. This binding is implicit (i.e., not shown) in the definition and in the signature (used in documentation) but must be made explicit (i.e., it must be shown) in the method call. The following example shows a Java method definition, its signature as it would appear in documentation, an object instantiation, and a method called though that object: public class JTextField public void settext(string text)... public void settext(string text) JTextField size = new JTextField(10); size.settext( Hello world ); // definition // signature //instantiation // call Note that JTextField size defines a variable named size but does not instantiate a JTextField object. The object is instantiated with the expression new JTextField(10);. Failing to instantiate the object will result in a runtime error. E.g., the statements: JTextField size; size.settext( Hello world ); will cause a null pointer exception runtime error.
Scope The visibility of variables within a program. There may be multiple, independent definitions of the same name or identifier in different parts of a program. The scope rules of a language determine which definition of an identifier applies when the identifier appears in the text of a program. The portion of the program to which a definition applies is called the scope of that definition. Global Scope A variable defined outside of any function or class has global scope (i.e., it is visible or accessible throughout the program). C and C++ permit global definitions but Java does not. Class Scope An identifier (variable or function/method) defined inside of a class has class scope (i.e., is visible or accessible from any function/method also defined in the same class. In C++, such identifiers are called members: member functions or member data. Java refers to variables defined in class scope as instance variables or instance fields because they belong to a given instance or object of the class. Static class scope variables are called class variables because they belong to the class as a whole and not to a specific instance. Java does not allow method definitions outside of classes so no distinguishing notation is needed. Local Scope Variables defined inside of a function/method has local scope (i.e., it is only visible or accessible within the defining function/method). Local scope variables are defined in one of two locations: within the body of the function/method or in the argument list (i.e., arguments are also local variables). If a function/method defines a variable with the same name as a class scope variable, the local definition shadows or hides the class scope variable. Block Scope The scopes defined above are special, albeit important, cases of block scope. A block is a statement containing its own local definitions. In C, C++, and Java, blocks begin with a and end with a. When a block ends, all definitions occurring within the block become unaccessible and the memory is deallocated. Blocks may be nested (a property sometimes referred to as block structure). In some cases, identifiers with the same name may be defined at different nesting levels. The inner most definition shadows or hides the outer definitions, which is a common source of programming errors. Java disallows some of these definitions (see Block Scope, p. 60). However, one common problem is related to the object model itself and is the responsibility of the programmer to understand (see the Caution on p. 109 and cross-reference with p. 107). Two common variations of this problem are illustrated by the following two examples:
Incorrect private Bar mybar; Correct private Bar mybar; public Foo(int i) Bar mybar = new Bar(i); public Foo(int i) mybar = new Bar(i); A local variable definition shadows the instance variable. The local variable goes out of scope at the end of the constructor and the instance variable is never initialized. Incorrect private int cost; Correct private int cost; Correct private int cost; public Foo(int cost) cost = cost; public Foo(int count) this.cost = cost; public Foo(int c) cost = c; Constructors are frequently used to initialize instance variables. Data are passed in to the constructor as arguments and then assigned to instance variables. However, problems arise when the instance variables and method arguments have the same name (a technique practiced by some Java programmers including those that programmed the API). In the incorrect example, cost = cost; simply assigns the argument to itself. The problem may be solved by using the this keyword: this.cost = cost; The this reference contains the address of the object calling the method (i.e., the this reference binds the calling object to the method) and always refers to the class scope. A more simple solution is to use different names for the variables (as in the last example).
Expression An expression is any legal combination of symbols that represents a value (i.e., anything whose evaluation produces a value). An expression may be simple like a constant (the value of the constant becomes the value of the expression or a variable (which evaluates to the last value assigned to it by the program i.e., the value stored in it). An expression may also consist of a function or method call that returns a value; the returned value is the value of the expression. More complex expressions consist of these simple expressions joined with operators. Operators are symbols such as +, *, <, and && that represent an operation or action on one or more operands. An operand is the input or the value upon which the operator acts. In C, C++, and Java, operands are expressions. Some operators are denoted by words and may be difficult to distinguish from function or method calls. For example: Operators Function / Method Calls sizeof counter sin(m_pi / 2) source instanceof JButton Math.sin(Math.PI / 2) new Employee( Snort ) return counter event.getsource() System.out.println(count) In the third operator example, new is an operator but Employee( Snort ) is a constructor (i.e., a function or method) call. In the third function/method example, getsource is a method call but the dot (i.e., the period) is an operator called the dot operator. Syntactically, the difference is that function/method calls require parentheses (which are, ironically, operators) but operators do not. The return operator is frequently mistaken for a function: return(expression). However, the parentheses used here are for grouping rather than signaling a function/method call. (On the other hand, both versions with and without parentheses compile and accomplish the same thing.) Statement A statement is a single instruction written in a high-level language that is used to perform a specific task or action. In C, C++, and Java, statements are terminated by a semicolon. A single high-level language statement typically represents many machine-language instructions. Programs consist of statements and expressions.