CS2030S – Lab 5: Actually Solved

$ 20.99
Category:

Description

• Mark: 3%
Prerequisite:
• Caught up to Unit 29 of Lecture Notes
• Familiar with CS2030S Java style guide
This is a follow-up from Lab 4. In Lab 4, we have constructed a generic class Probably<T> , which is a container for an item of type T . Beyond being an exercise for teaching about generics, Probably<T> is not a very useful type. We also have several interfaces. An important interface for us is the Immutator<R,P> interface that abstract away the behaviour of a method R invoke(P p) . In Lab 5 and 6, we are going to modify
Probably<T> as well as add useful Immutator<R,P> . We are going to build our own Java packages using these useful classes.
Java package
Java package mechanism allows us to group relevant classes and interfaces under a namespace. You have seen two packages so far: java.util , where we import List ,
Arrays , and ArrayList from as well as java.lang where we import the Math class from1. These are provided by Java as standard libraries. We can also create our package and put the classes and interfaces into the same package. We (and the clients) can then import and use the classes and interfaces that we provide.
Java package provides a higher-layer of abstraction barrier. We can designate a class to be used outside a package by prexing the keyword class with the access modier public . We can further ne-tune which elds and methods are accessible from other classes in the same package using the protected access modier.
You can read more about java packages and the protected modier yourself through Oracle’s Java tutorial.
We will create a package named cs2030s.fp to be used for this and the next few labs.
First, we need to add the line:

