CS2030S Lab 4 Probably SOLVED

$30.00

Category:

Description

5/5 - (4 votes)

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 .