ASM Merge two value objects on Interpreter - java

I continue to research method emulation and getting actual value when passing instruction ILOAD. After Holger's help with Interpreter
and after adding new operations with local variable in main() method I stucked with merge(V a, V b) method, which must be overriden when extending Interpreter.
#Override
public LocalValue merge(LocalValue valueA, LocalValue valueB) {
if (Objects.equals(valueA, valueB)) return valueA;
else return new LocalValue(basicInterpreter.merge(valueA.type, valueB.type), null);
}
But it seems this not correctly written. I can try different logic vars what to return but without understanding, in what cases values can merge, I can't find that. There is no useful info I tried to find in javadocs and asm-4 tutorial. So, what I need to return, when:
- One value is null, and other is not
- Both values are not null, same type, but different objects (such as 0 and 5)
- Both values are not null, different types
basicInterpreter:
private BasicInterpreter basicInterpreter = new BasicInterpreter();
LocalValue:
public static class LocalValue implements Value {
Object value;
BasicValue type;
public LocalValue(BasicValue type, Object value) {
this.value = value;
this.type = type;
}
#Override public int getSize() {return type.getSize();}
#Override public String toString() {return value == null ? "null" : value.toString();}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof LocalValue)) return false;
LocalValue otherV = (LocalValue) obj;
return Objects.equals(otherV.type, type) && Objects.equals(otherV.value, value);
}
}

Values need to be merged when an instruction can be reached through different code paths, e.g when you have conditionals, loops or exception handlers.
So when the value is the same, regardless of which code path has been taken, you can keep it, otherwise the value is not a predictable constant anymore. So in my code, where null has been used to denote unknown values, it always returns null when the values differ.
So when you have code like
void foo(int arg) {
int i = 1;
int j = arg%2==0? i: arg;
}
The values for arg, i, and the value on the operand stack get merged right before the assignment to j. arg does already have an unpredictable value, i has the value 1 in each code path, but the value on the operand stack, to be assigned to j has different values, 1 or “unknown”, depending on which code path has been taken.
You may decide to maintain a set of possible value, if you like, but when one of the possible values is “unknown”, the result of the merging cold be any value, hence, is “unknown”.

Related

Assigning Variable Types to numbers java

I'm trying to figure out how to assign multiple variables to int type but I'm not sure how to assign it to them. Also, I'm having difficulty understanding how you can use a boolean with this restriction. I was thinking about putting them in an array but I'm not sure if there is an easier approach to the problem. Any help is much appreciated!
Instructions for Attraction.java
Write a Java program Attraction.java that has the following characteristics.
extends Place
New attributes: type (int) price (double)
New Methods: public Attraction(String name, String desc, double latitude, double longitude, double price, int type) where for type values:
0 is an amusement park
1 is an aquarium
2 is a zoo
public double getPrice() -- returns current price
public int getType() -- returns type
public boolean hasAnimals() -- returns true if type contains "zoo" or "aquarium"
Your hasAnimals method needs to return a boolean value i.e. true or false based on the value of the type variable.
You're .. kind of on the right track, but you're not honoring the requirements of the method. It shouldn't print anything, and it shouldn't return type because type is an int and not the boolean that is required.
public boolean hasAnimals() {
if(type == 1) {
return true; // aquarium has animals
} else if (type == 2) {
return true; // zoo has animals
} else {
return false;
}
}
Think carefully about what a method is called, and what it should do. This method is just a way to answer a yes/no question.

null detection for double method

