Concepts of Programming Languages

Exercises

Instructor: Stefan Mitsch

Topics

  • Tail recursion
  • Scope and lifetime
  • Algebraic datatypes
  • Argument passing
  • Closures
  • Inheritance and delegation
  • JavaScript

Tail Recursion


            def f (n:Int) = if (n<=1) 1 else n * f (n-1)
            def g (n:Int) = f (n) * g (n-1)
            def h (n:Int) = h (g (n), f (n))
            def i (n:Int) = n * n
          
  • Is f recursive? tail-recursive?
  • Is g recursive? tail-recursive?
  • Is h recursive? tail-recursive?
  • Is i recursive? tail-recursive?

Scope and Lifetime: Dangling Pointers


            int* f(int x) { return &x; }
            int* g(int x) { int* y = (int*) malloc (sizeof (int)); *y=x; return y; }
            int main(void) {
              int* p = f(5);
              printf("%d\n", *p);
              int* q = g(5);              
            }
          
  • Is p pointing to the heap or stack?
  • Is p dangling? Is dereferencing it safe?
  • Does p need to be freed?
  • Is q pointing to the heap or stack?
  • Is q dangling? Is dereferencing it safe?
  • Does q need to be freed?

Static vs. Dynamic Scope

What is printed in a statically scoped language?
In a dynamically scoped language?
            
                var x:Int = 10
                def foo() =
                  x = 20                
                def bar() = 
                  var x:Int = 30
                  foo()
                  println(x)                
                def zee() = 
                  var x:Int = 40
                  bar()
                  println(x)
                bar(); print("bar: " + x)
                zee(); print("zee: " + x)
                foo(); print("foo: " + x)
            
          
Static: bar: 30 20
        zee: 30 40 20
        foo: 20
                
Dynamic: bar: 20 10
         zee: 20 40 10
         foo: 20
                

Algebraic Datatypes

Define an algebraic datatype for arithmetic expressions with literals, variables, +, -, *, /
              
                enum Expr:
                  case Literal(x:Int)
                  case Variable(n:String, v: Option[Expr])
                  case Neg(e:Expr)
                  case Plus(l:Expr, r:Expr)
                  case Minus(l:Expr, r:Expr)
                  case Times(l:Expr, r:Expr)
                  case Div(l:Expr, r:Expr)
              
            

Algebraic Datatypes

Define a toInt method for arithmetic expressions
                
                  enum Expr:
                    case Literal(x:Int)
                    case Variable(n:String, v:Option[Expr])     
                    case Neg(e:Expr)
                    case Plus(l:Expr, r:Expr)
                    case Minus(l:Expr, r:Expr)
                    case Times(l:Expr, r:Expr)
                    case Div(l:Expr, r:Expr)
                
              
                  
                    def toInt : Int = this match
                      case Literal(x)           => x
                      case Variable(n, None)    => ???
                      case Variable(_, Some(e)) => e.toInt
                      case Neg(e)               => -e.toInt
                      case Plus(l,r)            => l.toInt + r.toInt
                      case Minus(l,r)           => l.toInt - r.toInt
                      case Times(l,r)           => l.toInt * r.toInt
                      case Div(l,r)             => l.toInt / r.toInt         
                  
                

Call-by-value and Call-by-reference

What is printed in a call-by-value language?
In a call-by-reference language?
            
                def f(a:Int, b:Int) = {
                  a = b
                  b = b + 1
                }

                var x = 5
                var y = 10
                f(x,y); println(s"x=$x, y=$y")
                f(x,x); println(s"x=$x")
                f(x,x+2); println(s"x=$x")
            
          
CBV: x=5, y=10
x=5
x=5
CBR: x=10, y=11
x=11
x=13

Closures


            def f(): String=>String = {
              var s = ""
              (t:String) => { s = s + t; s }
            }
            val a = f()
            println(a("x"))
            println(a("y"))
            println(a("z"))
          
  • Does the program compile?
  • What is the type of a?
  • What is printed?
  • What is an OOP approach to the code above?

