Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 69

Value and Type

CNG 242 Programming Language


Concepts
Lecture - 2
Introduction

• Read chapter 2 in the book


• What is value?
– Value : anything that exist, that can be computed,
stored, take part in data structure.
– Constants, variable content, parameters, function return
values, operator results...
– Any entity that can be manipulated by a program
Types
• Type : set of values of same kind.

• "𝑣 is a value of type 𝑇” means “𝑣 ∈ 𝑇"

E.g. C types E.g. Haskel types


– int, char, long,... – Bool, Int, Float, ...
– float, double – Char, String
– pointers – tuples,(N-tuples), records
– structures: struct, union – lists
– arrays – functions
Types (2)
• Each type represents a set of values. Is that enough?
• What about the following set? Is it a type?

{false, true} is a type because the operations not, and, or operate uniformly over the values
false and true.
{...,-2, -1, 0, +1, +2,...} is a type because operations such as addition and multiplication
• Values in a type should exhibit a similar behaviour.
operate uniformly over all these values.
{13, true,
• The sameMonday}. is not
group of operations abetype,
should definedsince
on them.there are no useful operations over this set of
values
• Type: a set of values, equipped operations that can be applied uniformly to all these values
Primitive types
• Primitive Types: Values that cannot be decomposed into other sub values.
– C: int, float, double, char, long, short, pointer
– Haskell: Bool, Int, Float, function values
• cardinality of a type: The number of distinct values that a datatype has.
– Denoted as: ”#Type”.
– #Bool = 2 #char = 256 (ISO LATIN character set)
– #char = 216 (UNICODE character set), #short = 216, #int = 232
• Not all languages have the same primitives
• Some languages does not have a distinct type for Boolean or Character (e.g., C++ has a type named bool, but its values are
just small integers; there is a convention that zero represents false and any other integer represents true, similar for char)
• Some languages provide several integer types : byte, short
Primitive types (Example)
• Need 2 variable to store “population of the country (294,906)” and “population of the world (7.046 billion)”
• In C what would you choose?

History's Worst Software Bugs

short
• Real world –32,768
problem: spacecraft Ariane5 (1996) is lost due to to 32,767
integer overflow!
– Resulting $370 Million loss
– data int –2,147,483,648
conversion from a 64-bit floating point numberto
to a2,147,483,647
16-bit signed integer value

long –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

https://www.youtube.com/watch?v=5tJPXYA0Nec
User defined primitive types
• enumerated types
– e.g. C enum days {mon, tue, wed, thu, fri, sat, sun};
– enum months {jan, feb, mar, apr, .... };
– enum days today; /*usage as var*/
• e.g. Java
– public enum Currency {PENNY, NICKLE, DIME, QUARTER};
– Currency coin = Currency.PENNY;

• ranges (Pascal and Ada)


– type Day = 1..31;
– var g:Day;
User defined primitive types (2)
• Discrete Ordinal Primitive Types: Datatypes values have one to one mapping to a range of integers.

• Most programming languages allow only integers to be used for counting and array indexing.
– C: Every ordinal type is an alias for integers.
– Pascal, Ada: distinct types

• DOPT’s are important as they


i. can be array indices, switch/case labels
ii. can be used as for loop variable (some languages like pascal)
Composite Data Types
• User defined types with composition of one or more other data types.
• Depending on composition type:
1. Cartesian Product (struct, tuples, records)
2. Disjoint union (union (C), variant record (pascal), Data (haskell))
3. Mapping (arrays, functions)
4. Powerset (set datatype (Pascal))
5. Recursive compositions (lists, trees, complex data structures)
1-Cartesian product

#S x #T

(a,1) is a pair. if there were N sets, then the elements will be n-tuple
Cartesian product (2)

• In a Cartesian product, values of several types are


grouped into tuples.
• Let (x, y) stand for the pair whose first component is
x and whose second component is y.
• Let S x T stand for the set of all pairs (x, y) such that
x is chosen from set S and y is chosen from set T:
S x T = { (x, y) | x  S; y  T }
• Cardinality:
hence the “” notation
#(S x T) = #S x #T
Cartesian product (3)

• We can generalise from pairs to tuples. Let S1 x S2 x  x Sn stand