I'm employing a private lib. One of the objects has a method that delivers either a double or a null.
How could I perform:
if (object.method != null) {
// do some numeric operations with the returned value
}
Additional details:
library = org.apache.commons.collections4.map
class = LRUmap
method = get
My code is:
public class ExampleNode extends GeneralNode {
private LRUMap<Integer, Double> cache;
public ExampleNode() {
this.setCache(new LRUMap<Integer,Double>(100));
}
public void setCache(LRUMap<Integer, Double> lruMap) {
this.cache = lruMap;
}
public double getDatumCacheDebug(int llave){
return this.cache.get((Object)llave,false);
}
}
And then I call:
//outside ExampleNode
if ( actualNode.getDatumCacheDebug(k) != null ) {
Eclipse Neon3 says: "The operator != is undefined for the argument type(s) double,null."
When the method returns a primitive double (and not the Double class), it can never be null. A primitive value will always have a value of its type (i. e. you can't do double d = null;).
Thus this check would never return true and the compiler does not allow you to do it.
The signature of the library method is:
public V get(Object key,
boolean updateToMRU)
in class LRUMap<K,V>
The returned value is a Double, and therefore could be null, but it is being unboxed to double before the null test:
public double getDatumCacheDebug(int llave){
return this.cache.get((Object)llave,false);
}
I suggest changing the signature of this method to return Double instead of double, so that the information about whether the result was null is preserved and can be tested. Otherwise, it will throw NullPointerException if get returns null.
A working variant of your code will be:
if (object.method != 0) {
// do some numeric operations with the returned value
}
But it is better practice to refactor your method object.method() to return a specific number for your "null cases"- example: a method that is searching for an index in a list - returns the index number if found and -1 if not found or exception is thrown during the search (a null case for the search)

Counting length of string when only an object is passed through?

I'm currently on an 'Intermediate' Book for java but they don't supply the answers to most of the questions (Probably should get a new book).
but in the book they ask this question and say it's pretty easy.
Write a class ShortWordFilter that implements the Filter interface and only accepts words that are less than 5 characters. That is the method accept will return true if the number of characters is less than 5; otherwise, the accept method returns false.
So I implemented it on eclipse and this is the code:
#Override
public boolean accept(Object x) {
return false;
}
I mean, I have absolutely no idea, plus I dont have a tutor to help me so I hope you guys can give me some guidance because the stuff I've tried doesn't work.
Try
#Override
public boolean accept(Object x) {
if (x instanceOf String) and ((String)x).length() < 5)
return true;
else
return false;
}
As a variation from nullPointer's method (even if I think its one is better) :
#Override
public boolean accept(Object x) {
if (x == null) {
return false;
}
return (x.toString().length() < 5);
}
This one accepts any object, and converts it to string. As a special case, it returns false for a null object.
Use the Object.toString method (dangerous if the parameter can be null)
Cast the Object to a String (dangerous as above, and if you are not guaranteed an instance of a String as a parameter)
If the Filter interface is generic, you can parametize it
Once the Object is a String, you can use the length method (the API for String here is your friend).
Are you sure the type of your x parameter has to be Object? Can you think of any type that represents a sequence of characters?
If your variable has to be of typeObject, then you will need to cast it to that aforementioned type (hint: String) in order to treat it like a sequence of characters.
Now that you have there's a the length() method if you want to find the length of a String.
You can then use > or >= or < or <= for comparison.
#Override
public boolean accept(Object x) {
// cast x to "sequence of characters" type
// check the length of the sequence of characters and return appropriate true / false as appropriate
}
You would not want to process objects that are null as well as objects that are not Strings so you can do
public boolean accept(Object obj) {
if (null == obj) {
return false;
}
if (! (obj instanceof String)) {
return false;
}
String str = (String)obj;
return (str.length() < 5);
}

Integer Enum and Unboxing

public class Document{
private Integer status;
// get()/set()
}
Then an enum:
public enum DocumentStatusEnum {
ACTIVE_DOCUMENT(2060),CANCELLED_DOCUMENT(2061),DRAFT_DOCUMENT(2062),PROCESSED_DOCUMENT(2063);
private final Integer value;
private DocumentStatusEnum(Integer value){
this.value = value;
}
public Integer getValue(){
return value;
}
}
In a method I'm using the above method as below:
Document d = new Document();
d.setStatus(2063);
if (d.getStatus() == DocumentStatusEnum.PROCESSED_DOCUMENT.getValue()){
{
// print true;
}
else{
// print false;
}
I get true here. Looks alright. In the same method, After couple of lines, I do this:
d.setStatus(2060)
if (d.getStatus() == DocumentStatusEnum.ACTIVE_DOCUMENT.getValue()){
// print true
}
else{
// print false
}
I get a false. I researched and found something about caching and boxing features in Java. I converted the enum definition as this:
public enum DocumentStatusEnum {
ACTIVE_DOCUMENT(2060),CANCELLED_DOCUMENT(2061),DRAFT_DOCUMENT(2062),PROCESSED_DOCUMENT(2063);
private final int value;
private DocumentStatusEnum(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
Now, no issues. I get true in both cases.
Question is why this happening? I feel this behaviour is extremely unstable. It's a large application I'm dealing with and I'm using Integer == Integer comparison every where. Am I safe here?
Integer extends Object and therefore == is defined as reference equality, not value equality.
When comparing Integer with int, the Integer will be unboxed to an int, and the two operands will be compared for value equality. (Unless the Integer value is null, in which case NullPointerException will be thrown instead.) But Integer == Integer is never safe.
That said, because by default the runtime pre-allocates Integer instances for small integers (-128 through 127, according to the OpenJDK source), you can often get Integer == Integer to work for small values. But that behavior does not hold for larger values, and it is never required to hold. So you should never assume that two instances of Integer (or String, or any Object) will compare equal using ==, unless you are explicitly looking for reference equality.
You should use int instead of Integer, unless you need to handle null values.
There are indeed issues with comparing Integer objects. For example, the following will evaluate to false:
boolean test = (new Integer(1) == new Integer(1));
System.out.println(test); // "false"
These are just objects like any other. The == operator, when used with objects, only evaluates to true if they are the exact same Java object (as opposed to the equals() method, which can be overridden to compare the internals).

In Java, How do I return a String or a double depending on the circumstance of the method? Is it possible?

For example, I have a method that looks through a string for data separated by a specified deliminator, but some items might be a names, and other items might be numbers.
If a user calls my method to return item number X from the deliminated list, i want it to return a string if item X is a name, or a double if item X is a number.
For example, objectName.get(5); would get the 5th item in the deliminated list.
Would I have to use some type of overloading for this?
Or would I have to instead do something like objectName.getDouble(5); and objectName.getString(5); based on the fact that the user knows what item 5 is?
But what if the user doesn't know what item 5 is? He just needs a String or a Double depending on what it happens to be.
Here's one way to do this:
public Object get() {
if (blueMoon) {
return new Double(42.0);
} else {
return "fred";
}
}
Note that this will return a Double wrapper rather than a double.
I don't think this is a good idea though, since the caller now has to test the type of the returned value and do a typecast to do something with it.
For the record, Java does not allow a method to return a String or double because these types do not have a common supertype in the Java type system.
For this sort of thing, I prefer to use something akin to the Maybe/Option pattern from the functional programming camp. You end up with an interface like:
public abstract class DoubleOrString
{
// Constraint isDouble() xor isString()
public boolean isDouble();
public boolean isString();
//Must throw iff !isString()
public String getString();
//Must throw iff !ifDouble()
public Double getDouble();
public static DoubleOrString wrap(final double wrapMe)
{
return new DoubleOrString()
{
public boolean isDouble() {return true;}
public boolean isString() {return false;}
public Double getDouble() {return wrapMe;}
public String getString() {throw new RuntimeException();}
};
}
//same for wrap(String)
}
This forces the issue for clients, in that there is always a sanity check that there was indeed a double or String at the appropriate time. In your case, I'd make just one get() method, so when the client (thinks they) knows what the type is, the call is
objectName.get(5).getString();
and in your get(int) method, rather than returning a String or a double, the return statement looks like
DoubleOrString.wrap(theThingToReturn)
It's a little extra work up front, but it has paid of for me several times in the past.
Here's how you'd use it to build one (warning - this hasn't been near a compiler)
public static DoubleOrString parseADoubleOrString(String input) {
try {
return DoubleOrString.wrap(Integer.parseInt(input))
} catch (NumberFormatException nfe) {
return DoubleOrString.wrap(input);
}
}
and here's what the client looks like
String input = //get the input from the user somehow
DoubleOrString parsed = parseADoubleOrString(input);
if (parsed.isDouble())
aFunctionThatTakesADouble(parsed.getDouble());
else
aFunctionThatTakesAString(parsed.getString());
If you need to do this then there is problem with your design. Since the original datasource is String you have to accept that all returned values will be string and leave it to the client to check whether the result can be converted to a number.
If you want to save the client from doing the check, you can provide him with a minimal API which may look something like:
public class ValueExtractor {
public ValueExtractor(String delimitedText) {
// ...
}
/**
* Determines whether there is a next element
* to be returned
*/
public boolean next() {
// ...
}
public String get() {
// ...
}
/**
* Returns the value as a Double if possible
* null otherwise.
*/
public Double getPossibleDouble() {
// ...
}
}
The Java language does not expose an overload on the return type of a method. (As Thilo pointed out, this is a restriction of the Java language and not the JVM/bytecode.)
Generally this type of thing does not fit well into the Java type system. One could imagine returning an Either<String,Double> type (a more restricted return type than Object as suggested by Stephen C and a more general type than DoubleOrString as pointed out by B. Bear), but the general effort required to use such a construct in Java generally results in simply having multiple methods, e.g. getString(...) and getDouble(...).

Categories