Confusing behaviour of overloading - java

I am experiencing a behaviour that I do not understand related to this code snippet. More precisely, I was expecting the call of getUniqueCost method for the case in which the operator is of type Projection (that is, when n.isProjection() is true) to be calling the method having as signature private double getUniqueCost(final Projection p) instead of that having signature private double getUniqueCost(final Node p).
Note that Projection is a subclass of Node.
Here the code for the two aforementioned methods:
private double getUniqueCost(final Node n){
if(n.isScan())
return getUniqueCost(estimateCardinality(n));
if(n.isJoin())
return getUniqueCost((NJoin) n);
if(n.isUnion())
return getUniqueCost((Union) n);
if(n.isMaterialization())
return getUniqueCost(n.getChildren().iterator().next());
if(n.isProjection()){
return getUniqueCost(child.isJoin() ?
n.getChildren().iterator().next() : ((Projection) n));
}
throw new IllegalArgumentException("Unknown node type: " + n.getOperator());
}
private double getUniqueCost(final Projection p){
return getUniqueCost(estimateCardinality(p)) +
getUniqueCost(p.getChildren().iterator().next());
}
The only way to actually manage to call the second method was to modify the first method as follows (the omitted code is the same as before):
private double getUniqueCost(final Node n){
[...]
if(n.isProjection()){
final Node child = n.getChildren().iterator().next();
if(child.isJoin()){
return getUniqueCost(child);
}
final Projection proj = (Projection) n;
return getUniqueCost(proj);
}
throw new IllegalArgumentException("Unknown node type: " + n.getOperator());
}
Given that the cast is executed before actually calling the method (that is, call by value semantics, where the parameters are evaluated before evaluating the method itself), I was expecting it to be sufficient to call the most specific method (the one accepting a parameter of type Projection).
It has been a while since I had a look at the type system of Java, my suspect is that the whole expression child.isJoin() ? n.getChildren().iterator().next() : ((Projection) n) is typed as Node, due to the left part those type is indeed Node.
Does anybody can confirm it? If no, do you have a better understanding of what's going on here?
In addition, is there a way to have a more compact (elegant?) way of writing the second version of the code?

The type of your ternary conditional expression - child.isJoin() ? n.getChildren().iterator().next() : ((Projection) n) - is a type that both n.getChildren().iterator().next() and ((Projection) n) can be assigned to. Therefore, if one of them is Node and the other Projection, assuming Projection is a sub-class of Node, the type of the expression is Node.
Your second snippet can be shortened a bit :
if(child.isJoin()){
return getUniqueCost(child);
} else {
return getUniqueCost((Projection) n);
}
Casting n to Projection is enough the get the overloaded getUniqueCost(final Projection p) method called. You don't need an intermediate variable.

Related

Recursive method for binary tree node couting