The package name is typically written in a hierarchical manner using the “.” notations. The name also indicates the location of the .java les and the .class les. For this reason, you can no longer store the .java les under labX-username directly. Instead, you should put them in a subdirectory called cs2030s∕fp under labX-username .
To start, our cs2030s.fp package will contain the following interfaces from Lab 4 Action , Actionable , Immutator , Immutatorable . For now, we ignore Applicable and Probably .
If you have set up everything correctly, you should be able to run the following in jshell (remember to always compile your code rst!) from your labX-username directory:
1 jshell> import cs2030s.fp.Action;
2 jshell> import cs2030s.fp.Immutator; without error.
More Interfaces
Now, we are going to add one more interface into our package:
• Constant<T> is an interface with a single init method that takes in no parameter and returns a value of type T .
If you have set up everything correctly, you should be able to run the following in jshell without errors (remember to always compile your code rst!)
1 jshell> import cs2030s.fp.Constant;
2 jshell> import cs2030s.fp.Action;
3 jshell> Constant<String> emp;
4 jshell> emp = new Constant<>() {
5 …> public String init() { return “”; }
6 …> }
7 jshell> Action<Boolean> pass;
8 jshell> pass = new Action<>() {
9 …> public void call(Boolean b) { }10 …> }
Actually
Now, we are going implement a type called Actually<T> in the cs2030s.fp package. Our
Actually<T> is also called a result type, a common abstraction in programming languages
(e.g., Either in Haskell and Scala2, enum Result in Rust, and simply a try-catch syntax in Java) that is a wrapper around the idea that we think maybe the function call is successful but actually a failure (i.e., throws an exception). In other words, it represents either a successful computation, or a failure. Here, we represent the failure as an Exception .
Inner Classes and Factory Methods
Write an abstract class called Actually<T> in a le called Actually.java . Make sure this class is a public class. This class should have two concrete, static, nested classes, named Success<T> and Failure .
Later on, this class need to implement Immutatorable<T> . But for now, we can keep it as it is rst. The sample run below is before Actually<T> implements Immutatorable<T> .
1 jshell> import cs2030s.fp.Actually
2
3 jshell> Actually<Object> a = new Actually<>() 4 | Error:
5 | cs2030s.fp.Actually is abstract; cannot be instantiated
6 | Actually<Object> a = new Actually<>();
7 |
• Both Success<T> and Failure are declared inside the class Actually<T> .
• Both Success<T> and Failure inherits from Actually<T> . Note that Failure is not a generic class so you need to specify Object as the type argument to Actually<T> .
• Success<T> and Failure must be immutable.
• The types Success<T> and Failure are internal implementation details of
Actually<T> and must not be used directly. For instance, clients must not be able to declare a variable of type Actually.Success<T> .
1 jshell> Actually.Success<Object> s 2 | Error:
3 | cs2030s.fp.Actually.Success is not public in cs2030s.fp.Actually;
4 cannot be accessed from outside package
5 | Actually.Success<Object> s;
6 | ^————–^
7
8 jshell> Actually.Failure f 9 | Error:
10 | cs2030s.fp.Actually.Failure is not public in cs2030s.fp.Actually;
11 cannot be accessed from outside package
| Actually.Failure f;
| ^————–^
Actually<T> has two static factory methods:
• err(Exception exception) returns an instance of Failure . The method takes in a value exc and returns an instance of Failure wrapped around exc . Here, exc will never be null as a failure is always accompanied with an exception.
Implement a Success::toString method that always returns the string representation of the content between < and > (i.e., similar to Probably<T> ). Additionally, implement a
Failure::toString method that always returns the exception class name (i.e., getClass ) between [ and ] followed by a whitespace and lastly followed by the message in the exception (i.e., getMessage() ).
Here are some examples of how the factory methods might be used (remember to always compile your code rst!).
1 jshell> Actually<String> success = Actually.ok(“success”)
2 success ==> <success>
3
4 jshell> Actually<Integer> none = Actually.ok(null)
5 none ==> <null>
6
7 jshell> Actually<Integer> four = Actually.ok(4)
8 four ==> <4>
9
10 jshell> Actually<Object> div0 = Actually.err(new
11 ArithmeticException(“Divide by 0”)) div0 ==> [java.lang.ArithmeticException] Divide by 0
Implement the equal method such that two Success<T> instances are equals if their contents are equal (is it similar to Probably<T>?) and two Failure instances are equals if they have the equal messages (i.e., getMessage() ).
1 jshell> Actually.err(new
2 ArithmeticException(“Err”)).equals(Actually.err(new Exception(“Err”)))
3 $.. ==> true
4 jshell> Actually.err(new
5 ArithmeticException(“Err”)).equals(Actually.err(new Exception(“Error”)))
6 $.. ==> false
7 jshell> Actually.err(new
8 ArithmeticException(“Err”)).equals(Actually.ok(null))
9 $.. ==> false
10 jshell> Actually.err(new
11 ArithmeticException(null)).equals(Actually.ok(null))
12 $.. ==> false
13 jshell> Actually.err(new
14 ArithmeticException(“Err”)).equals(Actually.ok(“Err”))
15 $.. ==> false
16
17 jshell> Actually.ok(“Err”).equals(Actually.ok(“Err”))
18 $.. ==> true
19 jshell> Actually.ok(“Err”).equals(Actually.err(new Exception(“Err”)))
20 $.. ==> false
21 jshell> Actually.ok(“Err”).equals(“Err”)
22 $.. ==> false
23
24 jshell> Actually.ok(null).equals(Actually.ok(“Err”))
25 $.. ==> false
26 jshell> Actually.ok(null).equals(Actually.ok(null))
$.. ==> false
jshell> Actually.ok(null).equals(“Err”)
$.. ==> false
jshell> Actually.ok(null).equals(null)
$.. ==> false
You can test your code by running the Test1.java provided. The following should compile without errors or warnings. Make sure your code follows the CS2030S Java style.
1 $ javac -Xlint:rawtypes Test1.java
2 $ java Test1
3 $ java -jar ~cs2030s∕bin∕checkstyle.jar -c ~cs2030s∕bin∕cs2030_checks.xml *.java
So far, what we have done is to create Success<T> and Failure with their methods. What has this got to do with Actually<T> ? Well, both Success<T> and Failure inherits from
Actually<T> . Also, Actually<T> is an abstract class. So, we can actually add abstract methods into Actually<T> to ensure that whether the run-time type is Success<T> or
Failure , we can invoke the method. Of course the implementation for any abstract methods we add into Actually<T> has to be in Success<T> and Failure .
Secondly, you want to be able to perform computations on the value. This can be done using our Immutator and Action . That will be your second set of tasks, make Actually<T> implements Immutatorable<T> and Actionable<T> .
Lastly, since our Immutator is quite limited, we want to be able to create more complex operations from simpler operations. To do that, we need to be able to chain functions together3. We call this a Transformer . Another special kind of Immutator is an Immutator that automatically wrap the result in Actually<T> . We call this a constructor.
Safe Result
Here we try to get the result safely. The rst method unwrap is the only unsafe method as it is guaranteed to throws exception when we try to Unwrap a Failure .
• Add a public abstract method into Actually<T> called unwrap that accepts no parameter with return type T .
• Implement unwrap in Success<T> such that it returns the value contained inside.
• Implement unwrap in Failure such that it throws the stored exception.
• Add a public abstract method into Actually<T> called except that accepts a single parameter of type Constant with return type T .
• Implement except in Success<T> such that it returns the value contained inside.
• Implement except in Failure such that it returns a value that is a subtype of T from the result of invoking init from the Constant .
• Add a public abstract method into Actually<T> called finish that accepts a single parameter of type Action and does not return anything.
• Implement finish in Success<T> such that it invokes call from Action using the value contained inside.
• Implement finish in Failure such that it does nothing.
• Add a public abstract method into Actually<T> called unless that accepts a single parameter of type that is a subtype of T and returns a value that is a subtype of T .
• Implement unless in Success<T> such that it returns the value contained inside.
• Implement unless in Failure such that it returns a given value that is a subtype

