You are on page 1of 70

CSC 309: Survey of Programming

Languages (3 Units)

Declarations and Types


By
Dr S. M. Mafara
CHARACTERISTICS OF VARIABLES
• In computer programming, a declaration is a
language construct that specifies properties of
an identifier: It declares what a word (identifier)
"means".
• Declarations are commonly used for functions,
variables, constants, and classes, but can also be
used for other entities such as type definitions.
Beyond the name (the identifier itself) and the
kind of entity (function, variable, etc.),
declarations typically specify the data type (for
variables and constants)
• A declaration is used to announce the
existence of the entity to the compiler; this is
important in those strongly typed languages
that require functions, variables, and
constants, and their types to be specified with
a declaration before use, and isused in
forward declaration. The term“ declaration“ is
frequently contrasted with the term“
definition", but meaning and usage varies
significantly between languages.
Declaration vs. definition
• Declarations are particularly
prominent in languages SUCH AS
ALGOL, BCPL family, most
prominently C and C++, and also
Pascal.
• Java uses the term“ declaration",
though Java does not have separate
declarations and definitions
• A basic dichotomy is whether a declaration contains a
definition or not:
• for example, whether a declaration of a constant or
variable specifies the value of the constant
(respectively, initial value of a variable), or only its
type;
• and similarly whether a declaration of a function
specifies the body (implementation) of the function, or
only its type.
• Not all languages make this distinction: in many
languages, declarations always include a definition,
and may be referred to as either "declarations“ or“
definitions", depending on the language.
• In informal usage, a "declaration“ refers only to a pure
declaration (types only, no value or body), while a
"definition“ refers to a declaration that includes a value
or body.
• However, informal usage (in language specifications),
"declaration“ includes both of these senses, with finer
distinctions by language:
• in C and C++, a declaration of a function that does not
include a body is called a function prototype, while a
declaration of a function that does include a body is
called a "function definition".
• By contrast in Java declarations always include the
body, and the word "definition“ has no technical
meaning in Java
C++ PROTOTYPE & DEFINITION
• Declaration
• Int a, b, c;
• Char ans;

• Definition
• Int a = 20;
• Int b = 40;
• Char ans = ‘Y’;

• C = a + b;
Sizes of fundamental Types are:
• A declaration specifies the interpretation and
attributes of a set of identifiers.
• A definition of an identifier is a declaration for
that identifier that:
– for an object [variable or constant], causes storage to
be reserved for that object;
– for a function, includes the function body;
– for an enumeration constant, is the (only)declaration
of the identifier;
– for a typedef name, is the first (or only)declaration of
the identifier."
Declaration Models
• Names, variables
• Binding
• Scope
–-Visibility
• Constants. Variable initialization
Names
• A name is a handle on an entity in a
program. We refer to something by a
name if we want to create, use, change,
destroy it.

• •Declaration, use, lifetime, scope of


names: these properties are a major
consideration in programming languages
What needs a name?
• • constants, variables,
• •operators,
• •statement labels,
• •types,
• •procedures, functions, methods,
• •modules, programs,
• •files, disks,
• •commands, menu items,
• •computers, networks, user (login name)
Names and identifiers
• A name is denoted by an identifier.
• •Typical identifiers are built of
letters, digits and underscores, but
some languages allow "funny"
identifiers as well. Prolog, Scheme
and Perl are in this category
Declaration Models
• Names, variables
• Binding
• Scope
–-Visibility
• Constants. Variable initialization
Variables
• •Variables are abstractions for memory cells of the
computer.
• Variables attributes are name, address, value, type,
lifetime, scope
For example, if we write
int x;
we decide what will be the name and type of x.
• •The place of this declaration in the program decides where
and how long x is available (scope, lifetime).
• Its address is determined when its program unit is executing,
• Finally, using x in statements decides what is its current
value.
• •A problem in most programming languages:
• the same name can be reused in different contexts and denote
different entities. For example:
void a() {
• int b; /* ... */
}
float b() {
• char a; /* ... */
}
• •Different types, addresses and values may be associated with
such occurrences of a name.
• Each occurrence has a different lifetime (when and for how long is
an entity created?), and a different scope (where can the name be
used?).
Values of variables
• •The concept of value is more general:
– l-value (l for left) and
– r-value (r for right) are the source and target of an assignment. An example:
x = y;
l-value
• is the address of x,
r-value
• is the value of y.
• This becomes complicated for array elements that denote addresses
which must be evaluated:

