Practice Final Exam Questions

Approved & Edited by ProProfs Editorial Team
The editorial team at ProProfs Quizzes consists of a select group of subject experts, trivia writers, and quiz masters who have authored over 10,000 quizzes taken by more than 100 million users. This team includes our in-house seasoned quiz moderators and subject matter experts. Our editorial experts, spread across the world, are rigorously trained using our comprehensive guidelines to ensure that you receive the highest quality quizzes.
Learn about Our Editorial Process
| By Gorin
G
Gorin
Community Contributor
Quizzes Created: 1 | Total Attempts: 137
Questions: 11 | Attempts: 137

SettingsSettingsSettings
Practice Final Exam Questions - Quiz


These are the instructions that will also be on the real final, but of course this is just a practice final:You have 90 minutes to complete the exam. Only your first submission will count toward your grade. You may use any course materials (videos, slides, reading notes, etc. ). You may use the ML, Racket, and Ruby REPLs. You may use text editors. You may use the standard-library documentation for the languages. You may not use the discussion forum. You may not use other websites related to programming. (Sites like dictionaries for translating English words are okay to use. )


Questions and Answers
  • 1. 

    [12 points] Check a box if and only if it is an accurate description of Racket.

    • A.

      Removing parentheses from around a function call can change a program's meaning, but it is always okay to add an extra set of parentheses.

    • B.

      The library function set-mcar! can be implemented in terms of set!.

    • C.

      An anonymous function can be written anywhere an expression is allowed.

    • D.

      Racket is a weakly typed language.

    • E.

      Thunking is a programming idiom that does not need special support in the language beyond first-class function closures.

    • F.

      At the top-level in a file, an earlier function definition can refer to a later function definition.

    Correct Answer(s)
    C. An anonymous function can be written anywhere an expression is allowed.
    E. Thunking is a programming idiom that does not need special support in the language beyond first-class function closures.
    F. At the top-level in a file, an earlier function definition can refer to a later function definition.
  • 2. 

    [5 points] Which of the following Racket functions correctly takes a stream s and returns a stream that repeats each stream element from s twice? So, for example, calling the function with the stream that generates 1 2 3 ... would return a stream that generates 1 1 2 2 3 3 ...

    • A.

      (define (twice-each s) (lambda () (let ([pr (s)]) (cons (car pr) (lambda () (cons (car pr) (twice-each (cdr pr))))))))

    • B.

      (define (twice-each s) (let ([pr (s)]) (cons (car pr) (lambda () (cons (car pr) (twice-each (cdr pr)))))))

    • C.

      (define (twice-each s) (lambda () (let ([pr (s)]) (cons (car pr) (cons (car pr) (twice-each (cdr pr)))))))

    • D.

      (define (twice-each s) (let ([pr (s)]) (cons (car pr) (lambda () (cons (cdr pr) (twice-each ((cdr pr))))))))

    Correct Answer
    A. (define (twice-each s) (lambda () (let ([pr (s)]) (cons (car pr) (lambda () (cons (car pr) (twice-each (cdr pr))))))))
    Explanation
    The correct answer is the first option, which is (define (twice-each s) (lambda () (let ([pr (s)]) (cons (car pr) (lambda () (cons (car pr) (twice-each (cdr pr)))))))). This function correctly takes a stream and returns a stream that repeats each element from s twice. It does this by defining a lambda function that takes a stream and uses cons to create a new stream that repeats each element twice. The function recursively calls itself with the cdr of the original stream to continue generating the repeated stream.

    Rate this question:

  • 3. 

    [8 points] Which of the following is true of the promises we studied and defined using my-force and my-delay in Racket?

    • A.

      Evaluating (my-force (my-delay (lambda () e))) always produces the same result as evaluating e.

    • B.

      Evaluating (my-delay (my-force (lambda () e))) always produces the same result as evaluating e.

    • C.

      Evaluating (my-force (my-delay (my-delay (lambda () e)))) always produces the same result as evaluating e.

    • D.

      Evaluating (my-force (my-delay (my-delay (lambda () e)))) will not evaluate e.

    Correct Answer(s)
    A. Evaluating (my-force (my-delay (lambda () e))) always produces the same result as evaluating e.
    D. Evaluating (my-force (my-delay (my-delay (lambda () e)))) will not evaluate e.
    Explanation
    Evaluating (my-force (my-delay (lambda () e))) always produces the same result as evaluating e: This statement is true because the my-delay function delays the evaluation of the expression inside it until it is forced with my-force. Therefore, when we force the delayed expression, it will be evaluated and produce the same result as evaluating e directly.

    Evaluating (my-force (my-delay (my-delay (lambda () e)))) will not evaluate e: This statement is also true because the my-delay function delays the evaluation of the expression inside it. However, when we force the delayed expression twice, it will only evaluate the inner delay once and not evaluate e.

    Rate this question:

  • 4. 

    [8 points] Let e be a Racket expression. Consider these two versions of function f:(define (f) ; call this version A (let ([x e]) (if x x 42))) (define (f) ; call this version B (if e e 42)) Check the box below if and only if there exists any e such that the statement is true. Note different choices below can be true by choosing a different e for each, but in the code above we mean the same expression e wherever e appears.

    • A.

      Calling version A is equivalent to calling version B.

    • B.

      Calling version A evaluates e more times than calling version B.

    • C.

      Calling version A does not terminate but calling version B does terminate.

    • D.

      Version A and version B both always return 42.

    Correct Answer(s)
    A. Calling version A is equivalent to calling version B.
    D. Version A and version B both always return 42.
    Explanation
    The answer "Calling version A is equivalent to calling version B" is correct because both versions of the function f have the same logic and will return the same result. The answer "Version A and version B both always return 42" is also correct because in both versions, if the value of e is truthy, it will be returned, otherwise, 42 will be returned.

    Rate this question:

  • 5. 

    [5 points] Suppose a MUPL interpreter implements lexical scope for function calls incorrectly by evaluating the function body using the environment where the function is called rather than where it is defined. Which of the MUPL programs below is a good test for this bug because (eval-exp ...) will produce the wrong answer if ... is replaced with the MUPL program.A few relevant Racket struct definitions for MUPL are repeated here as a convenient reminder:(struct var (string) #:transparent) ;; a variable, e.g., (var "foo") (struct int (num) #:transparent) ;; a constant number, e.g., (int 17) (struct fun (nameopt formal body) #:transparent) ;; a recursive(?) 1-argument function (struct call (funexp actual) #:transparent) ;; function call (struct mlet (var e body) #:transparent) ;; a local binding (let var = e in body)

    • A.

      (mlet "x" (int 0) (mlet "x" (int 1) (mlet "f" (fun #f "y" (var "x")) (call (var "f") (var "x")))))

    • B.

      (mlet "f" (mlet "x" (int 0) (fun #f "y" (var "x"))) (mlet "x" (int 1) (call (var "f") (var "x"))))

    • C.

      (mlet "x" (int 0) (mlet "f" (fun #f "y" (mlet "x" (int 1) (var "x"))) (call (var "f") (var "x"))))

    • D.

      (mlet "x" (int 0) (call (fun #f "y" (var "x")) (var "x")))

    Correct Answer
    B. (mlet "f" (mlet "x" (int 0) (fun #f "y" (var "x"))) (mlet "x" (int 1) (call (var "f") (var "x"))))
    Explanation
    The MUPL program (mlet "f" (mlet "x" (int 0) (fun #f "y" (var "x"))) (mlet "x" (int 1) (call (var "f") (var "x")))) is a good test for the bug because it involves nested function definitions and variable bindings. If the interpreter incorrectly evaluates the function body using the environment where the function is called rather than where it is defined, the value of "x" inside the inner function will be incorrect and the result will be wrong.

    Rate this question:

  • 6. 

    [5 points] Suppose we change ML so that its type system works as follows: If a function takes a tuple with n pieces, then you can call that function with any tuple with m pieces as long as m >= n. (At run-time, the extra tuple components would be evaluated before calling the function and then ignored by the function body.) We do not change what the ML type system is supposed to prevent except for this particular change of allowing tuples that are "too big" for function calls. Which of the following is true?

    • A.

      The type system before this change is sound and complete and after this change is sound and complete.

    • B.

      The type system before this change is sound and not complete and after this change is sound and not complete.

    • C.

      The type system before this change is sound and complete and after this change is sound and not complete.

    • D.

      The type system before this change is sound and complete and after this change is not sound but is complete.

    • E.

      The type system before this change is sound and not complete and after this change is not sound and not complete.

    Correct Answer
    B. The type system before this change is sound and not complete and after this change is sound and not complete.
  • 7. 

    [10 points] For each of the following, check the box if and only if it is an accurate description of an advantage of static typing over dynamic typing.

    • A.

      If you are writing a function/method that should be called only with values of one type, it is more convenient because you do not need to add a run-time type test to the function/method body.

    • B.

      Static checking catches all the simple bugs, so your testing only has to test how multiple functions/methods are used together.

    • C.

      If you change the return type of a function/method, the type-checker will give a list of callers that still assume the old return type.

    • D.

      Languages with static type systems cannot have security bugs where "anything might happen."

    • E.

      A language with static typing always supports generic types, which are more powerful than subtyping.

    Correct Answer(s)
    A. If you are writing a function/method that should be called only with values of one type, it is more convenient because you do not need to add a run-time type test to the function/method body.
    C. If you change the return type of a function/method, the type-checker will give a list of callers that still assume the old return type.
    Explanation
    Static typing provides an advantage in the scenario where a function or method is designed to only accept values of a specific type. In such cases, there is no need to include a run-time type test within the function or method body, making it more convenient to implement. Additionally, if the return type of a function or method is changed, the static type-checker can identify all the callers that still assume the old return type, allowing for easier identification and resolution of potential issues.

    Rate this question:

  • 8. 

    [12 points] This question uses this Ruby code, where ... is assumed to be some correct code not relevant to the question.class A def m1 self.m2() end def m2 ... end end module M def m3 self.m4() end end class B < A def m2 ... end end class C < A include M def m4 ... end end class D < B include M end For each Ruby expression below, check the box if evaluating the expression would lead to a method-missing error.

    • A.

      B.new.m1

    • B.

      B.new.m3

    • C.

      C.new.m1

    • D.

      C.new.m3

    • E.

      D.new.m1

    • F.

      D.new.m3

    Correct Answer(s)
    B. B.new.m3
    E. D.new.m1
    F. D.new.m3
    Explanation
    Evaluating the expression B.new.m3 would lead to a method-missing error because class B does not define the method m4, which is called in the m3 method of module M. Evaluating the expression D.new.m1 would also lead to a method-missing error because class D inherits from class B, which does not define the method m1. Evaluating the expression D.new.m3 would also lead to a method-missing error because class D includes module M, which defines the method m4 that is called in the m3 method.

    Rate this question:

  • 9. 

    [14 points] Check the box if and only if the statement is true.

    • A.

      It should be a run-time error in Ruby to send the push message to an array holding 0 elements.

    • B.

      In Ruby, a method can use yield to call the block provided by the caller even if the method did not indicate that it expected a block.

    • C.

      In Ruby, the class of object nil is nil, so no methods are defined on this object.

    • D.

      In OOP, defining a method in a class that just returns the value of a field (what Ruby calls an instance variable) is not useful: it is analogous to unnecessary function wrapping.

    • E.

      Ruby has a notion of subclassing but no notion of subtyping.

    • F.

      Dynamic dispatch means that a call like self.foo in a method defined in class A could call code in a subclass of A that the writer of the class A code does not know exists.

    • G.

      If class C overrides method m from a superclass, then in the body of C's definition of m, the keyword super is just syntactic sugar for m.

    Correct Answer(s)
    B. In Ruby, a method can use yield to call the block provided by the caller even if the method did not indicate that it expected a block.
    E. Ruby has a notion of subclassing but no notion of subtyping.
    F. Dynamic dispatch means that a call like self.foo in a method defined in class A could call code in a subclass of A that the writer of the class A code does not know exists.
    Explanation
    In Ruby, a method can use yield to call the block provided by the caller even if the method did not indicate that it expected a block. This means that a method can still execute a block of code even if the caller did not explicitly pass a block to the method.

    Ruby has a notion of subclassing but no notion of subtyping. This means that Ruby supports the concept of creating a new class that inherits properties and methods from a parent class, but it does not have the concept of subtyping, which is the ability to treat an instance of a subclass as an instance of its superclass.

    Dynamic dispatch means that a call like self.foo in a method defined in class A could call code in a subclass of A that the writer of the class A code does not know exists. This means that when a method is called on an object, the appropriate implementation of the method is determined at runtime based on the actual type of the object, allowing for polymorphism and flexibility in object-oriented programming.

    Rate this question:

  • 10. 

    [5 points] Which of the following programming problems would lead to a solution using double dispatch in Ruby if the programmer wanted to maintain a "full" commitment to OOP?

    • A.

      Provide a reusable Button class for a graphical interface that subclasses can specialize by changing the size, color, and text of the button.

    • B.

      Provide a class like ML's lists that has a sort method that reuses methods provided by standard-library mixins.

    • C.

      Provide classes that represent each of the "essential" amino acids, each with a method resultOfCombining that takes an argument that is another "essential" amino acid and returns the protein resulting from combining the two amino acids.

    • D.

      Provide a mixin that is like Enumerable except it raises an error if any of its methods are used on an empty collection, where the notion of emptiness is provided by classes via an empty? method.

    Correct Answer
    C. Provide classes that represent each of the "essential" amino acids, each with a method resultOfCombining that takes an argument that is another "essential" amino acid and returns the protein resulting from combining the two amino acids.
    Explanation
    The correct answer is to provide classes that represent each of the "essential" amino acids, each with a method resultOfCombining that takes an argument that is another "essential" amino acid and returns the protein resulting from combining the two amino acids. This problem would lead to a solution using double dispatch in Ruby because the result of combining two amino acids depends on the specific combination of amino acids involved. By using double dispatch, the method can determine the appropriate combination based on the types of the two amino acids, allowing for a more flexible and extensible solution in an object-oriented manner.

    Rate this question:

  • 11. 

    [16 points] In this problem, suppose we add record subtyping and function subtyping to ML. Because ML records are immutable (there is no way to assign to a field after a record is created), depth subtyping is sound for records. So assume record subtyping supports width, permutation, and depth, and that function subtyping supports contravariant arguments and covariant results.For each of the function calls below, check the box if and only if the function call should type-check assuming these variables have the types indicated:(* assume these variables are bound to functions with the given types; they are used below *) val f1 : { a:int, b : { c:int, d:int } } -> { a:int } = ... val f2 : { a:int } -> { a:int, b : { c:int, d:int } } = ... val f3 : { a:int, b : { c:int, d:int } } -> { a:int, b : { c:int, d:int } } = ... val f4 : (({ a:int, b : { c:int} } -> { a:int }) * int) -> { a:int } = ... val r1 : { a:int } = { a = 1 } val r2 : { a:int, b : { c:int} } = { a=1, b = { c=2 } } val r3 : { a:int, b : { c:int, d:int}, e:int } = { a=1, b = { c=2, d=3}, e=4 } val r4 : { a:int, b : { c:int, d:int, e:int }} = { a=1, b = { c=2, d=3, e=4} }

    • A.

      F1 r1

    • B.

      F1 r2

    • C.

      F1 r3

    • D.

      F1 r4

    • E.

      F2 r1

    • F.

      F2 r2

    • G.

      F2 r3

    • H.

      F2 r4

    • I.

      F4(f1,42)

    • J.

      F4(f2,42)

    • K.

      F4(f3,42)

    Correct Answer(s)
    C. F1 r3
    D. F1 r4
    E. F2 r1
    F. F2 r2
    G. F2 r3
    H. F2 r4
    J. F4(f2,42)

Quiz Review Timeline +

Our quizzes are rigorously reviewed, monitored and continuously updated by our expert board to maintain accuracy, relevance, and timeliness.

  • Current Version
  • Nov 16, 2023
    Quiz Edited by
    ProProfs Editorial Team
  • Dec 11, 2015
    Quiz Created by
    Gorin
Back to Top Back to top
Advertisement
×

Wait!
Here's an interesting quiz for you.

We have other quizzes matching your interest.