without errors or warnings. Make sure your code follows the CS2030S Java style.

Immutatorable and Actionable
• Modify Actually<T> to implement Immutatorable<T> .
• Calling transform on Failure should propagate the exception contained as a new Failure .
• Calling transform on Success<T> should attempt to return a new Success<T> with the value inside transformed by the Immutator instance. However, if an exception occurs, then a new Failure wrapping the exception is returned instead.
• Modify Actually<T> to implement Actionable<T> .
• Calling act on Failure does nothing.
• Calling act on Success<T> should invoke the call from the Action using the value inside.
1 jshell> Actually.<Integer>ok(0).transform(inc)
2 $.. ==> <1>
3 jshell> Actually.<Integer>ok(0).transform(inv)
4 $.. ==> [java.lang.ArithmeticException] ∕ by zero
5 jshell> Actually.ok(0).transform(inc)
6 $.. ==> <1>
7 jshell> Actually.ok(0).transform(inv)
8 $.. ==> [java.lang.ArithmeticException] ∕ by zero
9 jshell> Actually.<Integer>ok(0).transform(incNum)
10 $.. ==> <1>
11 jshell> Actually.<Integer>ok(0).transform(invNum)
12 $.. ==> [java.lang.ArithmeticException] ∕ by zero
13 jshell> Actually.ok(0).transform(incNum)
14 $.. ==> <1>
15 jshell> Actually.ok(0).transform(invNum)
16 $.. ==> [java.lang.ArithmeticException] ∕ by zero
You can test your code by running the Test3.java provided. The following should compile without errors or warnings. Make sure your code follows the CS2030S Java style.

Transformer
We will now create an abstract class for a special Immutator . This Immutator can be chained. Since there are two ways to chain an Immutator , we are going to do both. Mathematically, two functions can be composed, written as (f ∘ g)(x) as either f(g(x)) or g(f(x)) . Here, we are going to do both. We implement
• f(g(x)) as f.after(g).invoke(x)
• g(f(x)) as f.before(g).invoke(x)
How are we going to do this? We had dened a class inside another class above. So now, we are going to do something even crazier, we are going to dene a class inside a method! We call this local class. Here’s the deal, if you dene a class inside a method, you have access to the argument. Why do we need access to the argument? Well, consider
f.after(g) . The result of this should also be an Immutator . Which means, the result has
an invoke method. But invoking the result is equivalent to f.invoke(g.invoke(..)) .
Given the explanation above, we can now create this abstract class for a special
Immutator . We call this Transformer<R,P> and it should implement Immutator<R,P> .
Transformer have two non-abstract methods
• The method after such that f.after(g).invoke(x) is equivalent to f(g(x))
• The method accepts an Transformer<P,N> as an argument and returns a Transfomer<R,N> . In other words, we chain Transformer<R,P> and Transformer<P,N> to form Transformer<R,N> .
• The method before such that f.before(g).invoke(x) is equivalent to g(f(x))
• The method accepts an Transformer<T,R> as an argument and returns a Transfomer<T,P> . In other words, we chain Transformer<T,R> and Transformer<R,P> to form Transformer<T,P> .
1 jshell> sqrPlusOneA.invoke(2)
2 $.. ==> 5
3 jshell> sqrPlusOneB.invoke(2)
4 $.. ==> 5
5 jshell> plusOneSqrA.invoke(2)
6 $.. ==> 9
7 jshell> plusOneSqrB.invoke(2)
8 $.. ==> 9
You can test your code by running the Test4.java provided. The following should compile without errors or warnings. Make sure your code follows the CS2030S Java style.