Nested Closures


            def f(): ()=>String=>String = {
              var s = ""
              () => {
                var i = 0
                (t:String) => { s = s + t + i; i = i+1; s }
              }
              
            }
            val factory = f()
            val a = factory()
            val b = factory()
            println(a("x"))
            println(a("y"))
            println(b("z"))
          
  • Do a and b share s?
  • Do a and b share i?
  • What is printed?

Inheritance


            class A {
              def f() = { println("A.f") }
            }
            class B extends A {
              override def f() = { println("B.f"); super.f() }
                       def g() = { println("B.g") }
            }

            val b:A = new B() // b:B?
            b.f()
          

Does the program compile? If yes, what is printed?

Does b.g() compile? If yes, what is printed? If no, would it compile with

val b:B = new B()

Delegation


            class A {
              def f() = { println("A.f"); this.f() }
            }

            class B(val a:A) {
              def f() = { println("B.f"); a.f() }
            }

            val b = new B(new A())
            b.f()
          

Does the program compile? If yes, what is printed?

Parametric Types


            class A {}
            class B extends A {}
            var as: List[A] = List(new A(), new B())
          

Which code compiles and why/why not?

val bs: List[B] = as
val bs: List[B] = List(new B(), new B()); as = bs
as(0) = new B()
val a1: Any = as(0) // a1: A // a1: B

Parametric Types


            class A {}
            class B extends A {}
            class C extends B {}
            val as: List[A] = List(new A(), new C())
            val bs: List[B] = List(new B(), new C())
            val cs: List[C] = List(new C(), new C())            
          

Which code compiles and why/why not?

var xs: List[_ <: B] = bs
xs = as
xs = cs
val x1: B = xs(0) // x1: Any // x1: C
xs(0) = new C() // new B() // new A()

Parametric Types


            class A {}
            class B extends A {}
            class C extends B {}
            val as: List[A] = List(new A(), new C())
            val bs: List[B] = List(new B(), new C())
            val cs: List[C] = List(new C(), new C())
          

Which code compiles and why/why not?

var xs: List[_ >: B] = bs
xs = cs
xs = as
val x1: A = xs(0) // x1: B // x1: C // x1: Any
xs(0) = new A() // new B() // new C()

JavaScript


            function f() {
              return {
                a: 1,
                b: "hello"
                c: function () { return 2; }
              }
            }
          
  • What is the result type of function f?
  • What is the result of f().a?
  • What is the result of f().d?
  • What is the result of f().c()?

JavaScript: Closures

            
            function f(n) {
              var x = n;
              return {
                get: function(y) { x = x+y; return x; }
              }
            }
          
  • What is the result of f(3).get(1) and why?
  • What are the values of b and c in
    
                    var a = f(3); 
                    var b = a.get(1); 
                    var c = a.get(2);

Scheme Lists


            (let (xs '(1 2 3 4 5 )))
          
  • Which element is accessed by (car s)?
  • What is the result of (cdr xs)?
  • What is the result of (cdr (cdr (cdr xs)))?
  • Which element is accessed by (car (cdr (cdr xs)))?
  • What is the result of (car (car xs))?

Scheme Cons Cells


            (let (x (cons 1 (cons 2 3))))
          
  • Is this a Scheme list?
  • What is (car x)?
  • What is (cdr x)?
  • What is (car (cdr x))?

Scala Lists


            val xs = 1 :: 2 :: Nil
            val ys = List(1, 2)
            val zs = 0 :: xs
            val as = List(0) :: xs
            val bs = List(0) ::: xs
          
  • Do xs and ys contain the same elements?
  • What is zs? Does it contain the same elements as 0 :: ys?
  • What is as?
  • What is bs?

Missing Types


            def f(xs:List[?3]): ?4 = xs.map(x => x+1)
            def g(ys:?2): ?1 = ys.foldLeft(0)(_ + _)
            g (f (List (1,2,3,4)))
          
  • In which order should we try to resolve the types?
  • What is the type ?1
  • What is the type ?2
  • What is the type ?3
  • What is the type ?4