T[i*2+1] = y;
• •This address depends on the current value of i.
Undefined variables
• In some programming languages, an implicit
declaration is provided the first time such a
variable is encountered at compile time.
• In other languages, such a usage is considered
to be an error, which may resulting in a
diagnostic message.
• Some languages have started out with the
implicit declaration behavior, but as they
matured they provided an option to disable it
(e.g. Perl's "use strict", Visual Basic's use
"Option Explicit").
How to Declare Variables in Java
• To reference a variable in a Java
program, you must first declare it. To
declare a variable, see this,

• Or in Pascal, see this


Declaration Models cont…
• Names, variables
• Binding
• Scope
–-Visibility
• Constants. Variable initialization
Binding
• An informal presentation
• Binding times
• Bindings of a variable
• Lifetime
Binding
• Binding is not formally defined. Intuitively, we can
say that it is (that is, binding) an attribute with an
entity. Examples of attributes are name, type, value.
• Binding occurs at various times in the life of a
program. Three periods are usually considered:
– compile time(actually, translation time, because binding
happens both in compilers and interpreters);
– load time(preparing object code for execution, pulling in
the necessary code for built-in operations or operations
defined in libraries of modules);
– run time(between starting the program's execution and
its termination).
Static and dynamic binding
• We also distinguish two kinds of
binding, depending on its duration:
– static binding is permanent during the life
of the program;
– dynamic binding is in force during some
part of the program's life
Assigning properties to variables
• •variable - name
– •compile time
• –described in declarations
• •variable - address
– •load time or run time (e.g. C),
– •run time (e.g. Smalltalk)
• –this is usually done implicitly
• •variable - type
– •compile time (e.g. Java),
– •run time (e.g. Scheme)
• –described in declarations, if bound at compile time
Assigning properties cont…
• •variable - value
– •run time,
– •load time (initialization)
• –specified in statements, mainly assignment
• •variable - lifetime
– •compile time
• –described in declarations
• •variable - scope
– •compile time
• –expressed by placement of declarations
Lifetime
• This refers to when and for how long is an
entity created
• Allocation of memory for an entity
happens at load time or at run time.

• Two classes of variables are distinguished:


– •Static variables
– •Dynamic variables
Static variables
• Memory for static variables is allocated
once, before the program begins
execution.
• Fortran IV was an important language with
such an allocation policy for all variables.
– This was inflexible, but it also was
conceptually simple and inexpensive.
– Recursion was not possible.
Dynamic variables
• Allocation is done after the program has started.
• Two possibilities of dynamic allocation.
– Explicit allocation and deallocation, that is, the
programmer must do it.
– This is what we do when we use pointers; for
example, in Pascal we allocate using new(p),
deallocate using dispose(p). In C we use malloc().
– Implicit allocation (when a block is entered) and
deallocation (when a block is exited).
Declaration Models
• Names, variables
• Binding
• Scope
–-Visibility
• Constants. Variable initialization
Scope
• Description of scope
• Examples of scope
• Blocks and block structure
• Anonymous blocks
• Nesting diagrams
• Call graphs
• Static and dynamic scoping
• The scope of a variable is the range of statements
over which it is visible
– •A variable is visible in a statement if it can be referenced
in that statement

• Scope of a variable can be statically determined