for the set of all n-tuples such that the ith component is chosen from
Si: S1 x S2 x  x Sn = { (x1, x2, , xn) | x1 ∈ S1; x2 ∈ S2; …; xn ∈
Sn }
• Basic operations on tuples:
– construction of a tuple from its component values
– selection of an explicitly-designatedso
component of athetuple.
we can select 1st or 2nd
component

 Records (Ada), structures (C), and tuples (Haskell) can


all be understood in terms of Cartesian products.
Cartesian product (2)
• struct in C, record in Pascal, tuple in functional programming
• What is the type of the following C struct?
struct Person{
char[20] name;
int no;
} x= {“Dennis Ritchie”,194183};

Answer: string x int


• In Haskell: string x int (making a synonym for an already existing type)
• type People =(String, Int)
• x::People
• x=(“Dennis Ritchie”,194183)
Cartesian product (3)

• Multiple cartesian products


enum Month
{Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec};

struct Person{
char[20] name;
int no;
Month m;} x={“Dennis Ritche”, 194183, May};
Cartesian product (4)
Homogeneous Cartesian product

• S0 is not empty set. It has exactly 1 value


• So its cardinality is 1
– Corresponds to void in C,C++,Java
– Nil for functional language lists.
exercise
• Write the set of values of each of the following C
types. What is the cardinality of each type
– enum Suit{club,diamond,heart,spade};
#Suit=4
– struct Card {Suit s; byte r;};
#Card=4*256
– struct P {bool pass; Card play};
#P=2*4*256
2-Disjoint Union
• A value is chosen from one of several sets (Only one of
the types can be in use at any one time)
• Notation S+T
• Values consists of a tag and value chosen from either sets

– Example: S={1,2,3} T={‘a’,’b’}


– S+T={left 1, left 2, left 3, right ‘a’, right ‘b’}
– #(S+T)=#S+#T
• Are C union’s disjoint union? ( You need to implement the
tag)
Disjoint Union (C)
Union of C: unsafe!
• Complication with C: enum Accuracy {exact, inexact};
struct Number{
union Untagged_Number { enum Accuracy accuracy;
int ival; int acc;
float rval; union {
}; int ival; /*used when acc contains exact */ float
rval; /*used when acc contains inexact */
} content;
};
Such a union type is useless on its own.
Lacking a tag, we cannot perform a tag – Very very error-prone!
test Valid field is unknown because of the lack of
tags . Only great care and self-discipline by the
programmer can ensure that the structure is
. used in the way intended
Disjoint Union (Haskell)

Disjoint union
• In Haskell, algebraic types are used for
disjoint unions

data Sayi= Reel Float | Tamsayi Int deriving Show


x= Tamsayi 5
y= Reel 1.3

• You cannot access different values


3-Mappings in math
Given sets S and T, the set of all possible mappings is

What is the cardinality?


Mappings in PL

If 𝑓 maps value 𝑥 ∈ 𝑆 to y ∈ 𝑇, then we write


𝑦 = 𝑓( 𝑥)
• Arrays and functions are mappings
• Arrays map a range of integers (or DOPT) to any type
– E.g. in C: char[5] name={‘f’,’e’,’w’,’e’ ,’r’}
Maps 0->’f’ , 1 ->’e’, 2->’w’,3->’e’ ,4->’r’
– e.g. in C
exercise
Bool P [3]
• What is the type?
• What is the cardinality? #P=8
• What are the values in this set?

• What about multidimensional arrays?


– Think as the index as N-tuple that maps to type T
– E.g. bool[3][4] aa;
– C thinks that as multiple mapping
Functions are mappings

• A function takes parameters and returns a value.


• So it maps its parameters to the return type
• E.g. in C
int myfunc (int a){
if (a%2 ==0) return 0; else return 1;}
– myfunc maps an integer to 0 or 1
– Regardless of the function body myfunc: int -> int
• E.g. in Haskell
myfunc a = if mod a 2 ==0 then 0 else 1
– The type of myfunc is int->int
Functions are mappings

• What about functions with multiple parameters?