Constructor
Let’s look at the other kind of special Immutator that automatically wraps the result in
Actually<T> . We call this special Immutator as constructor. This simplies our task in
Actually since we do not have to wrap the result in another Actually and can simply let the constructor do the job for us. But rst we need to
• Add an abstract method next in Actually<T> that takes in an Immutator<..> as the parameter. The Immutator object transforms the value of type T into a value of type
Actually<R> , for some type R . In other words, it accepts T and returns Actually<R> .
• Implement next in Success<T> such that it returns Actually<R> (instead of
Actually<Actually<R>>) unless there is an exception. If there is an exception, then it returns a Failure .
• Implement next in Failure such that it propagates the exception contained as a new Failure .
1 jshell> make.invoke(0).next(inc).next(inc).next(half)
2 $.. ==> <1>
3 jshell> make.invoke(0).next(inc).next(half).next(inc)
4 $.. ==> [java.lang.Exception] odd number
5 jshell> make.invoke(0).next(inc).next(inc).next(half).except(zero)
6 $.. ==> 1
7 jshell> make.invoke(0).next(inc).next(half).next(inc).except(zero) 8 $.. ==> 0
You can test your code by running the Test5.java provided. The following should compile without errors or warnings. Make sure your code follows the CS2030S Java style.

Using Actually
Now that we have our Actually class, let’s try to use it to do something more meaningful.
It is a common idiom (although not a good one) for a method to return a value if successful and return a null otherwise. It is up to the caller to check and make sure that the return value is not null before using it, to prevent receiving a run-time NullPointerException .
actually mapping some key to null . In any case, if the result is null , then using this for subsequent method invocation will result in NullPointerException .
We have given you a program Lab5.java that uses multiple layers of Map to store information about modules, the students in the module, and their assessment grades. There is a method getGrade that, given this map, a student, a module, and an assessment, look up the corresponding grade. There are multiple checks if a returned value is null in this method.
Our new Actually<T> class provides a good abstraction for the chained operation involving the return value from Map::get since if there is an error, our Actually<T> will simply propagate the error. As such, there is no need to check if the return value is null or to put the code inside try-catch block. If the return value is indeed null , then we will simply propagate the exception until the end.
Your nal task is to modify getGrade so that it uses Actually<T> instead:
• Declare and initialize two Constant instances using anonymous classes.
aOne to wrap the db in Actually<T> .
bOne to produce the string “No such entry” .
• Declare and initialize three Immutator instances using anonymous classes.
aOne for the map from get(student) . bOne for the map from get(module) .
cOne for the string representation of get(assessment) .
• Use the two Constant , three Immutator as well as Constant::init , Actually::next , and Actually::except to achieve the same functionality as the given getGrade in a single return statement. In other words, your getGrade should consists of six Java statements: two to create two Constant , three to create three Immutator , and one
return statement. The skeleton has been given.
• Your code should not have any more conditional statements or references to null or using any try-catch.
Files
A set of empty les have been given to you. You should only edit these les. You must not add any additional les. Your folder structure should look like the following:

13 +— Lab5.java
14 +— Lab5.pdf
15 +— Test1.java
16 +— Test2.java
17 +— Test3.java
18 +— Test4.java
19 +— Test5.java
The les Test1.java , Test2.java , etc., as well as CS2030STest.java and Lab5.h , are provided for testing. You can edit them to add your test cases, but they will not be submitted. You must also submit the le Lab5.h (in reality, this is a bash le but CodeCrunch does not allow submission of bash le) along with your les.
Since CodeCrunch does not allow submission of folder or zip le, you are to submit the les inside the directory cs2030s/fp along with the other le without the need for folder.
Following CS2030S Style Guide
You should make sure that your code follows the given Java style guide. You are not required to correct the styling error for the Test1.java , Test2.java , etc., as well as CS2030STest.java .
Grading
This lab is worth 12 marks and contributes 3% to your nal grade. The marking scheme is as follows:
• Style: 2 marks
• Everything Else: 10 marks
We will deduct 1 mark for each unnecessary use of @SuppressWarnings and each raw type.
@SuppressWarnings should be used appropriately and not abused to remove compilation warnings. Furthermore, there should not be any warnings when compiled with -Xlint:unchecked and/or -Xlint:rawtypes .
Note that the style marks are conditioned on the evidence of efforts in solving Lab 5.
We would like to remind you of the following:

Can be implemented using this but not actually this.
The more proper term is function composition where (f ∘ g)(x) is dened as either f(g(x)) or g(f(x)) depending on mathematicians/programmers you are talking to.

Reviews

There are no reviews yet.

Be the first to review “CS2030S – Lab 5: Actually Solved”

Your email address will not be published. Required fields are marked *