Quick review about Types
========================
* Types can be checked at two different moments:
- Dynamically: during the program execution. E.g: php, python, ruby, bash.
- Statically: during the compilation of the program. E.g: Java, C, C++, SML.
* There exists languages which are strongly typed, and languages which
are weakly typed.
- A strongly typed language guarantees that a type will be always used
as declared.
- A weakly typed language allows a value to be used as if it had a type
different than its declared type.
* There are two ways to decide when two types are equivalente:
- name equivalence: two types are the same, if, and only if, they have the
same name: C, Java, C++, etc.
- structural equivalence: two types are the same if they have the same
structure. Example: SML.
Ex. in C:
typedef struct { int a; float b; } T0;
typedef struct { int a; float b; } T1;
void foo(T1 s) { printf("%d, %f\n", s.a, s.b); }
int main() {
T0 x;
T1 y;
foo(y);
foo(x); // Does not compile
}
Ex. in SML:
- type T0 = int * real;
type T0 = int * real
- type T1 = int * real;
type T1 = int * real
- fun foo (s:T1) = #1 s;
val foo = fn : T1 -> int
- val x:T0 = (1, 3.14);
val x = (1,3.14) : T0
- foo x;
val it = 1 : int
* Compilers use three different strategies to statically discover the types of
symbols:
- Annotations: the programmer must explicitly write the type of a symbol
next to it. Examples: Java, C, C++.
- Special names: In some old languages, the name of the variable gives away
its type. Example: in old Fortran, integer variables should start with 'I'.
- Inference: the compiler uses an algorithm that finds the correct type of
each value. Examples: Haskell, Scala, SML.
* Some languages allow runtime type tests.
1) Can anyone give me an example?
http://homepages.dcc.ufmg.br/~fpereira/coisas/test.php
";
echo "Is bool? " . is_bool($var) . "
";
echo "Is float? " . is_float($var) . "
";
echo "Is string? " . is_string($var) . "
";
?>
Polymorphism
============
1) What's the type of this function in python?
def f (selector, a, b): return a if selector else b
1.1) What is the type of this C function?
int f (int selector, char a, char b) {
return selector ? a : b;
}
1.2) What about this ML function?
fun f (selector, a, b) = if selector then a else b;
1.3) Which statically typed language gets closer to python?
* A function or operator is polymorphic if it has at least two possible
types
- It exhibits ad hoc polymorphism if it has at least two but only
finitely many possible types
- Overloading
- Coercion
- It exhibits universal polymorphism if it has infinitely many possible
types.
- Subtyping
- Parametric
2) What is overloading?
2.1) Can anyone give me an example?
// over.cpp
#include
int sum(int a, int b) {
std::cout << "Sum of ints\n";
return a + b;
}
double sum(double a, double b) {
std::cout << "Sum of doubles\n";
return a + b;
}
int main() {
std::cout << "The sum is " << sum(1, 2) << std::endl;
std::cout << "The sum is " << sum(1.2, 2.1) << std::endl;
}
2.2) What if I change the doubles to ints?
3) How to implement overloading? E.g, how does the program above look like
in assembly?
$> g++ -S over.cpp
* Many languages have overloaded operators. There are languages
that allow the programmer to change the meaning of operators:
3.1) Consider the class MyString below:
// opOver.cpp
class MyString {
public:
static const int CAP = 100;
MyString (const char* arg) {
strncpy(member1, arg, CAP);
}
private:
char member1[CAP];
};
3.1) How to add a '+' operator to this class so that s1 + s2 has the effect
of appending the contents of s2 into s1, and storing the result into s1?
class MyString {
...
void operator +(MyString val) {
strcat(member1, val.member1);
}
...
}
3.2) How to add a << operator to this class, so that it prints the object?
class MyString {
...
friend std::ostream & operator<<(std::ostream & os, const MyString & a);
...
}
std::ostream & operator<<(std::ostream & os, const MyString & a) {
os << a.member1;
return os;
}
Example of usage:
int main () {
MyString s1("UF");
MyString s2("MG");
s1 + s2;
std::cout << s1 << std::endl;
}
3.3) How can we overload an operator in Python?
class Interval:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
return self.a + other.a, self.b + other.b
def __gt__(self, other):
return self.a < other.a and self.b > other.b
def __str__(self):
return "(" + str(self.a) + ", " + str(self.b) + ")"
i0 = Interval(1, 4)
i1 = Interval(2, 3)
i2 = i0 + i1
print(i0)
print(i0 > i1)
print(i1 > i0)
>>> execfile('Interval.py')
(1, 4)
True
False
In sml we can overwrite a symbol or a name, but we cannot have two user
defined implementations with the same name:
- infix 3 +;
infix 3 +
- fun op + (a, b) = a - b;
val + = fn : int * int -> int
- 3 + 2;
val it = 1 : int
3.4) Oops: how to recover the original meaning of the plus symbol?
fun op + (a, b) = a - (~b);
3.5) Several languages decided not to support overloading. Why?
Readability. Consider:
?- a << 1 // shift left or streaming?
?- a + b == b + a // '+' on strings
4) What is a type coercion?
5) Which calls are legal in the program below?
public class Coercion {
public static void f(double x) {
System.out.println(x);
}
public static void main(String args[]) {
f((byte)1);
f((short)2);
f('a');
f(3);
f(4L);
f(5.6F);
f(5.6);
}
}
5.1) Why do we get 5.599999904632568 when we try to print 5.6F?
* Tricky iterations:
- overloading uses the types to choose the definition.
- Coercion uses the definition to choose a type conversion.
6) Which functions get called?
// square.cpp
#include
int square(int a) {
std::cout << "Square of ints\n";
return a * a;
}
double square(double a) {
std::cout << "Square of doubles\n";
return a * a;
}
int main() {
double b = 'a';
int i = 'a';
std::cout << square(b) << std::endl;
std::cout << square(i) << std::endl;
std::cout << square('a') << std::endl;
}
7) Which sum is called in the file below?
#include
int sum(int a, int b) {
std::cout << "Sum of ints\n";
return a + b;
}
double sum(double a, double b) {
std::cout << "Sum of doubles\n";
return a + b;
}
int main() {
std::cout << "The sum is " << sum(1, 2) << std::endl;
std::cout << "The sum is " << sum(1.2, 2.1) << std::endl;
// What happens here?
std::cout << "The sum is " << sum(1, 2.0) << std::endl;
}
7.1) Coersions in JavaScript are complicated. What are the values of the
comparisons below?
var w = '1.0'
var x = '1'
var y = 1
if (w == x) {
document.write("w == x
")
} else {
document.write("w != x
")
}
if (x == y) {
document.write("x == y
")
} else {
document.write("x != y
")
}
if (w == y) {
document.write("w == y
")
} else {
document.write("w != y
")
}
8) What is the type of:
List l
fun f a b = a
9) Why does parametric polymorphism has this name?
9.1) Code a function getMax in c++ that returns the maximum of two elements:
template
T GetMax (T a, T b) {
T result;
result = (a>b)? a : b;
return (result);
}
9.2) How to call this function?
// template.cpp:
int main () {
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax(i,j); // see the type parameter!
n=GetMax(l,m);
cout << k << endl;
cout << n << endl;
return 0;
}
9.3) How to implement the function getMax in SML? Is this implementation
polymorphic? Why?
9.4) The GetMax function could be implemented as a macro. How?
#define GetMax(a,b) ((a) < (b) ? (b) : (a))
9.5) What are the advantages and disadvantages of using macros over templates?
9.6) How to create a C++ class MyInt, with the operator >, so that we can
apply getMax on it?
class MyInt {
friend std::ostream & operator<<(std::ostream& os, const MyInt& m) {
os << m.data;
return os;
}
friend bool operator >(MyInt& mi1, MyInt& mi2) {
return mi1.data > mi2.data;
}
public:
MyInt(int i) : data(i) {}
private:
const int data;
};
9.7) And how to use it?
MyInt m1(50), m2(56);
MyInt mi = GetMax(m1, m2);
cout << mi << endl;
What would happen if MyInt did not have the operator '>' defined?
10) What is a type constructor?
11) How is parametric polymorphism implemented in C++?
11.1) How is it implemented in Java?
12) What is the type of "fun comp a b = a = b;"
stdIn:1.18 Warning: calling polyEqual
val comp = fn : ''a -> ''a -> bool
12) Which type of polymorphism is happening here?
public class Sub {
public static void print(Object o) {
System.out.println(o);
}
public static void main(String[] a) {
print(new String("dcc024"));
print(new Integer(42));
print(new Character('a'));
}
}
13) What is the type of polimorphism that exists between int* and const int*
in C? E.g.:
int main(int argc, char** argv) {
const int *x = &argc;
int *y = x;
printf("%d\n", *x);
*y = 0;
printf("%d\n", *x);
}
13.1) What about in C++? E.g., try compiling the same program above with a
C++ compiler.
13.2) Compare the program with:
int main(int argc, char** argv) {
int *y = &argc;
const int *x = y;
printf("%d\n", *x);
*y = 0;
printf("%d\n", *x);
}
13.3) What are the operations that we can apply on int*?
read & write
13.4) What are the operations that we can apply on const int*?
read
14) Has anyone heard of Ocaml?
- It is a functional, object-oriented language, that came out of ML, and that
uses structural typing.
14.1) How to create objects in Ocaml?
let x =
object
val mutable x = 5
method get_x = x
method set_x y = x <- y
end;;
let y =
object
method get_x = 2
method set_x y = Printf.printf "%d\n" y
end;;
14.2) How to run a program?
$> ocaml
# use "sub.ml";;;
14.3) What happens if I try: # x = y;;
14.4) Does this expression type-checks?
14.5) What does this definition do?
let set_to_10 a = a#set_x 10;;
14.6) Is it legal?
# set_to_10 x;;
- or -
# set_to_10 y;;
14.7) Consider, now, the z object below:
let z =
object
method blahblah = 2.5
method set_x y = Printf.printf "%d\n" y
end;;
Is it legal? set_to_10 z;;
14.8) Consider, now, a new type definition:
type simpler_obj = < get_x : int >;;
Is it legal to convert x to simpler_obj?
# let w = (x :> simpler_obj);;
# w#get_x;;
14.9) What about converting z to simpler_obj?
(z :> simpler_obj);;
Summary:
- Overloading: each different type requires a separate definition.
- Coercion: all the conversions must be defined in the language
spec.
- Parametric: infinite as long as the universe over which type variables
are instantiated is infinite.
- Subtype: infinite, as long as there is no limit on the number of
subtypes of a type.
15) Why do programming languages have polymorphism?