Ok, so i have to create a recursive method for counting the nodes in a tree, and i did this (variable names are in portuguese, sorry):
public int contaNos(Arvbin r) {
Integer cardinalidade = 0;
contaNosPrivado(r, cardinalidade);
return cardinalidade;
}
private void contaNosPrivado(Arvbin r, Integer cardinalidade) {
if (r==null) {
return;
}
cardinalidade=cardinalidade+1;
contaNosPrivado(r.esq, cardinalidade);
contaNosPrivado(r.dir, cardinalidade);
return;
}
Arvbin is the binary tree, esq and dir are the left and right references to the tree's branches.
I thought this would work, but for some reason when i try to run it, it returns 0. I've usen a little bit of debugging and i think the issue is that when the methods finish and come back to the original non-recursive one, the cardinalidade variable is set to 0. I'm not sure if it's because autoboxing is messing with my Integer and turning it into an int, and then when i call the method it passes a copy of the value instead of the reference to the existing object, and i don't know how to fix it. If anyone could help, i'd greatly appreciate it
The problem is that wrapper classes are immutable in Java. cardinalidade is just a parameter of contaNosPrivado here and, unfortunately, cannot act as an argument like other object type parameters can, i.e. this local reference cannot change inner fields of the object that initial reference refers. Any change to it affects it only the way it affects any primitive local variable.
What exactly happens inside your contaNosPrivado:
On invocation, it is indeed supplied a reference to an Integer object. This reference is assigned to a local variable named
cardinalidade.
In this line:
cardinalidade=cardinalidade+1;
this object is first unboxed to a primitive int variable, this variable is incremented afterwards, and
finally the result is reboxed into a new Integer object which is
then assigned to cardinalidade. There is no way to 'increment'
original object, even if you use the increment operator:
cardinalidade++;
Any further processing applies to the newly created Integer object and doesn't affect the reference passed to contaNosPrivado.
To achieve your goals, use something like this instead:
static int contaNosPrivado(Arvbin r) {
if (r == null)
return 1;
else
return contaNosPrivado(r.esc) + contaNosPrivado(r.dir);
}
As #John McClane has pointed out, you can't pass an Integer argument by reference, only by value.
But there's also no need for a private helper method, you can just simplify it all to a single method:
public int countLeaves( BinaryTreeNode n )
{
return n == null? 0 : ( countLeaves( n.rightLeaf ) + countLeaves( n.leftLeaf ) );
}
Or (excuse my poor Portugese):
public int contaNos( Arvbin r )
{
return r == null? 0 : ( contaNos( r.esq ) + contaNos( r.dir ) );
}

Method reference and Lambda expression

I´m currently reading through someone else´s code and he has the following two methods:
public static double fac(double d) {
return d <= 0 ? 1 : d * fac(d - 1);
}
public static DoubleUnaryOperator getfun() {
return LamdaTests::fac; // LamdaTests is the classname of this class
}
First of all, i´m currently trying to understand lambda expressions/method references.
I have 2 questions:
1) What does the getFun() method exactly do? It should call the fac(double d) method in this class LambdaTests right? But with which argument and how can the return value be a DoubleUnaryOperator, shouldn´t "LamdaTests:fac" return a double?
2) What would be the equivalent Lamda expression for Lamdatests::fac in this case?
Edit: As far as i know
return LamdaTests::fac;
should be equal to
return x -> fac(x);
But i just dont understand where it gets the argument x from.
getFun doesn't call anything. It just returns a reference to the fac function. You need to call the returned function still to get a result. getFac isn't very useful here, so that may be what's confusing things. In reality, you would just use LamdaTests::fac directly, unless that method was private.
For the latter question, think of it this way:
x -> fac(x)
is a function that takes a double and returns a double. What is fac? It's the same thing: a function that takes a double and returns a double. The argument is just implicit here.

Recursive Descent Parser - Adding Unitialized Variables

