Sunteți pe pagina 1din 8

FACULTY OF SCIENCE

COMPUTER SCIENCE DEPARTMENT

COMP 400 PROGRAMMING LANGUAGE DESIGN Name: CHARLES KIREKI

Reg No.: SP13/20527/08

SUBMITTED TO MR VICTOR KEBANDE

TYPE SYSTEMS
A type meaningful subset of the set of the domain of data values used in a program. Types are used to describe the intended behavior of program operations. The concept is derived from mathematics; functions have specified domain and co-domains sets which are often called types. In fact, a function with domain A and co-domain B is often said to have type A B. Moreover, the variables used in mathematical formulas typically have specified types In computer programs, some forms of type checking can be formalized and automated. Static vs. dynamic typing In a statically typed language, every variable name is bound both

To a type (at compile time, by means of a data declaration) To an object.

The binding to an object is optional if a name is not bound to an object, the name is said to be null. Once a variable name has been bound to a type (that is, declared) it can be bound (via an assignment statement) only to objects of that type; it cannot ever be bound to an object of a different type. An attempt to bind the name to an object of the wrong type will raise a type exception. In a dynamically typed language, every variable name is (unless it is null) bound only to an object. Names are bound to objects at execution time by means of assignment statements, and it is possible to bind a name to objects of different types during the execution of the program. SMALLTALK, LISP, PROLOG, PERL, and PYTHON are examples of dynamically typed languages. The choice between static and dynamic typing is essentially pragmatic: Static typing is more efcient. Dynamic typing requires (possibly repeated) run-time type checks, which slow down the programs execution. Static typing requires only compile-time type checks, whose cost is minimal (and one-off). Moreover, dynamic typing forces all values to be tagged (in order to make run-time type checks possible), and these tags take up storage space. Static typing requires no such tagging. Static typing is more secure: the compiler can certify that the program contains no type errors. Dynamic typing provides no such security. Dynamic typing provides greater exibility, which is needed by some applications where the types of the data are not known in advance. In practice the greater security and efciency of static typing outweigh the greater exibility of dynamic typing in the vast

majority of applications. It is no coincidence that most programming languages are statically typed.

Type equivalence Consider some operation that expects an operand of type T1. Suppose that it is given instead an operand whose type turns out to be T2. Then we must check whether T1 is equivalent to T2, written T1 T2. What exactly this means depends on the programming language. One possible denition of type equivalence is structural equivalence: T1 T2if and only if T1 and T2 have the same set of values. Structural equivalence is so called because it may be checked by comparing the structures of the types T1 and T2. (It is unnecessary, and in general even impossible, to enumerate all values of these types.)The following rules illustrate how we can decide whether types T1 andT2, dened in terms of Cartesian products, disjoint unions, and mappings, are structurally equivalent or not. (We could similarly phrase the rules in terms of the types of a specic programming language.) If T1 and T2 are both primitive, then T1 T2 if and only if T1 and T2 are

identical. For example: Integer Integer but Integer /Float (The symbol / means is not equivalent to.) If T1 = A1 B1 and T2 = A2 B2, then T1 T2 if and only if A1 A2 and

B1 B2. For example: Integer Float Integer Float but Integer Float /Float Integer If T = A1 B1 and T2 = A2 B2, then T1 T2 if and only if A1 A2

and B1 B2. For example: Integer Float Integer Float but Integer Float /Integer Boolean

If T1 = A1 + B1 and T2 = A2 + B2,then T1 T2 if and only if either

A1 A2 and B1 B2,or A1 B2 and B1 A2. For example: Integer + Float Integer + Float Integer + Float Float + Integer but Integer + Float /Integer + Boolean Otherwise, T1 /T2.

Although these rules are simple, it is not easy to see whether two recursive types are structurally equivalent. Consider the following: T1 = Unit + (S T1) T2 = Unit + (S T2) T3 = Unit + (S T2)