– Cartesian product of the parameters are mapped to
return type (we will use this approach)
* Operation type
– Example
f3 a b = fromIntegral (mod a b) * 0.1
double f(int m, int n){…}
f: int x int ->double
A very useful function for
dealing with numbers
– Haskel thinks as nested mapping
is fromIntegral. Useful when you
– Example : f a b = (mod a b)*0.1
want integral and floating point
f:int->int->double
types to work together nicely.
exercise

• What is the type of these functions?

• float power (float a, int n) {…} float x int ->float

• void myf(int, int){…} Int x int

• int myf2 (struct Card card){….} Card->int


Assume struct Card {Suit s; byte r;};
Array and Function Difference

Arrays Functions

• Values stored in memory • Defined by algorithms


• restricted: domain is only DOPT. • Has properties that are not
shared by math functions
– In C domain is only positive – Efficiency, resource usage
integer • All types of mappings are
possible
• Side effect, output, error,
termination problem
exercise
#(S  T) = #T #S

#(S x T) = #S x #T

• What is the relationship between


S->(T->U) and (SxT)->U
• The same? Different? How? Why?
– Hint: think cardinality

#(T->U) = #U #T #(SxT) =#S x #T


#S->(T->U) = (#U #T)#S #(SxT)->U = (#U )#Sx#T
4-Powerset

Counting: For each element there are two options in


the chosen subset of not therefore 2n
Set datatype
Set datatype is restricted and special type exists in Pascal, and special set
of lang like SetL

In C++ supported by library


In Java there is a Set interface and default
implementation.
5-Recursive Types

• A recursive type is one defined in terms of itself


• Types including themselves in composition
• S = …..S….
• Lists and Strings
Lists

• Lets define the type of an integer list

• An integer list is either empty, or is a pair consisting of


an integer and an integer list.
– A type if defined in terms of itself.

• S={empty}+ (int x S)

– See the recursion!


Lists (2)
S={left empty} U {right (a, left empty) | a ∈ int} U
{right(a, right(b, left empty)) | a,b ∈ int} ……

• Lets enumerate the elements of S


S={left empty, right(1, left empty), right(2,left empty)…….,

right(1,right(1,left empty)), right(1,right(2,left empty)),…..


…..}
•We can write the type as
L=Unit+ (T x L)
Where unit is the 0-tuple , L is list of T
•Alternatively:
T* = Unit + ( T x T*)
Where T is a type
Examples

• Haskel lists examples

data List = Left (Int, List) | Empty


x=Left (1, Left (2,Left (3,Empty)))
y=Empty

• C list: pointer based, not actual recursion


struct List{
int x;
struct List * next;
} a;
Polymorphic lists
• A single definition defines lists of many types
• List a = a x (List a)+{empty}

– Where a stands for many types, like a type variable


• Left(1,Left (“ali”, Left(1.2, Empty))) ∈ List a ?
– No (homogeneous).
– Most languages only permits homogenous lists (including
Haskell)
Haskel Lists

• Actually Haskell has built-in list types


• [1,2,3] is a [integer]
– x=[4,2,4]

• Binary operator “:” for list construction

x= (1:(2:(3:[]))) is the same as x=[1,2,3]


(“ali”:[]) is the same as [“ali”]
General recursive types

• T= ….T….
• The cardinality of recursive types are infinite
• Let S=int x S , a=Left (1,Left(2,a))
– Is a ∈ S? Yes
The value of a is [1,2,1,2,1,2……]
– Some languages like Haskell lets you define such values.
Infinite lists
– Most languages allow only a subset of S, the subset of
finite values.
Tree – a recursive type example
Tree – a recursive type example
• Tree is an abstract data type

• C++: using pointers and template


template <class Alpha>
struct Tree{
Alpha x;
Tree *left, *right; //Usage Tree <double> root2;
};
Tree – a recursive type example

•Tree is an abstract data type

•Haskell

data Tree alpha=Empty| Node (alpha, Tree alpha, Tree alpha)


x=Node (3, Empty, Empty)
y=Node (1,Node(2,Empty,Empty),Node(3,Empty,Empty))

By definition, the first element should be a node the


remaining two should be trees. Therefore a single node is like x
Strings: a recursive type
• String with no char in it : empty string
• A string is a char + a string