So, I have a recursive descent parser that analyzes a mathematical expression in infix. The expression is tokenized, parsed with the aforementioned parser, which generates an AST on the fly (with nodes for each type of expression) and evaluates the final value. I am handling all of these values as doubles; so, I use this parser like so:
Parser parser = new Parser();
try {
ExpressionNode expression = parser.parse("5 + 4*cos(pi)");
System.out.println("The value of the expression is "
+ expression.getValue());
} catch (ParserException | EvaluationException e) {
System.out.println(e.getMessage());
}
}
With Exceptions I defined myself.
The line expression.getValue() returns a double, and the way my parser works is that every expression node returns a double, so each branch is evaluated bottom up, until it finally ends up at one double answer.
The thing is, I want to handle unitialized variables in my expressions, like so if I wanted to parse 5 + x (where x is not initialized prior) the expression's value would return 5 + x.
Would I have to change my expression node's getValue() return type to a String? I feel like that would complicate and bloat the program, and there must be a better way to accomplish this. Does anyone have any experience with this type of thing?
I know the description of my parser might have been a little vague, so this is where I learned how to implement most of it.
I assume in your expression tree you have classes defined for operators and constants. You will need to define a new class for variables.
You will then need to add a method like getAllVariables which can return all variables below any point in the tree.
The I suggest you change getValue to accept a Map<String, Double> to provide values for any variables at evaluation time. This will need to be ignored by all nodes other than variables which will return their own value from the map. If they don't find a mapping for themselves as a key they should throw an EvaluationException.
Finally if you want to be able to print out the expression as a string then that's really a separate method to your getValue. Perhaps getExpressionText. Then each class can override this to return a String representing the expression from that point down with the variables just returning the variable name.
So now once you've parsed your expression you can get all variables, prompt the user for values for them, evaluate the expression for given values (catching the exception if any are undefined) and print it out again.
ExpressionNode expression = Parser.parse("x + 5 * y");
System.out.println(expression.getExpressionText());
System.out.println(expression.getAllVariables());
Map<String, Double> variableValues = new TreeMap<>();
variableValues.put("x", 4);
variableValues.put("y", -2);
System.out.println("Evaluates to " + expression.getValue(variableValues));
I would expect your Variable class to end up looking something like:
public class Variable implements ExpressionNode {
private final String name;
public double getValue(Map<String, Double> variableValues) {
if (variableValues.containsKey(name)) {
return variableValues.get(name);
} else {
throw new EvaluationException(name + " is undefined");
}
}
public String getExpressionText() {
return name;
}
public List<String> getAllVariables() {
return Arrays.asList(name);
}
}
Another common operation you might want to perform on an expression tree is to simplify it. That essentially means to evaluate to a constant anything that can be evaluated. In my view the best way to do this is to return a new simplified tree rather than changing the current tree. So I recommend adding a new method to ExpressionNode:
public ExpressionNode simplify();
For variables and constants this would just return this. For operators it needs to do something more complicated. Something like:
class Operator implements ExpressionNode {
public ExpressionNode simplify() {
if (getAllVariables().isEmpty()) {
return new Constant(getValue());
} else {
Operator simplified = new Operator(operation);
for (ExpressionNode operand: operands) {
simplified.addOperand(operand.simplify());
}
return simplified;
}
}
Hopefully you see what that does. If the operation can be completely evaluated then it's converted to a constant. Otherwise it remains an operation but each of its operands is simplified in turn.
So now if you want to simplify an expression you can do:
System.out.println(Parser.parse("7 * 2 + x * 3").simplify().getExpressionText());
Which will return "14 + x * 3".
If you then want to get even more sophisticated you can build awareness of association and distribution into your operators and change simplify so that it reorganises the tree to group variables. But I believe that's a bit beyond the scope of this question!

Assign value to method invocation

For later reference:
Operations o = new Operations(); //class containing the operation methods
HashMap<String, Method> ops = new HashMap<String, Method>();
I'm working on a program that will parse a mathematical expression input via console or eventually maybe a GUI.
Currently, I have a class called "Operations" which has various basic math functions (more will be added later, just testing right now). In another class, I have a method which calculates the result by taking an operand, the successive operator, and another operand, and invoking a method to evaluate the expression. It stores the info necessary to the calculation in:
double numOne = //...
char operator = //...
double numTwo = //...
double result = //...
Now I don't want to have a long switch/case statement or if statement saying:
if (operator.equals("+")) //I know .equals() doesn't use chars; it's an example
o.add(numOne, numTwo);
else if (operator.equals("-"))
o.subtract(numOne, numTwo);
on and on for every operation. That's why I tried creating a HashMap<String, Method> to store the operator (String) and the method which should be called. Basically, in the current class' constructor, I put:
ops.put("+", o.getClass().getMethod("add", double.class, double.class));
ops.put("-", o.getClass().getMethod("subtract", double.class, double.class));
//etc. Which in and of itself is also pretty lengthy
Now to once the method is identified via operator, I need another method to return a Method to call.
private Method getMethodFromKey(HashMap<String, Method> map, char op) {
Method method = null;
for (Map.Entry<String, Method> e: map.entrySet()) {
if (e.getKey().equals(op))
method = e.getValue();
}
return method;
}
Finally, once I have the correct method, I can call it with:
getMethodFromKey(ops, operator).invoke(o, numOne, numTwo);
That all works great. My problem is, the method(s) I am/will be invoking are getter methods; they return a double. Example:
public double add(double one, double two) {
double answer = 0;
answer = one + two;
return answer;
}
I guess this is all just a long-winded way of asking is there a way to assign the returned value of an innvoked method? Something like:
result = getMethodFromKey(ops, operator).invoke(o, numOne, numTwo); //This doesn't work :(
Any help is appreciated. Additionally, if my aproach is completely wrong, I would appreciate a bump in the right direction.
DISCLAIMER: I'm relatively inexperienced at Java and known for overcomplicating things, so please point out any grievous flaws in my design. :)
invoke() returns Object and since Java does not know how to assign an Object to a double this won't compile. invoke starts by boxing the double from the method into a Double. You have to cast it now from Object to Double (and could then call .doubleValue() but that's done automatically) for that to work.
I'm [...] known for overcomplicating things, so please point out any grievous flaws in my design. :)
Using reflection instead of an interface. A Method is a function object. But it's not type-safe to use. An interface can do the same without those problems.
interface Operation {
double evaluate(double a, double b);
}
Then put objects that implement the interface in your map:
ops.put("+", new Operation() {
public double evaluate(double a, double b) {
return a+b;
});
and you can do
double result = getMethodFromKey(ops, operator).evaluate(numOne, numTwo);
The need to cast is gone.
If you're sure that all of your operations are going to be on a single class (no extensibility), then you should consider using an enum instead. You can add an instance field to the enum to represent the character command corresponding to the operation and then have an abstract evaluate method that's implemented by each enum value.
If invoke() is returning an Object that you know is a double, you can cast it like so:
result = (Double) getMethodFromKey(ops, operator).invoke(o, numOne, numTwo);
Since double is a primitive, which is not of type Object, you need to cast it to a Double, and through unboxing, we get a double.

Merging methods (Binary Search Tree)

I'm working on writing a BST (Binary Search Tree) and there's an example in a book I'm reading that gives this code
public int height() {
return height(root);
}
private int height(BinaryNode<E> node) {
if (node == null) {
return 0;
} else {
int leftHeight = height(node.left);
int rightHeight = height(node.right);
if (leftHeight < rightHeight) {
return 1 + rightHeight;
} else {
return 1 + leftHeight;
}
}
}
but there's no explanatory information about why there's two separate height methods.
Therefore I'm asking you guys if it's possible to merge these two methods in to one height method. Is it possible, if not. Why not?
Appreciative for any help possible,
Bob.
It's an example of method overloading.
There are two methods with the same name, that differs by the number of type of arguments passed.
The first method has no parameter, the second one has one parameter of type BinaryNode<E>.
When the first method is called, it calls the second one passing to it the root variable (which I assume is of type BinaryNode<E>).
The first one is also public, so you can call it from other classes, the second one is private and is callable only from the class where it is defined.
Assuming that the methods you provided are part of the tree class, then I don't see how you can merge them. The first is a public method, which expects no argument, and the second is a helper recursive method that checks the height of a given node. The first one uses the second: it invokes the helper method on the root itself. The second method shouldn't be visible from outside, so it's private.
If the height method was implemented on the Node level, then it could be done in a single recursive method with no arguments.
Notice that the int height() method is public. This is the one that will be called from outside your class. It must decide the height of the tree. It will do this by calling the other one.
See also that the int height(BinaryNode<E> node) is private because it is used only by the public int height() method to determine the height of any subtree.

Categories