– •Based on program text, a spatial concept
• To connect a name reference to a variable, you (or
the compiler) must find the declaration
– First search locally, then in increasingly larger enclosing
scopes,
– until one is found for the given name, or
– an undeclared variable error
• There are two basic types of scope:
– local scope and
– global scope.
• A variable declared outside all functions is
located into the global scope.
• Access to such variables can be done from any
where in the program.
• These variables are located in the global pool
of memory, so their life time coincides with
the lifetime of the program.
• A variable declared inside a block (part of code
enclosed in curly brackets) belongs to the local
scope.
• Such a variable is not visible (and therefore not
available) outside the block, in which it is
declared.
• The most common case of local declaration is a
variable declared within a function.
• A variable declared locally, is located on the
stack, and the lifetime of such a variable is equal
to the lifetime of the function.
• Since the scope of a local variable is
the block in which it is declared,
• it is possible to declare variables with
the same name, as those of variables
declared in other blocks;
• as well as of those declared at upper
levels, up to the global level.
• Pay attention to the variable i, declared in line
• for(int i=begin; i<limit; i++)
• {
int k = I – begin + 1;
weightsum += k;
firstValue += k * price[i];
}
• Its scope is only the for loop; outside of this loop
there is another variable with the same name,
declared at the beginning of the function. In
addition, the k variable is declared in the loop
body, its scope is the loop body
• Local variables can be declared with the access
specifier static.
• In this case, the compiler has a variable in the
global pool of memory.
• Therefore, the lifetime of a static variable is equal
to the life time of the program.
• Here the scope of such a variable is limited to the
block in which it is declared.
Scope varies among languages.
• Some allow scopes to be nested; every block or
statement can contain declarations.
• Some allow declarations anywhere within a block,
some only prior to any executable statements.
• Some allow function declarations to be nested
(Pascal does, C does not).
• Some are even more complicated with special
rules for some types of statements (Ada).
• There are five scopes in C: program, file, function,
block, and prototype
declarations anywhere within a block
function declarations to be nested
Blocks and block structure
• Block: It is a method of creating new static
scopes inside program units (from ALGOL 60)
• e.g.: C and C++ in any compound statement
for (...) {
int index;
...
}
An Example of Block Scope in C
Blocks and block structure
• We group declarations and statements in order
to
– •keep steps of a non-elementary activity together
(e.g., all steps of a sorting algorithm),
– •ensure proper interpretation of names.
• Names are bound to various elements of a
program. We refer to names in statements.
• The scope of a name N means all places in the
program where N denotes the same object.
• •Blocks can be nested. Names introduced in a block
are called local bindings.
• A name referred to, but not declared, in a block must
have been declared in a surrounding block.
• •Nesting of blocks is possible many languages,
including C and its descendants.
• Nesting of procedures is allowed in Algol 60 and its
descendants, but not in C.
• •A program, procedure or function consists of a
heading and a named block.
• This is opposed to anonymous blocks, available in
Algol 60, Algol 68, PL/I, Ada and C –but not in Pascal.
Imagine C with nested functions

• main P() {
int X;
void A() {
char Y;
void B() {
float Z;
SB}
SA }
void C() {
int Z;
SC }
SP}
Call graphs
• Show which program units can call other units
• A loop "to itself" indicates possible recursion
• main P() {
int X;
void A() {
char Y;
void B() {
float Z;
SB}
SA }
void C() {
int Z;
SC }
SP}
Visibility, or the referencing environment
• Read U.V as "variable V declared in unit U".
• main P() {
int X;
void A() {
char Y;
void B() {
float Z;
SB}
SA }
void C() {
int Z;
SC }
SP}
Hole-in-scope (hiding):
• the same name is used in an enclosing block
and a nested block
• The visible variables in SP: P.X, P.Y
• The visible variables in SA: P.A.X, P.Y, P.A.Z
• The visible variables in SB: P.X, P.B.Y, P.B.Z
• That is, P.X is visible everywhere in P except in SA, where
P.A.X hides it and itself becomes visible.
• P.Y is visible everywhere in P except in SB, where P.B.Y
hides it and itself becomes visible.
• There is no hole in the scope of P.A.Z or P.B.Z because
they have disjoint areas of visibility
Types of scoping
• •So far we saw static scoping (lexical scoping). It
allows us to determine the use of every variable
in a program statically, without executing it.

• •Dynamic scoping is an alternative with unclear


