Note you will need both your Ryerson and your CS (moon) login credentials!

Follow these instructions to access the exam environment:

  1. Leave your bag, any electronics, etc. at the edges of the lab (or under your chair in a plastic bag). Keep your student ID card. You may keep blank paper, pen/pencil, ear-plugs, but no electronics. Any brimmed hat must point backwards.
  2. You need to login with your CS (moon) username and password to the lab machine. You will be in Windows.
  3. Open a browser "Microsoft Edge or Chrome" then go to: https://cps506.cs.ryerson.ca/ then final, then to this page.
Now that you're here, you have access to all these resources:
  1. Open another tab in the browser and go to: https://vdi.cs.ryerson.ca
  2. You have to login with two factor authentication using your Ryerson username and password.
  3. Once you are authenticated you will be redirected to the actual vdi page
  4. Click on "VMware Horizon HTML Access"
  5. Login using your CS username and password. Same as you did with the workstation at the beginning
  6. Choose the domain "SCS.RYERSON.CA" and you will see pools named "CPS506-Windows" & "CPS506-Linux", click on one and a machine will be assigned to you.

You will be accessing a virtual Windows or Linux machine. You can choose either one.

  1. On Windows
    1. Use the H: drive - that is where you will see your home directory (which will have a folder called ExamQuestions
    2. you will also have a home directory on Windows - this will disappear when you log off and will not be seen by marking. DO NOT USE THIS!!!!!
    3. Open a powershell, and immediately go to the H:
    4. There you will see a folder with all the exam questions in it. You can see a sample below
    5. Even though all your files are on the H: drive, some of the editors may default to C:
    6. For Pharo, cd Smalltalk, then you can open Pharo with pharo CPS506Exam.image (note slight difference from Linux)
  2. On Linux
    1. It's a lot more straghtforward
    2. In your home directory, you will see a folder with all the exam questions in it. You can see a sample below
    3. For Pharo, cd Smalltalk, then you can open Pharo with pharo-ui CPS506Exam.image (note slight difference from windows)
  3. In both environments
    1. Edit only the files in the ExamQuestions folder/directory and subfolders/subdirectories.
    2. All the mix/cabal/cargo folders have been created. You jus need to edit the files and run the tests (see below)
    3. There are 5 questions in each of the first 3 languages, 4 in Rust, and 6 in the ShortAnswer section.
    4. In Smalltalk, when you open the image (see above) you'll see an exam-specific help page that will link you directly to the appropriate classes
    5. In the other directories, you will see .txt files... which you simply edit and leave your answers in the files.
    6. ...or there are sub-directories, which you can cd to and then run the appropriate test command for the language (see below for reminder)
    7. When you're done, whatever is in the home directories (on H: for Windows) is what will be marked
    8. There is no "submit" or "fossil" or "git" or "Iceberg" required... write your code, save it, test it, repeat until it works, then move on to the next.
    9. From the shell/terminal emacs file or vi file will open the editor on the file. vscode may need to be opened from the GUI.

The following tools will be available:

  1. Pharo 9 - with an image that will already have test cases defined. Open it, work on the Smalltalk questions, Save often, Save and Quit when you are done.
  2. Elixir - with a pre-loaded test script. Edit, run mix test until all tests pass.
  3. Haskell - with a pre-loaded test script. Edit, run cabal test until all tests pass.
  4. Rust - with a pre-loaded test script. Edit, run cargo test until all tests pass.
  5. Editors (they should all have highlighting for the languages):
    1. emacs
    2. vim or vi
    3. vscode
    4. notepad++ - on Windows
  6. Powershell and cmd - on Windows
  7. the full Linux shell environment - on Linux

The following documentation resources will be available:

  1. Both Dave's and Alex's slide decks as PDFs
  2. Smalltalk
    1. the interactive Prof Stef tutorial
    2. Learn Smalltalk in Y minutes
  3. Elixir
    1. Learn Elixir in Y minutes
    2. Elixir cheat sheet
    3. Elixir Kernel doc
    4. Elixir List doc
  4. Haskell
    1. Learn Haskell in Y minutes
    2. The PDF version of A Gentle Introduction to Haskell
    3. Haskell Cheat Sheet
  5. Rust
    1. Learn Rust in Y minutes
    2. Rust cheat sheet - but not the things linked from it
  6. Zig
    1. Zig language reference

Sample Questions

Note that for each language there is a somewhat increasing level of difficulty as you go from sq0 to sq4. Everybody should be able to do the simpler problems in each language. Realistically, not everyone will be able to do all questions easily, but there is no fixed order to working on problems or languages - leave questions that you find challenging (don't delete the code... we can't give part marks for no code!) and come back to them.

Smalltalk/CPS506Exam

sumSquare: aCollection
	" return the sum of the squares of the elements in the collection "
        self shouldBeImplemented.
weird: a with: b
" note that a can be a character collection (String) "
"      or it can be a collection of any value that understands > and negated "
" you should test with several kinds of collection and collections of several kinds of values "
	| temp |
	temp := a select: [: v | v > b ].
	^ b isCharacter ifTrue: [ temp capitalized ] ifFalse: [ temp negated ]

Smalltalk/CPS506MarkExam

You won't change this... it will be test cases that we use to mark your code. (We will actually use different values, but the same basic tests. If your code passes the tests here without hard-coding answers, it will work with our tests.)
testSumSquare
	self assert: (exam sumSquare: #()) equals: 0.
	self assert: (exam sumSquare: #(1 2 3)) equals: 14.
	self assert: (exam sumSquare: (-2 to: 3)) equals: 19.

Smalltalk/CPS506TestExam

Write a test for #weird:with:

Elixir/sq1/lib/sq1.ex

defmodule Sq1 do
  @moduledoc """
  Documentation for `Sq1`.
  """

  @doc """
  
  CPS506 Elixir sample question 1
  
  isAscending?/1 should return true if the elements of the 
  input list 'items' are strictly ascending. 
  Each element must be strictly larger (not merely equal to) 
  than the element that precedes it. 
  Return True if the list of items is strictly ascending, 
  and return False otherwise.
  Note that the empty list is ascending, as is every
  list containing only a single element. 
  
  """
  
  
  
end

Elixir/sq1/test/sq1_test.exs

defmodule Sq1Test do
  use ExUnit.Case
  doctest Sq1
  
  test "Testing []" do
    assert Sq1.isAscending?([]) == true
  end
  
  test "Testing [-5, 10, 99, 123456]" do
    assert Sq1.isAscending?([-5, 10, 99, 123456]) == true
  end
  
  test "Testing [2, 3, 3, 4, 5]" do
    assert Sq1.isAscending?([2, 3, 3, 4, 5]) == false
  end

  test "Testing [-99]" do
    assert Sq1.isAscending?([-99]) == true
  end
  
  test "Testing [4, 5, 6, 7, 3, 7, 9]" do
    assert Sq1.isAscending?([4, 5, 6, 7, 3, 7, 9]) == false
  end
  
  test "Testing [1, 1, 1, 1]" do
    assert Sq1.isAscending?([1, 1, 1, 1]) == false
  end
  
  test "Testing [4, 3, 2, 1]" do
    assert Sq1.isAscending?([4, 3, 2, 1]) == false
  end
  
  test "Testing [1, 2, 3, 3]" do
    assert Sq1.isAscending?([1, 2, 3, 3]) == false
  end
  
end

Elixir/sq1/test/test_helper.exs

ExUnit.start()

Elixir/sq2/lib/sq2.ex

defmodule Sq2 do
  @moduledoc """
  Documentation for `Sq2`.
  """

  @doc """
  
  CPS506 Elixir sample question 2
 
  onlyOddDigits?/1 should return true if the provided
  integer argument contains only odd digits (1, 3, 5, 7, 9)
  and false otherwise. Note that the digit '0' is 
  considered even.
  Hint: The functions rem/2 and div/2 will serve you well
  
  """
  
  
end

Elixir/sq2/test/sq2_test.exs

defmodule Sq2Test do
  use ExUnit.Case
  doctest Sq2

  test "Testing 8" do
    assert Sq2.onlyOddDigits?(8) == false
  end
  
  test "Testing 1" do
    assert Sq2.onlyOddDigits?(1) == true
  end
  
  test "Testing 13579753" do
    assert Sq2.onlyOddDigits?(13579753) == true
  end
  
  test "Testing 42" do
    assert Sq2.onlyOddDigits?(42) == false
  end
  
  test "Testing 71358" do
    assert Sq2.onlyOddDigits?(71358) == false
  end
  
  test "Testing 0" do
    assert Sq2.onlyOddDigits?(0) == false
  end
  
end

Elixir/sq2/test/test_helper.exs

ExUnit.start()

Haskell/sq1/app/Main.hs

module Main where

import qualified SQ1 (main)

main :: IO ()
main = SQ1.main

Haskell/sq1/src/SQ1.hs

module SQ1 (main, is_cyclops) where

main :: IO ()
main = do
    contents <- getLine
    putStrLn $ show $ is_cyclops (read contents::Int)

{--
CPS506 Haskell sample question 1

A non-negative integer is a cyclops number if its middle
digit, and ONLY its middle digit, is '0'.
If a number does not have a middle digit, i.e. it has
an even number of digits, it cannot be a cyclops number.
Hint: Perhaps it's easier to solve this if the integer
were represented as a String/[Char]...
-}

Haskell/sq1/src/TestSuite.hs

module Main where
    import Test.HUnit
    import qualified SQ1
    import qualified System.Exit as Exit

    main = do
         status <- runTestTT tests
         if failures status > 0 then Exit.exitFailure else return ()
- run tests with:
-     cabal test

- here are some standard tests
- you should augment them with your own tests for development purposes
    is_cyclops = SQ1.is_cyclops
    tests = test [
      "0" ~: True ~=? is_cyclops 0,
      "101" ~: True ~=? is_cyclops 101,
      "98053" ~: True ~=? is_cyclops 98053,
      "777888999" ~: False ~=? is_cyclops 777888999,
      "1056" ~: False ~=? is_cyclops 1056,
      "675409820" ~: False ~=? is_cyclops 675409820
      ]

Haskell/sq2/app/Main.hs

module Main where

import qualified SQ2 (main)

main :: IO ()
main = SQ2.main

Haskell/sq2/src/SQ2.hs

module SQ2 (main, domino_cycle) where

main :: IO ()
main = do
    putStrLn "Hello"

{--
CPS506 Haskell sample question 2

A domino is represented as a 2-tuple containing two integer
values, such as (2, 5) or (6, 6).
Given a list of dominos, determine if the list of dominos
forms a cycle, so that each domino ends with the same 
number that the next domino starts with. This property wraps
around the list. That is, the last domino must end with the 
same number that the first domino begins with.
You may assume the list contains at list one domino.
Return True if the dominos form a cycle, and False otherwise
Hint: The tuple functions fst and snd will come in handy...
-}

Haskell/sq2/src/TestSuite.hs

module Main where
    import Test.HUnit
    import qualified SQ2
    import qualified System.Exit as Exit

    main = do
         status <- runTestTT tests
         if failures status > 0 then Exit.exitFailure else return ()
- run tests with:
-     cabal test

- here are some standard tests
- you should augment them with your own tests for development purposes
    domino_cycle = SQ2.domino_cycle
    tests = test [
      "[(3, 5), (5, 2), (2, 3)]" ~: True ~=? domino_cycle [(3, 5), (5, 2), (2, 3)],
      "[(4, 4)]" ~: True ~=? domino_cycle [(4, 4)],
      "[(2, 6)]" ~: False ~=? domino_cycle [(2, 6)],
      "[(5, 2), (2, 3), (4, 5)]" ~: False ~=? domino_cycle [(5, 2), (2, 3), (4, 5)],
      "[(4, 3), (3, 1)]" ~: False ~=? domino_cycle [(4, 3), (3, 1)]
      ]

Rust/sq1/src/main.rs

#![allow(non_snake_case,non_camel_case_types,dead_code)]

// This is at the harder end of the Rust questions

// You must not change the types of the functions or the test code,
// so part of the requirement is to get the types correct

fn pairList1<a,b,c>(f:fn(a)->b,g:fn(b)->c,xs:Vec<a>) -> Vec<(b,c)> where a : Copy {
    // map f and g over the values of the vector in the way that makes the types work

}

fn pairList2<a,b,c>(f:fn(a)->b,g:fn(a)->c,xs:Vec<a>) -> Vec<(b,c)> where a : Copy {
    // map f and g over the values of the vector in the way that makes the types work

}

fn ff(x:i8) -> i32 {
    // return x plus 1

}
fn gg(x:i32) -> i64 {
    // return x times 2
    
}

#[cfg(test)]
#[path = "tests.rs"]
mod tests;

Rust/sq1/src/tests.rs

#[cfg(test)]
mod tests {
    // we adjust the path to:
    use super::super::{*};

    #[test]
    fn ff_test() {
        assert_eq!(ff(1),2);
        assert_eq!(ff(10),11);
        assert_eq!(ff(-5),-4);
    }

    #[test]
    fn gg_test() {
        assert_eq!(gg(1),2);
        assert_eq!(gg(10),20);
        assert_eq!(gg(-5),-10);
    }

    #[test]
    fn pairList1_test() {
        assert_eq!(pairList1(ff,gg,vec![1,2,3]), vec![(2, 4), (3, 6), (4, 8)]);
        assert_eq!(pairList1(ff,hh,vec![2,3,4,5]), vec![(3, 9), (4, 12), (5, 15), (6,18)]);
    }
    fn hh(x:i32) -> i64 {
        (x*3) as i64
    }
    
    #[test]
    fn pairList2_test() {
        assert_eq!(pairList2(ff,ii,vec![1,2,3]), vec![(2, 3), (3, 6), (4, 9)]);
    }
    fn ii(x:i8) -> i64 {
        (x*3) as i64
    }

}

ShortAnswer/q1.txt

Explain some of the important differences between tracing garbage collection and reference counting.
-

ShortAnswer/q2.txt

Explain 2 advantages of static typing and 2 advantages of dynamic typing:
-