CS2030 Lab 5: Actually solution




5/5 - (3 votes)

This is a follow-up from Lab 4. In Lab 4, we have constructed a generic class Probably , which is a container for an item of type T . Beyond being an exercise for teaching about generics, Probably 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 as well as add useful Immutator<R,P> . We are going to build our own Java packages using these useful classes. Java ppaacckkaaggee 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 pre�xing the keyword class with the access modi�er public . We can further �ne-tune which �elds and methods are accessible from other classes in the same package using the protected access modi�er. You can read more about java packages and the protected modi�er 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: on top of every .java �le that we would like to include in the package. 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: without error. More Interfaces Now, we are going to add one more interface into our package: • Constant 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!) Actually 1 package cs2030s.fp; 1 2 jshell> import cs2030s.fp.Action; jshell> import cs2030s.fp.Immutator; 1 2 3 4 5 6 7 8 9 10 jshell> import cs2030s.fp.Constant; jshell> import cs2030s.fp.Action; jshell> Constant emp; jshell> emp = new Constant<>() { …> public String init() { return “”; } …> } jshell> Action pass; jshell> pass = new Action<>() { …> public void call(Boolean b) { } …> } Now, we are going implement a type called Actually in the cs2030s.fp package. Our Actually 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 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 and Failure . Later on, this class need to implement Immutatorable . But for now, we can keep it as it is �rst. The sample run below is before Actually implements Immutatorable . • Both Success and Failure are declared inside the class Actually . • Both Success and Failure inherits from Actually . Note that Failure is not a generic class so you need to specify Object as the type argument to Actually . • Success and Failure must be immutable. • The types Success and Failure are internal implementation details of Actually and must not be used directly. For instance, clients must not be able to declare a variable of type Actually.Success . 1 2 3 4 5 6 7 jshell> import cs2030s.fp.Actually jshell> Actuallya = new Actually<>()| Error:| cs2030s.fp.Actually is abstract; cannot be instantiated| Actuallya = new Actually<>();|Actually has two static factory methods:• ok(T res) returns an instance of Success . The method takes in a value res andreturns an instance of Success wrapped around res . Here, res may be null andthat’s �ne, we also had a method that returns null in Lab 1 – 3.• err(Exception exception) returns an instance of Failure . The method takes in avalue exc and returns an instance of Failure wrapped around exc . Here, exc willnever be null as a failure is always accompanied with an exception.Implement a Success::toString method that always returns the string representation ofthe content between < and > (i.e., similar to Probably ). Additionally, implement aFailure::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 theexception (i.e., getMessage() ).Here are some examples of how the factory methods might be used (remember to alwayscompile your code �rst!).Implement the equal method such that two Success instances are equals if theircontents are equal (is it similar to Probably ?) and two Failure instances are equals if 1 2 3 4 5 6 7 8 91011jshell> Actually.Successs| Error:| cs2030s.fp.Actually.Success is not public in cs2030s.fp.Actually;cannot be accessed from outside package| Actually.Successs;| ^————–^jshell> Actually.Failure f| Error:| cs2030s.fp.Actually.Failure is not public in cs2030s.fp.Actually;cannot be accessed from outside package| Actually.Failure f;| ^————–^ 1 2 3 4 5 6 7 8 91011jshell> Actually success = Actually.ok(“success”)success ==> jshell> Actually none = Actually.ok(null)none ==> jshell> Actually four = Actually.ok(4)four ==> <4>jshell> Actuallydiv0 = Actually.err(newArithmeticException(“Divide by 0”))div0 ==> [java.lang.ArithmeticException] Divide by 0they have the equal messages (i.e., getMessage() ).You can test your code by running the Test1.java provided. The following should compilewithout errors or warnings. Make sure your code follows the CS2030S Java style.So far, what we have done is to create Success and Failure with their methods. Whathas this got to do with Actually ? Well, both Success and Failure inherits fromActually . Also, Actually is an abstract class. So, we can actually add abstractmethods into Actually to ensure that whether the run-time type is Success orFailure , we can invoke the method. Of course the implementation for any abstractmethods we add into Actually has to be in Success and Failure .Since Actually is an abstraction of the result of a computation –which may be presentor actually an exception– we want to be able to get the result in a safe way. That is going 1 2 3 4 5 6 7 8 91011121314151617181920212223242526jshell> Actually.err(newArithmeticException(“Err”)).equals(Actually.err(new Exception(“Err”)))$.. ==> truejshell> Actually.err(newArithmeticException(“Err”)).equals(Actually.err(new Exception(“Error”)))$.. ==> falsejshell> Actually.err(newArithmeticException(“Err”)).equals(Actually.ok(null))$.. ==> falsejshell> Actually.err(newArithmeticException(null)).equals(Actually.ok(null))$.. ==> falsejshell> Actually.err(newArithmeticException(“Err”)).equals(Actually.ok(“Err”))$.. ==> falsejshell> Actually.ok(“Err”).equals(Actually.ok(“Err”))$.. ==> truejshell> Actually.ok(“Err”).equals(Actually.err(new Exception(“Err”)))$.. ==> falsejshell> Actually.ok(“Err”).equals(“Err”)$.. ==> falsejshell> Actually.ok(null).equals(Actually.ok(“Err”))$.. ==> falsejshell> Actually.ok(null).equals(Actually.ok(null))$.. ==> falsejshell> Actually.ok(null).equals(“Err”)$.. ==> falsejshell> Actually.ok(null).equals(null)$.. ==> false123$ javac -Xlint:rawtypes Test1.java$ java Test1$ java -jar ~cs2030s∕bin∕checkstyle.jar -c ~cs2030s∕bin∕cs2030_checks.xml*.javato be your �rst set of tasks.Secondly, you want to be able to perform computations on the value. This can be doneusing our Immutator and Action . That will be your second set of tasks, makeActually implements Immutatorable and Actionable .Lastly, since our Immutator is quite limited, we want to be able to create more complexoperations from simpler operations. To do that, we need to be able to chain functionstogether3. We call this a Transformer . Another special kind of Immutator is an Immutatorthat automatically wrap the result in Actually . We call this a constructor.In all cases, remember to apply PECS in your method signature so that all the methods areas �exible as possible in the type that it accepts. As usual, the test cases given may not becomplete and there may be other test cases used.Safe ResultHere we try to get the result safely. The �rst method unwrap is the only unsafe method asit is guaranteed to throws exception when we try to Unwrap a Failure .• Add a public abstract method into Actually called unwrap that accepts noparameter with return type T .• Implement unwrap in Success 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 called except that accepts a singleparameter of type Constant with return type T .• Implement except in Success such that it returns the value contained inside.• Implement except in Failure such that it returns a value that is a subtype of Tfrom the result of invoking init from the Constant .• Add a public abstract method into Actually called finish that accepts a singleparameter of type Action and does not return anything.• Implement finish in Success such that it invokes call from Action usingthe value contained inside.• Implement finish in Failure such that it does nothing.• Add a public abstract method into Actually called unless that accepts a singleparameter of type that is a subtype of T and returns a value that is a subtype of T .• Implement unless in Success such that it returns the value contained inside.• Implement unless in Failure such that it returns a given value that is a subtypeof T .You can test your code by running the Test2.java provided. The following should compilewithout errors or warnings. Make sure your code follows the CS2030S Java style.Immutatorable and Actionable• Modify Actually to implement Immutatorable .• Calling transform on Failure should propagate the exception contained as anew Failure .• Calling transform on Success should attempt to return a new Successwith the value inside transformed by the Immutator instance. However, if anexception occurs, then a new Failure wrapping the exception is returnedinstead.• Modify Actually to implement Actionable .• Calling act on Failure does nothing.• Calling act on Success should invoke the call from the Action using thevalue inside. 1 2 3 4 5 6 7 8 91011121314jshell> Actually.ok(0).unwrap()$.. ==> 0jshell> Actually.ok(9).finish(print)$.. ==> 9jshell> Actually.err(new Exception(“Err”)).finish(print)$.. ==>jshell> Actually.ok(9).except(zero)$.. ==> 9jshell> Actually.err(new ArithmeticException(“div by0”)).except(zero)$.. ==> 0jshell> Actually.err(new ArithmeticException(“div by0”)).unless(4)$.. ==> 4jshell> Actually.ok(0).unless(4)$.. ==> 0123$ javac -Xlint:rawtypes Test2.java$ java Test2$ java -jar ~cs2030s∕bin∕checkstyle.jar -c ~cs2030s∕bin∕cs2030_checks.xml*.java 1 2 3 4jshell> Actually.ok(0).transform(inc)$.. ==> <1>jshell> Actually.ok(0).transform(inv)$.. ==> [java.lang.ArithmeticException] ∕ by zeroYou can test your code by running the Test3.java provided. The following should compilewithout errors or warnings. Make sure your code follows the CS2030S Java style.TransformerWe will now create an abstract class for a special Immutator . This Immutator can bechained. 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 de�ned a class inside another class above. So now,we are going to do something even crazier, we are going to de�ne a class inside a method!We call this local class. Here’s the deal, if you de�ne a class inside a method, you haveaccess to the argument. Why do we need access to the argument? Well, considerf.after(g) . The result of this should also be an Immutator . Which means, the result hasan invoke method. But invoking the result is equivalent to f.invoke(g.invoke(..)) .If we look at f.after(g) , then the argument is g and we can invoke g.invoke(..) insidethe local class. What we still need is to be able to use the result of g.invoke(..) asargument to f.invoke . We cannot really invoke f.invoke using this.invoke because weare in the local class so the keyword this is bound to this local class and not the originalf instance. An easy solution is to create a temporary variable called f assigned to this .The limitation in Java is that you cannot change the value of f . In other words, it is kind oflike there is a final keyword used on f .Given the explanation above, we can now create this abstract class for a special 5 6 7 8 910111213141516jshell> Actually.ok(0).transform(inc)$.. ==> <1>jshell> Actually.ok(0).transform(inv)$.. ==> [java.lang.ArithmeticException] ∕ by zerojshell> Actually.ok(0).transform(incNum)$.. ==> <1>jshell> Actually.ok(0).transform(invNum)$.. ==> [java.lang.ArithmeticException] ∕ by zerojshell> Actually.ok(0).transform(incNum)$.. ==> <1>jshell> Actually.ok(0).transform(invNum)$.. ==> [java.lang.ArithmeticException] ∕ by zero123$ javac -Xlint:rawtypes Test3.java$ java Test3$ java -jar ~cs2030s∕bin∕checkstyle.jar -c ~cs2030s∕bin∕cs2030_checks.xml*.javaImmutator . 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 aTransfomer<r,n> . In other words, we chain Transformer<r,p> andTransformer<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 aTransfomer<t,p> . In other words, we chain Transformer<t,r> andTransformer<r,p> to form Transformer<t,p> .You can test your code by running the Test4.java provided. The following should compilewithout errors or warnings. Make sure your code follows the CS2030S Java style.ConstructorLet’s look at the other kind of special Immutator that automatically wraps the result inActually . We call this special Immutator as constructor. This simpli�es our task inActually since we do not have to wrap the result in another Actually and can simply letthe constructor do the job for us. But �rst we need to• Add an abstract method next in Actually that takes in an Immutator<..> as theparameter. The Immutator object transforms the value of type T into a value of typeActually , for some type R . In other words, it accepts T and returns Actually .• Implement next in Success such that it returns Actually (instead ofActually<actually> ) unless there is an exception. If there is an exception,then it returns a Failure .12345678jshell> sqrPlusOneA.invoke(2)$.. ==> 5jshell> sqrPlusOneB.invoke(2)$.. ==> 5jshell> plusOneSqrA.invoke(2)$.. ==> 9jshell> plusOneSqrB.invoke(2)$.. ==> 9123$ javac -Xlint:rawtypes Test4.java$ java Test4$ java -jar ~cs2030s∕bin∕checkstyle.jar -c ~cs2030s∕bin∕cs2030_checks.xml*.java• Implement next in Failure such that it propagates the exception contained as anew Failure .The use of constructor allows us to chain easily. We �rst create an Actually using aconstructor and then simply chain using next . At the end, we may unwrap if we believethere will not be an error or we use except / unless if think there may be an error thatwe want to restart with fresh value.You can test your code by running the Test5.java provided. The following should compilewithout errors or warnings. Make sure your code follows the CS2030S Java style.Using AAccttuuaallllyyNow 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 successfuland return a null otherwise. It is up to the caller to check and make sure that the returnvalue is not null before using it, to prevent receiving a run-time NullPointerException .In some cases, it may also be simpler (although still not good) to simply enclose theNullPointerException in a try-catch so that there is no need to check for any null value.One example of this is the Map<k,v> implements in Java. The method Map::get returnsnull if the key that you are looking for does not exist. This may cause confusion if we areactually mapping some key to null . In any case, if the result is null , then using this forsubsequent method invocation will result in NullPointerException .We have given you a program Lab5.java that uses multiple layers of Map to storeinformation 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 in12345678jshell> make.invoke(0).next(inc).next(inc).next(half)$.. ==> <1>jshell> make.invoke(0).next(inc).next(half).next(inc)$.. ==> [java.lang.Exception] odd numberjshell> make.invoke(0).next(inc).next(inc).next(half).except(zero)$.. ==> 1jshell> make.invoke(0).next(inc).next(half).next(inc).except(zero)$.. ==> 0123$ javac -Xlint:rawtypes Test5.java$ java Test5$ java -jar ~cs2030s∕bin∕checkstyle.jar -c ~cs2030s∕bin∕cs2030_checks.xml*.javathis method.Our new Actually class provides a good abstraction for the chained operationinvolving the return value from Map::get since if there is an error, our Actually willsimply propagate the error. As such, there is no need to check if the return value is nullor to put the code inside try-catch block. If the return value is indeed null , then we willsimply propagate the exception until the end.Your �nal task is to modify getGrade so that it uses Actually instead:• Declare and initialize two Constant instances using anonymous classes.a��One to wrap the db in Actually .b��One to produce the string “No such entry” .• Declare and initialize three Immutator instances using anonymous classes.a��One for the map from get(student) .b��One for the map from get(module) .c��One 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 asingle return statement. In other words, your getGrade should consists of six Javastatements: two to create two Constant , three to create three Immutator , and onereturn statement. The skeleton has been given.• Your code should not have any more conditional statements or references to null orusing any try-catch.FilesA set of empty �les have been given to you. You should only edit these �les. You must notadd any additional �les. Your folder structure should look like the following: 1 2 3 4 5 6 7 8 9101112\— cs2030s| \— fp| \— Action.java| +— Actionable.java| +— Actually.java| +— Constant.java| +— Immutator.java| +— Immutatorable.java| +— Transformer.java+— CS2030STest.java+— Lab5.hThe �les Test1.java , Test2.java , etc., as well as CS2030STest.java and Lab5.h , areprovided for testing. You can edit them to add your test cases, but they will not besubmitted. You must also submit the �le Lab5.h (in reality, this is a bash �le butCodeCrunch 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 GuideYou should make sure that your code follows the given Java style guide. You are notrequired to correct the styling error for the Test1.java , Test2.java , etc., as well asCS2030STest.java .GradingThis lab is worth 12 marks and contributes 3% to your �nal grade. The marking scheme isas follows:• Style: 2 marks• Everything Else: 10 marksWe will deduct 1 mark for each unnecessary use of @SuppressWarnings and each raw type.@SuppressWarnings should be used appropriately and not abused to remove compilationwarnings. 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.WARNING ��We would like to remind you of the following:• We will take the latest submission only. If you have submitted your work and you13141516171819+— Lab5.java+— Lab5.pdf+— Test1.java+— Test2.java+— Test3.java+— Test4.java+— Test5.javaresubmit the same work after the deadline, late submission penalty will apply.• We will no longer accept submission two days after the deadline.• This also applies to all previous labs to ease grading of really late submission andlet the TA focus on their assessments.���In fact, java.lang is automatically imported by JVM.���Can be implemented using this but not actually this.���The more proper term is function composition where (f ∘ g)(x) is de�ned as eitherf(g(x)) or g(f(x)) depending on mathematicians/programmers you are talking to.</k,v></actually</t,p></r,p></t,r></t,p></t,r></r,n></p,n></r,p></r,n></p,n></r,p></r,p>