advantages. The idea is to search for a name in a
chain of called procedures, starting from the
main program. This chain is built according to
the visibility rules, but regardless of nesting.
Scoping example
• main P(){ • The main program calls B, then
int X; B calls A. When A prints X,
void A(){
which X is it?
X = X + 1;
print(X); • With static scoping, it is X in P,
} the enclosing block of
void B(){ procedure A. The number
int X;
printed will be 24.
X = 17;
A(); • With dynamic scoping (search is
} done up the chain of calls), it is
X = 23; X in B, the most recently
B();
• }
entered block with a declaration
of X. The number printed will be
18.
Dynamic scoping
• •The dynamic scoping rule has been used in APL,
SNOBOL-4 and in classic Lisp. It is not used much today.
• Even Common Lisp, a recent standard, has adopted
static scoping.
• •Dynamic scoping is easier to implement than static
scoping, but:
– •it is not possible to understand at compile time which
variables refer to which objects, that is, type checking is
impossible at compile time;
– •internal variables are not protected in the way we have
come to expect: in our example X is local in B but A can
nevertheless access it.
• •To reuse the same Identifier within a program
requires the use of scope, hiding, and visibility.
• •The scope of a variable is the part of program
or block of program in which it is visible.
• •A variable is visible within its scope and
invisible or hidden outside it.
• •Life time of variable define the time for which
the variable exists in a program.
• •Scope determine the life time and visibility of
variable.
• •Variables can be bound to a scope either
statically or dynamically.
Other example of scope, lifetime and visibility in
C programming Language
• Often, programmers confuse the scope, lifetime
and visibility of variables.
• When ever you declare a variable, you determine
its scope, life time and visibility.
• These three are important concepts associated
with any variable declared in C.
• Understanding the difference between them, and
how they are related to each other, will help avoid
mistakes in writing code.
Scope
• Scope is defined as the area in which the
declared variable is ‘available’.
• There are five scopes in C: program, file,
function, block, and prototype.
• Let us examine a dummy program to
understand the difference (the comments
indicate the scope of the specific variable):
Scope
• The foo function has program scope.
• All non-static functions have program scope, and they can be called
from anywhere in the program.
• Of course, to make such a call, the function needs to be first
declared using extern, before being called, but the point is that it is
available throughout the program.
• The function bar has file scope —it can be called from only within
the file in which it is declared.
• It cannot be called from other files, unlike foo, which could be called
after providing the external declaration of foo. The label print has
function scope.
• Remember that labels are used as a target for jumps using goto in C.
• There can be only one print label inside a function, and you can
write a goto print statement anywhere in the function, even before
the label appears in the function.
• Only labels can have function scope in C.
• The variable i has block scope, though declared at
the same level/block as print. Why is that so?
• The answer is, we can define another variable with
the same name i inside another block within the
bar function, whereas it is not possible for print,
since it is a label.
• The variable j has prototype scope: you cannot
declare any other parameter with the same name j
in the function baz.
• Note that the scope of j ends with the prototype
declaration: you can define the function baz with
the first argument with any name other than j.
Lifetime(again)
• The lifetime of a variable is the period
of time in which the variable is
allocated a space (i.e., the period of
time for which it “lives”).
• There are three lifetimes in C: static,
automatic and dynamic. Let us look at
an example:
• In this code, the variable
• intfoo() { count has a static
• static int count = 0; lifetime, i.e., its lifetime is
• // "count" has static lifetime that of the program.
• The variable counter has
• int* counter = malloc (sizeof an automatic lifetime —
(int)); its life is till the function
• // "counter" has automatic returns; it points
lifetime • to a heap-allocated
• memory block —its life
free(counter);
remains till it is explicitly
• // malloc’ed memory has deleted by the program,
dynamic lifetime • which is not predictable,
• } and hence it has a
dynamic lifetime
Visibility
• As you can see, scope, lifetime and visibility are related to
each other, but are distinct. Scope is about the
‘availability’ of the declared variable:
• within the same scope, it is not possible to declare/define
two variables of the same type with the same name.
• Lifetime is about the duration in which the variable is
‘alive’:
• it determines how long the name do run named variable
has memory allocated to it.
• Visibility is about the ‘accessibility’ of the declared
variables:
• it arises because of the possibility of variables in outer
scope having the same name as the ones in inner scopes,
resulting in ‘hiding’.
Overview of Type checking

• •Operations and operands


• •Strong typing
• •Conversion and coercion
Types of operations
• Operations in programming languages normally
require operands (arguments) of well-defined,
specific types.
• Examples of operations
• •Boolean (comparison, conjunction, disjunction
etc.),
• •arithmetic (+, -, *, /, sin, tan, exp etc.),
• •string (concatenation, substring etc.),
• •assignment (this is an operation with two
arguments),
• •passing a parameter to a procedure
Type checking
• •Type checking ensures that an operator —
when it is applied —gets arguments that it can
handle.
• Type checking is done at compile time or at run
time.
• •A type error occurs when an argument of an
unexpected type is given to an operation.
• This too can be signalled at compile time or at
run time
Strong typing
• •A programming language has strong typing when all
type errors can be discovered at compile time. This is
not easy to achieve even in a strict language such as
Pascal or Java.
• •Problem from Pascal: subtypes of enumerated types.
• type
– day = (mo,tu,we,th,fr,sa,su);
– workday = (mo,tu,we,th,fr);
• var x : day; y : workday;
• {...}
• y := x; {???}
Strong typing (2)
• •A relaxed definition of strong typing: all
errors can be discovered, preferably at
compile time.
• •It is interesting that no popular programming
language features perfect strong typing.
• There are always minor (or major) exceptions.
Java is quite good on this count.
But…

• •Strict typing of operands is elegant and desirable, but it


may be impractical. What happens if two operands make
some sense together?
• •Example:
– float x; int n = 2;
– x = n * 3.14;
• •This multiplication may be rejected by a strict compiler.
We normally use an explicit conversion (also known as a
type cast, in Java):

– x = float(n) * 3.14;

You might also like