The Type Completeness Principle It says that no programming language operation should be arbitrarily restricted in the types of its operands. For example, in Haskell, a function can take an argument of any type, including a function type, and a tuple may contain a function. To a large extent, Haskell satises the type completeness principle on the value level. There are exceptions, however. For example, it is not possible to pass a polymorphic function as argument. Pascal does not satisfy the type completeness principle, since, for example, procedures cannot be part of composite values.

EXPRESSIONS
An expression is a construct that will be evaluated to yield a value. Forms of expressions: Literals Constant/variable accesses Constructions Function calls Iterative expressions.

Literals Literals or constants are the values we write in a conventional form whose value is obvious. Literals represent the possible choices in primitive types for that language. Some of the choices of types of literals are often integers, floating point, Booleans and character strings. Constructions A construction is an expression that constructs a composite value from its component values. In C, the component values are restricted to be literals. In Ada, Java, and Haskell, the component values are computed by evaluating sub expressions. Java objects constructions examples: 1. Assume: class Date { public int m, d; public Date (int m, int d) { this.m = m; this.d = d; } } 2. Object constructions: Date today = new Date(12, 25);

Date tomorrow = new Date(today.m, today.d+1); C or C++ structure constructions example The following C or C++ structure construction: {jan, 1} constructs a value of the type Date C++ array constructions example: In the following C++ code: int size[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; ... if (is_leap(this_year)) size[feb] = 29; an array construction is used to initialize the variable size. The component values must be literals.

Function calls A function call computes a result by applying a function to some arguments. If the function has a single argument, a function call typically has the form F(E), or just F E, where F determines the function to be applied, and the expression E is evaluated to determine the argument. In most PLs, F is just the identifier of a specific function. However, in PLs where functions as firstclass values, F may be any expression yielding a function. E.g., this Haskell function call:(if then sin else cos)(x) If a function has n parameters, the function call typically has the form F(E1, , En ). We can view this function call as passing a single argument that is an n-tuple. An operator may be thought of as denoting a function.

Applying a unary operator to its operand is essentially a function call with one argument: E is essentially equivalent to (E) Applying a binary operator to its operands is essentially a function call with two arguments: E1 E2 is essentially equivalent to (E1, E2) Thus a conventional arithmetic expression is essentially equivalent to a composition of function calls: a * b + c / d is essentially equivalent to +(*(a, b), /(c, d)) The convention whereby we write a binary operator between its two operands is called the inx notation, which is adopted by nearly all programming languages. The alternative convention whereby we write every operator before its operands is called the prex notation, which is adopted only by LISP among the major programming languages. Examples of JAVA operators: The unary operator ! denotes the function {falsetrue, truefalse} in BooleanBoolean. The binary operator % denotes the remainder function in Integer IntegerInteger. The binary operator + denotes several functions at the same time: integer addition in Integer Integer Integer, real addition in Float Float Float, and concatenation in String StringString.

Iterative expressions An iterative expression is one that performs a computation over a series of values (typically the components of an array or list), yielding some result .Iterative expressions are uncommon, but they are supported by Haskell in the form of list comprehensions. Haskell list comprehensions Given a list of characters cs, convert all lower case letters to uppercase, yielding a modified list of characters: [if isLowercase c then toUppercase c else c | c <- cs]

Given a list of year numbers ys, compute a list (in the same order) of those year numbers in ys that are not leap years: [y | y <- ys, not(isLeap y)]

Constant and variable accesses A constant access is a reference to a named constant, and yields the value of that constant. A variable access is a reference to a named variable, and yields the current value of that variable. Conditional expressions A conditional expression chooses one of its sub expressions to evaluate, depending on a condition. An if-expression chooses from two sub expressions, using a Boolean condition. A case-expression chooses from several sub expressions. Conditional expressions are commonplace in functional programming Languages, but less common in imperative/OO programming languages.

S-ar putea să vă placă și