• Typical operations:
– Length, equality, lexicographic comparison, character
selection, substring selection, concatenation
• Language design choice:
– Character array (C, C++,Pascal)
– Character list (Haskell, Lisp, Prolog)
– Primitive type Meta Language (ML). There is an internal
table of strings
– Objects (Java)
• Choice effects the complexity and efficiency
TYPE SYSTEMS
Type systems
•Types are required to provide data processing integrity
checking, efficiency, access controls
•Type compatibility on operators is essential
• a PL’s type system groups values into types
– Helps us to describe data effectively
– Prevent nonsensical operations

• y=true * 12;
• x=12; x[1]=6;
• x=5; x.a = 4
• Simple bugs can be avoided at compile time
– Type checking
When to do type checking?

1. Compile time
– Static type checking
– Statically typed languages

2. Run time
– Dynamic type checking
– Dynamically typed languages

• The latest time to type check is the time just before the
operation.
Static type checking
• Compile time type information is used to do type checking.
• All incompatibilities are resolved at compile time.
bool even (int n){ return n%2==0;}

– Although compiler does not know the value of n, it knows that this

value must be of type int.


– The type declaration tells the compiler (int n)
– Compiler also infers the operand of % are both int, therefore
the result is int CHECK
– Compiler also knows that both operands of == will be of type int
CHECK
– Compiler infers that the return value will be boolean because of
==
– Return value is consistent with the function’s stated result type.
CHECK
Static type checking

• Most languages do static type checking


• User defined constants, variable and function types:
– Strict type checking. User has to declare all types
• C, C++,Fortran,Java...
– Languages with type inference
• Haskell, ML, Scheme...
• No type operations after compilation.
– i.e. no type checking at runtime, so faster
– All issues are resolved.
– Direct machine code instructions
Dynamic type checking

• No checking until the operation is to be executed


• Interpreted PLs: Python, Perl, PHP, Lisp, Prolog
def even (n):
return (n%2 ==0)
• Type of n is unknown, so % needs a run time type
check to ensure n is an integer
– Just before performing %, the type of n is checked
• May be useful at some occasions
example

def month(m):

