Sale!

CS2030 Lab 4: Probably solved

Original price was: $35.00.Current price is: $35.00. $21.00

Category: You will receive a download link of the .ZIP file upon Payment

Description

5/5 - (1 vote)

Probably Just a Value but Maybe Nothing? In this lab, you are given our own generic wrapper class, a Probably . This is a wrapper class that can be used to store a value of any reference type. For now, our Probably is not going to be a very useful abstraction. Not to worry. we will slowly add more functionalities to it. Please read the following explanation on what the class Probably is. The Basics The class Probably stores either (1) none1 or (2) just a value of type T 2 . So, it is probably just some value of type T or it maybe nothing. It: • contains a private final �eld of type T to store the value of reference type T . • provides a private constructor. • provides a class method called none() that returns nothing1 . • provides a class method called just(T value) that returns something that contains just the value2 . • Since there is a possibility that value is equal to null , in such case, we also return nothing. • overrides the equals method from Object to compare if the two values inside are the same. • Two values are the same according to their respective equals method. • overrides the toString method so it returns the string representation of its values, between < and > . The method none and just are called a factory method. A factory method is a method provided by a class for the creation of an instance of the class. Probably is also made to be immutable. Once created, the value of the �eld value cannot be modi�ed! This is achieved by: • making the �eld final . • provide no getter and setter. Relevant part of the code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Probably { private final T value; private static final Probably<?> NONE = new Probably<>(null); private Probably(T value) { this.value = value; } public static Probably none() { @SuppressWarnings(“unchecked”) Probably res = (Probably) NONE; return res; } public static Probably just(T value) { if (value == null) { return none(); } return (Probably) new Probably<>(value); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Probably<?>) { Probably<?> some = (Probably<?>) obj; if (this.value == some.value) { return true; } if (this.value == null || some.value == null) { return false; } return this.value.equals(some.value); } return false; } Shared Object Using a public constructor to create an instance necessitates calling new and allocating a new object on the heap every time. A factory method, on the other hand, allows the �exibility of reusing the same instance. With the availability of the factory methods, Probably should keep the constructor private. Additionally, the factory method as well as having Probably immutable allows us to share a common object safely. The most common object here is the concept of nothing1 . The factory methods return nothing when: • the input argument to just(T value) is null , or • the factory method none() is invoked In both cases, we return a static instance called NONE . The sequence below shows how we can use a Probably using the methods above. Testing Probably The following sample run shows the current capability of Probably . You should also test using your own test cases to further understand Probably . 38 39 40 41 42 43 44 45 46 @Override public String toString() { if (this.value == null) { return “<>”; } else { return “<” + this.value.toString() + “>”; } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 jshell> Probably.just(4) $.. ==> <4> jshell> Probably.just(Probably.just(0)) $.. ==> <<0>> jshell> Probably.just(Probably.just(Probably.just(“null”))) $.. ==> <<>> jshell> Probably.just(Probably.just(Probably.none())) $.. ==> <<<>>> jshell> Probably.just(Probably.just(null)) $.. ==> <<>> jshell> Probably.just(4).equals(Probably.just(4)) $.. ==> true jshell> Probably.just(4).equals(4) $.. ==> false jshell> Probably.just(Probably.just(0)).equals(Probably.just(0)) $.. ==> false You can check that our Probably is correct by running: There shouldn’t be any compilation warning or error when you compile TestProbably.java and all tests should prints ok . Acting on the Value Because Probably is immutable, it is not useful for us. Once created, we cannot modify the value and we cannot even get the value back. To make the class more useful, we want to be able to act on the object. A simple act can be just printing using System.out.println . One way for us to print the content of the value is to simply add a method called print . However, this is not useful as we have to add a new method for each action that we want Probably to allow. One way to do this is to abstract a computation. Think of higherorder function. Action Interface One way to abstract a computation is to imagine having a class with a single method called call that perform an action that we want. If we receive an instance of this class, we can invoke the method call to perform the action. Thus, we can say that a collection of all classes with a single method called call is an abstraction of an action. You have 2 tasks in this section: 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 jshell> Probably.just(Probably.just(0)).equals(Probably.just(Probably.just(0))) $.. ==> true jshell> Probably.just(“string”) $.. ==> jshell> Probably.just(“string”).equals(Probably.just(4)) $.. ==> false jshell> Probably.just(“string”).equals(Probably.just(“null”)) $.. ==> false jshell> Probably.just(null) $.. ==> <> jshell> Probably.none() $.. ==> <> jshell> Probably.none().equals(Probably.just(null)) $.. ==> true jshell> Probably.none() == Probably.just(null) $.. ==> true 1 2 javac -Xlint:rawtypes TestProbably.java java TestProbably ���Create an interface Action with a single abstract method called call inside the �le Action.java . • The method takes in a single parameter of generic type parameter T 3. • The method does not return any type. ���Create a non-generic class Print that implements Action with the method call that prints the string representation of the input argument into the standard output (i.e., System.out.println ) in the �le Print.java . Testing Action We recommend to �rst design your solution, �gure out the type needed which may or may not involve wildcards. Afterwards, you can test your solution with the following code. You should also test with your own test cases as the given test case may not be complete. You can test the additions to Probably above more comprehensively by running: There shouldn’t be any compilation warning or error when you compile Test1.java and all tests should prints ok . Actionable Interface With the Action interface, we can now perform a custome action. We can do this by adding in the Probably class, a method that can accept an Action . Since this is a good behaviour to have, we want to create an interface representing all classes that can accept an Action . Let’s call this interface as Actionable . You have 2 tasks in this section: ���Create an interface Actionable with a single abstract method called act inside the �le Actionable.java . • The method takes in a single parameter of type Action . This Action should accept a type T . 1 2 3 4 jshell> new Print().call(17) $.. ==> 17 jshell> new Print().call(“string”) $.. ==> string 1 2 javac -Xlint:rawtypes Test1.java java Test1 • The method does not return any type. ���Modify Probably to implement the interface Actionable . You need to implement the method act appropriately: • if the value in Probably is not null , we invoke call with the value. • otherwise, do nothing. Testing Actionable We recommend to �rst design your solution, �gure out the type needed which may or may not involve wildcards. Afterwards, you can test your solution with the following code. You should also test with your own test cases as the given test case may not be complete. You can test the additions to Probably above more comprehensively by running: There shouldn’t be any compilation warning or error when you compile Test2.java and all tests should prints ok . Immutating the Value So now we can create a container called Probably and we can print the content (with appropriate classes implementing Action we may also write the string representation of the value into a �le, etc). This is still not very useful since we cannot mutate the value. In the �rst place, we can not mutate the value because there is no mutator and the �eld value is declared with final . Instead, what we want to do is whenever there is a mutation, we want to create a new instance of this class. This is the essence of an immutable class. Immutator Interface How can we do this. Again, the simplest way is to simply add a method to return a new instance with some changes. However, due to type erasure, type T is treated as if it is of 1 2 3 4 5 6 jshell> Probably.just(4).act(new Print()) $.. ==> 4 jshell> Probably.just(“string”).act(new Print()) $.. ==> string jshell> Probably.none().act(new Print()) $.. ==> 1 2 javac -Xlint:rawtypes Test2.java java Test2 type Object . There is not much we can do with Object . Similar to how we manage to add a custom action to Probably , we want to add a custom mutator to the class. But since the class is immutable, let us calls this concept as immutation instead with the relevant interface called Immutator and Immutatorable . An Immutator is similar to the Action . However, unlike Action that does not return anything, we want Immutator to return something. Consider any method with single parameter. We can write this method signature as: where R is the return type and P is the type of the parameter. By invoking this method, we can change a reference type of some value of type P into another value of type R . This is the basis of our Immutator . Such a powerful concept, not only can we change the value, we can also change the type! You have 2 tasks in this section: ���Create an interface Immutator<R,P> with a single abstract method called invoke inside the �le Immutator.java . • The method takes in a single parameter of generic type parameter P . • The method returns a single value of generic type R . • In other words, Immutator<R,P> is an abstraction of the method R method(P param) . ���Create a generic class Improbable that implements Immutator in the �le Immutator.java with the method invoke that: • takes in a single parameter of type T . • returns a value of type Probably . • the method simply creates a Probably from T regardless of what the type T is (including even when type T is already Probably , but in this case what will be the actual return type?). Testing Immutator We recommend to �rst design your solution, �gure out the type needed which may or may not involve wildcards. Afterwards, you can test your solution with the following code. You should also test with your own test cases as the given test case may not be complete. 1 R method(P param) { .. } You can test your additions to Probably more comprehensively by running: There shouldn’t be any compilation warning or error when you compile Test3.java and all tests should prints ok . Immutatorable Interface Similar to before, we want to add a new method to Probably but we also want to create an interface to represent all classes that can accept an Immutator . Let’s call this method as transform . Remember that Immutator<R,P> has a method called invoke that can produce a value of type R when given a value of type P . Our �nal aim in the end is to transform Probably to Probably . For that, we want an immutator that transform T to R . Note that in this case, T corresponds to P in Immutator<R,P> . You have 2 tasks in this section: ���Create an interface Immutatorable with a single abstract method called transform 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 jshell> class Incr implements Immutator<Integer,Integer> { …> public Integer invoke(Integer t1) { …> return t1 + 1; …> } …> } jshell> class Length implements Immutator<Integer,String> { …> public Integer invoke(String t1) { …> return t1.length(); …> } …> } jshell> new Incr().invoke(4) $.. ==> 5 jshell> new Incr().invoke(new Incr().invoke(4)) $.. ==> 6 jshell> new Length().invoke(“string”) $.. ==> 6 jshell> new Incr().invoke(new Length().invoke(“string”)) $.. ==> 7 jshell> new Improbable<>().invoke(1) $.. ==> <1> jshell> new Improbable().invoke(null) $.. ==> <> jshell> new Improbable().invoke(1).transform(new Incr()) $.. ==> <2> jshell> new Improbable<>().invoke(new Improbable<>().invoke(1)) $.. ==> <<1>> 1 2 javac -Xlint:rawtypes Test3.java java Test3 inside the �le Immutatorable.java . • The method takes in a single parameter of type Immutator . This Immutator should accept a type T and return a type R . • The method returns a single value of type Immutatorable . ���Modify Probably to implement the interface Immutatorable . You need to implement the method transform appropriately: local • if the value in Probably is not null , we invoke invoke with the value and return Probably . • otherwise, return NONE . Testing Immutatorable We recommend to �rst design your solution, �gure out the type needed which may or may not involve wildcards. Afterwards, you can test your solution with the following code. You should also test with your own test cases as the given test case may not be complete. You can test your additions to Probably more comprehensively by running: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 jshell> class Incr implements Immutator<Integer,Integer> { …> public Integer invoke(Integer t1) { …> return t1 + 1; …> } …> } jshell> class Length implements Immutator<Integer,String> { …> public Integer invoke(String t1) { …> return t1.length(); …> } …> } jshell> Probably.just(4).transform(new Incr()) $.. ==> <5> jshell> Probably.just(4).transform(new Incr()).transform(new Incr()) $.. ==> <6> jshell> Probably.just(“string”).transform(new Length()) $.. ==> <6> jshell> Probably.just(“string”).transform(new Length()).transform(new Incr()) $.. ==> <7> jshell> Probably.none().transform(new Incr()) $.. ==> <> jshell> Probably.none().transform(new Length()) $.. ==> <> jshell> Probably.just(null).transform(new Length()).transform(new Incr()) $.. ==> <> 1 javac -Xlint:rawtypes Test4.java There shouldn’t be any compilation warning or error when you compile Test4.java and all tests should prints ok . Question First, recap what we can do. We can create Probably such that we can perform an action on it and mutate the value by creating a new instance each time the value changes. The next step is to ask questions regarding the value. The kind of questions we want to ask is a simple yes/no question. Since at this point we have already created so many interfaces: • Action • Actionable • Immutator • Immutatorable we do not want to create more interface. Instead, note that this is a special case of Immutator . This is simply an Immutator that returns a boolean. Special Immutator You have 2 tasks in this section: ���Create a non-generic class IsModEq that implements this special Immutator that returns boolean values in the �le IsModEq.java . • The class has a public constructor that takes in two positive integer parameters div and check . • The class implements the invoke inherited from Immutator . • The method accepts a single integer parameter val . • The method returns true if the remainder when val is divided by div is equal to check . ���Add the method check in Probably . • The method takes in a single parameter of type of the special Immutator introduced in this section. 2 java Test4 • The method returns a single value of type Probably . • The behaviour of the method can be captured by the table below: value in PPrroobbaabbllyy<> yes/no result null yes ( true ) nothing null no ( false ) nothing non- null yes ( true ) this non- null no ( false ) nothing Testing Question We recommend to �rst design your solution, �gure out the type needed which may or may not involve wildcards. Afterwards, you can test your solution with the following code. You should also test with your own test cases as the given test case may not be complete. You can test your additions to Probably more comprehensively by running: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 jshell> class Incr implements Immutator<Integer,Integer> { ...> public Integer invoke(Integer t1) { ...> return t1 + 1; ...> } ...> } jshell> class Length implements Immutator<Integer,String> { ...> public Integer invoke(String t1) { ...> return t1.length(); ...> } ...> } jshell> Probably.just(17).check(new IsModEq(3,2)) ∕∕ 17 % 3 is equal to 2 $.. ==> <17> jshell> Probably.just(18).check(new IsModEq(3,2)) ∕∕ 18 % 3 is not equal to 2 $.. ==> <> jshell> Probably.just(16).transform(new Incr()).check(new IsModEq(3,2)) ∕∕ 17 % 3 is not equal to 2 $.. ==> <17> jshell> Probably.just("string").transform(new Length()).check(new IsModEq(3,2)) $.. ==> <8> jshell> Probably.just(null).check(new IsModEq(0,2)) $.. ==> <> There shouldn't be any compilation warning or error when you compile Test5.java and all tests should prints ok . It is also good to check that the following code should throw ArithmeticException due to divide by zero. However, note that this is the similar to the last line above. The difference is that in above we have null so the instance of IsModEq is not even used. Applicable In this last section, we want to show some of the power of Probably given our changes to it. Recap that we have at least 4 interfaces. • Action • Actionable • Immutator • Immutatorable It's Probably an Immutator Since Probably can store any reference type T and Immutator is a reference type, we can store Immutator inside Probably . What can we do with this Immutator inside Probably ? We have two cases here: • if there is indeed an Immutator (i.e., it just2 some immutator), then we can use the immutator to mutate the value and the result of this really depends on the value. • if there is no Immutator (i.e., it is nothing1 ), then we simply return nothing. Basically: nothing in, nothing out. You have 2 tasks in this section: 1 2 javac -Xlint:rawtypes Test5.java java Test5 1 Probably.<>just(2030).check(new IsModEq(0,2)) ���Create an interface Applicable with a single abstract method apply inside the �le Applicable.java . • The method takes in a single parameter of type Immutator inside Probably . This Immutator should accept a generic type T and return a generic type R . • The method returns a single value of type Probably . • The method performs the operation described above. ���Modify Probably to implement the interface Applicable . You need to implement the method apply appropriately: • if the value in Probably is not null and the value inside the Probably parameter is not null, we invoke the Immutator with the value and return Probably`. • otherwise, return NONE . Testing Applicable We recommend to �rst design your solution, �gure out the type needed which may or may not involve wildcards. Afterwards, you can test your solution with the following code. You should also test with your own test cases as the given test case may not be complete. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 jshell> class Incr implements Immutator<Integer,Integer> { ...> public Integer invoke(Integer t1) { ...> return t1 + 1; ...> } jshell> class Length implements Immutator<Integer,String> { ...> public Integer invoke(String t1) { ...> return t1.length(); ...> } jshell> Probably<Immutator<Integer,Integer>> justIncr = Probably.just(new Incr()); jshell> Probably<Immutator<Integer,String>> justLength = Probably.just(new Length()); jshell> Probably<Immutator<Integer,Integer>> noIncr = Probably.none(); jshell> Probably<Immutator<Integer,String>> noLength = Probably.none(); jshell> Probably.just(17).apply(justIncr) $.. ==> <18> jshell> Probably.none().apply(justIncr) $.. ==> <> jshell> Probably.just(17).apply(noIncr) $.. ==> <> jshell> Probably.none().apply(noIncr) $.. ==> <> jshell> Probably.just("string").apply(justLength) $.. ==> <6> jshell> Probably.none().apply(justLength) $.. ==> <> You can test your additions to Probably more comprehensively by running: There shouldn't be any compilation warning or error when you compile Test6.java and all tests should prints ok . Hints • This lab is more about the type rather than the code. • You should think about the types that are required by each class and methods. In particular, you should think carefully about the generic type and wildcards if needed. Files A set of empty �les have been given to you. You should only edit these �les. You must not add any additional �les. The �les Test1.java , Test2.java , etc., as well as CS2030STest.java , are provided for testing and they are not to be submitted. You can edit them to add your own test cases. Lastly, the �le Lab4.java is given for you and it should not be modi�ed except for correcting any style problems detected by our style checker. This �le will be the main entry point for our testing on CodeCrunch. Following CS2030S Style Guide You should make sure that your code follows the given Java style guide Grading This lab is worth 16 marks and contributes 4% to your �nal grade. The marking scheme is as follows: • Style: 2 marks 27 28 jshell> Probably.just("string").apply(noLength) $.. ==> <> jshell> Probably.none().apply(noLength) $.. ==> <> 1 2 javac -Xlint:rawtypes Test6.java java Test6 • Correctness: 14 marks We will deduct 1 mark for each abuse or unnecessary use of @SuppressWarnings and for each raw type. Note that the style marks are conditioned on the evidence of efforts in solving Lab 4. ���We will refer to this as none, nothing, or NONE . ���We will refer to this as just, some, or something. ���Here, a single type T includes the possibility that it uses wildcards involving T .