Note you will need both your Ryerson and your CS (moon) login credentials!
Follow these instructions to access the exam environment:
- 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.
- You need to login with your CS (moon) username and password to the lab machine. You will be in Windows.
- Open a browser "Microsoft Edge or Chrome" then go to: https://cps506.cs.ryerson.ca/ then final, then to this page.
- Open another tab in the browser and go to: https://vdi.cs.ryerson.ca
- You have to login with two factor authentication using your Ryerson username and password.
- Once you are authenticated you will be redirected to the actual vdi page
- Click on "VMware Horizon HTML Access"
- Login using your CS username and password. Same as you did with the workstation at the beginning
- 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.
- On Windows
- Use the
H:drive - that is where you will see your home directory (which will have a folder calledExamQuestions - 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!!!!!
- Open a powershell, and immediately go to the
H: - There you will see a folder with all the exam questions in it. You can see a sample below
- Even though all your files are on the
H:drive, some of the editors may default toC: - For Pharo,
cd Smalltalk, then you can open Pharo withpharo CPS506Exam.image(note slight difference from Linux)
- Use the
- On Linux
- It's a lot more straghtforward
- In your home directory, you will see a folder with all the exam questions in it. You can see a sample below
- For Pharo,
cd Smalltalk, then you can open Pharo withpharo-ui CPS506Exam.image(note slight difference from windows)
- In both environments
- Edit only the files in the
ExamQuestionsfolder/directory and subfolders/subdirectories. - All the mix/cabal/cargo folders have been created. You jus need to edit the files and run the tests (see below)
- There are 5 questions in each of the first 3 languages, 4 in Rust, and 6 in the ShortAnswer section.
- 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
- In the other directories, you will see
.txtfiles... which you simply edit and leave your answers in the files. - ...or there are sub-directories, which you can
cdto and then run the appropriate test command for the language (see below for reminder) - When you're done, whatever is in the home directories (on
H:for Windows) is what will be marked - 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.
- From the shell/terminal
emacs fileorvi filewill open the editor on the file. vscode may need to be opened from the GUI.
- Edit only the files in the
The following tools will be available:
- 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.
- Elixir - with a pre-loaded test script. Edit, run
mix testuntil all tests pass. - Haskell - with a pre-loaded test script. Edit, run
cabal testuntil all tests pass. - Rust - with a pre-loaded test script. Edit, run
cargo testuntil all tests pass. - Editors (they should all have highlighting for the languages):
emacsvimorvivscodenotepad++- on Windows
- Powershell and cmd - on Windows
- the full Linux shell environment - on Linux
The following documentation resources will be available:
- Both Dave's and Alex's slide decks as PDFs
- Smalltalk
- the interactive Prof Stef tutorial
- Learn Smalltalk in Y minutes
- Elixir
- Haskell
- Learn Haskell in Y minutes
- The PDF version of A Gentle Introduction to Haskell
- Haskell Cheat Sheet
- Rust
- Learn Rust in Y minutes
- Rust cheat sheet - but not the things linked from it
- Zig
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: -