if (isinstance (m,int) and 1<=m<=12: return m


elif m==“Jan”: return 1
elif m==“Feb”:return 2
….
else : return “Date error”
• Use this function as month(12) or month(“Jan”)
– In Statically typed lang, type system gets in the way
• Runtime decision based on user choice is possible
• Type of a variable can change at runtime
a=1 ….after some code ….. a=“s”
• Has to carry type information along with variable at run time.
– Extra memory required
Static vs dynamic

• Static type checking is faster.


– Dynamic type checking does type checking before each
operation at run time. (check again and again)
– Also uses extra memory to keep run-time type information.

• Static type checking is more restrictive= Safer.


– Bugs avoided at compile time, earlier is better.
– Type errors are abundant!

• Dynamic type checking is less restrictive=more flexible.


– Useful if types of data are not known in advance
– Operations working on dynamic run-time type information can be defined
Type Equality
• How to decide 𝑆 is equivalent to 𝑇
1. Name equivalence
– Types defined at the same place , or type aliasing
– Easier. Most language use name equivalence

struct Point {int x,y;};


typedef struct Point Point2D;

struct Point x;
Point2D y;
x=y; //valid. Name equivalence

2. Structural equivalence

– Types have same value set


Example

typedef struct Comp1 { double x , y ;} Complex ;


struct COMP2 { double x ,y; };
struct Comp1 a;
Complex b;
struct COMP2 c ;
….
a=b; /* valid, equal types*/
a=c; /* no name equivalence, type error*/
/* if structural equivalence is used, it would be ok*/
Structural equivalence
Most PL use name equality
• Structural equiv. check is hard to implement, especially in
recursive types

• struct Circle{ double x,y,a;};


struct Square{double x,y,a;};
These have semantic difference. User error needs less
tolerance
Type completeness
• First class values
– There is no restriction
– Can be used in assignment
– can be passed as parameters to a function
– can be returned from a function as a result
– can take a part in composition
– can be the value of some expression
– can be given names
• If there is a restriction for a value, then it is second class
– E.g. functions are 2nd class in Pascal
Type completeness

• Recall that functions are mapping

• Functions are first class value in functional programming languages


(Haskell, Scheme)

• Functions are second class value in most imperative languages


-C uses function pointers, can return a function pointer (so,  not
directly supported by the language but require the use of other
language features)
Type completeness principle

• Type completeness principle :No operation should be


arbitrarily restricted in the types of its operands

• In other words: First order values should take part in all


operations below, no arbitrary restrictions should exist.

– Assignment
– Function parameter
– Take part in compositions
– Return value from a function
expression

• Program segment that results in a value when evaluated


– Expression evaluate to a value, whereas statement/command don’t
– 3*2 is an expression , x:=3*2 is a statement

• Expressions:
– Literals
– Variable and constant access
– Aggregate
– Variable references
– Function calls
– Conditional expr
– Iterative expr (in Haskell)
Literals/Variable and Constant Access

• Literals:
– Constants with same value with their notation
123, 0755, 0xa12, 12451233L, -123.342,
-1.23342e-2, ’c’, ’\021’, "ayse", True, False

• Variable and constant access:


– User defined constants and variables give their content
when evaluated.
int x;
#define pi 3.1416
x=pi*r*r
Aggregates
• Used to compose composite values lexically

• C only has aggregates at definition. There is no


aggregates in the executable expressions!
Variable References

• r-value vs l-value
• Expressions that refer to memory locations are called "l-
value" expressions.
– An l-value represents a storage region's "locator"
value, or a "left" value of an assignment
• R-value : value of an expression
– Not all r-values are l-values, but all l-values are r-
values
• Example: b=a
– evaluate a (variable access) : r-value
– assign that r-value to the location value of b (l-
value)
Example: C
Any of these can be an l-value expression:

• An identifier of integral, floating, pointer, structure, or


union type
• A subscript ([ ]) expression that does not evaluate to
an array
• A member-selection expression (–> or .)
• A unary-indirection (*) expression that does not refer
to an array
• An l-value expression in parentheses
• A const object (a nonmodifiable l-value)
Function Calls

• 𝐹(𝐺𝑝1𝐺𝑝2, … , 𝐺𝑝𝑛)
• Function name followed by actual parameter list.
• Function is called, executed and the returned value is substituted
in the
expression position.
• Actual parameters: parameters send in the call
• Formal parameters: parameter names used in function definition
• Operators can be considered as function calls. The difference is
the
infix notation.
⊕(a, b) vs a ⊕ b
• languages has built-in mechanisms for operators.
• Some languages allow user defined operators (operator
overloading): C++, Haskell.
Conditional Expressions

• Evaluate to different values based on a condition


• Haskell:
if condition then exp1 else exp2 .
case value of p1 -> exp1 ; p2 -> exp2 ...

• C (ternary): (condition )?exp1 :exp2 ;


• if .. else in C is not conditional expression but conditional
statement. No value when evaluated!

x = (a >b)? a:b;
y = ((a >b)? s i n : cos )( x ); /* Does it work ? Try */
expression
Conditional Expression (cont) Haskell

• case checks for a pattern and evaluate the RHS


expression with substituting variables according to
pattern at LHS
Iterative Expression

• Expressions that do a group of operations on elements of a


list or data structure, and returns a value
[ expr | variable <- list , condition ]
• Similar to set notation in math:
{expr |var ∈ list, condition}

Iterative expression, not iterative statement!


Iterative Expressions

x =[1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12]


y =[ a *2 | a <- x ]
{-- evaluates to [2 ,4 ,6 ,8 ,...24 ] - -}
z =[ a | a <- x , mod a 3 == 1 ]

{-- evaluates to [1 ,4 ,7 ,10] - -}


Some examples (1)

--The Ord class is used for totally ordered datatypes.


maxi :: (Ord a) => [a] ->a
maxi [] = error "maximum of empty list"
maxi [z] = z
maxi (z:zs)= max z (maxi zs)

-- maxi [3,7,8] is
--max 3 ( maxi [7,8]= max 7 maxi(8))
Some examples (2)

reverse1 :: [a] -> [a]


reverse1 []= []
reverse1 (z:zs)= reverse1 zs ++ [z]
-- reverse1 [1,2,3] is
--reverse1 [2,3] ++ 1 is
--reverse1 [3] is
--reverse1 []++ 3 ++ 2 ++ 1 is
--[] ++ 3 ++ 2 ++ 1 = [3,2,1]

You might also like