OOP Class Notes for 11/05/13
Comments on OOP Midterm Projects (Some issues you may want to consider fixing...)
try{ if (myCppFiles!=null)myCppFiles.closeFiles();System.out.println("CLOSING FILE: "+myFileDep.getFilePath());}
catch(Exception e){System.out.println("closing failed");}
}
- Catches the exception, prints an error message then continues execution. The exception is ignored, and probably causes problems down the line.
- Do something meaningful with the error, don't just catch
it and ignore it.
- Use
System.err
for error output rather
than System.out
- You are not payed by the line, yet, but use line breaks
and indentation to improve code readability. Adding line
breaks would also reveal that the code after the if
condition should be enclosed by
{ }
.
GNode leftSide = // ...
if (leftSide.getName() == "SelectionExpression") {
// ...
}
- You can only use '==' on internal (intern) strings, so this is pretty brittle. Note that Java string literals are guaranteed to be intern-ed. We do not know about names in GNode (they happen to be provided by string literals as well).
- Xtc already provides a method for this case. Use Node.hasName(String) to check the name of a node.
public void visitForStatement(GNode n) {
interior(n);
visit(n);
}
public void visitExpressionStatement(GNode n) {
interior(n);
visit(n);
}
public void visitForStatement(GNode n) {
interior(n);
visit(n);
}
public void visitConditionalStatement(GNode n) {
interior(n);
visit(n);
}
public void visitReturnStatement(GNode n) {
interior(n);
visit(n);
}
// ... and then later
if (current.equals("ExpressionStatement")) {
contents.add(new ExpressionStatement(n.getNode(i)));
}
else if (current.equals("ForStatement")) {
contents.add(new ForStatement(n.getNode(i)));
}
else if (current.equals("WhileStatement")) {
contents.add(new WhileStatement(n.getNode(i)));
}
else if (current.equals("FieldDeclaration")) {
contents.add(new FieldDeclaration(n.getNode(i)));
}
else if (current.equals("ConditionalStatement")) {
contents.add(new ConditionalStatement(n.getNode(i)));
}
else if (current.equals("ConstructorDeclaration")) {
contents.add(new ConstructorDeclaration(n.getNode(i)));
}
else if (current.equals("MethodDeclaration")) {
methods.add(new MethodDeclaration(n.getNode(i)));
}
else if (current.equals("ReturnStatement")) {
contents.add(new ReturnStatement(n.getNode(i)));
}
- A lot of repetitive code usually means there's a better way to do it.
- In this case, use the visitor pattern as it is intended to be used.
GNode initializedDeclarator = GNode.create("InitializedDeclarator");
initializedDeclarator.add(0, null);
initializedDeclarator.add(1, GNode.create("SimpleDeclarator").add(className));
initializedDeclarator.add(2, null);
initializedDeclarator.add(3, null);
initializedDeclarator.add(4, null);
- The index is completely unnecessary in this case (and a likely cause of future bugs), just call add(Object), which adds a child to the end.
cppFm.write("\n\t\ttemplate<>\n"+
"\t\tClass __Array<"+
myTree.getCppPakageName()+myTree.myClassnameString+">::__class() {\n"+
"\t\t\tstatic Class k = new __Class(__rt::stringify(\"[L"+
myInfo.getPackageName()+"."+myTree.myClassnameString+"\"),\n"+
"\t\t\t\t\t\t\t\t\t__Array<"+myTree.mySuperClass.getCppPakageName()+
myTree.mySuperClass.myClassnameString+">::__class(),\n"+
"\t\t\t\t\t\t\t\t\t"+myTree.getCppPakageName()+"__"+myTree.myClassnameString+"::__class());\n"+
"\t\t\treturn k;\n"+
"\t\t}\n\n");
- Hacking together a string like this is likely slow. Java's
StringBuilder
helps with incremental string creation and is more efficient. Do NOT use StringBuffer
, which is synchronized.
- Even better: Using xtc's
Printer
, once again, would be much easier and a better fit to the problem (formatting source code). Simply have the printer write to a StringWriter
...
for (int i = 0; i < nodeSize; i++) {
try {
System.out.println("part " + i + ": " + n.getNode(i));
}
catch (ClassCastException e) {
System.out.println("part " + i + ": " + n.getString(i));
}
}
- Exception handling is an expensive mechanism and should be avoided
in regular code if possible.
- In this case, use
get(int)
to retrieve the i-th child and
then conditionally branch on its dynamic type. No need to use
execeptions here.
Java Reflection
- Java Reflection
- Reflection is a language facility that lets you get information about and manipulate objects at runtime.
- It is useful for writing programs that deal with objects in a general way, such as programmer tools.
- JUnit and xtc's Visitor are two examples.
- Compared to direct invocation, reflection has poor performance.
- java.lang.reflect
- The
Method
class
Method
describes a method but isn't a method itself.
Method
's invoke function can be used to invoke the method described by an instance of Method
.
- The arguments to the invoke function is an object on which to invoke the method, and the arguments to the method
myMethod.invoke(myObj, args);
Reflection allows you to modify access-level modifiers (for example: private,protected).
myMethod.setAccessible(true);
This can be abused, so we have java.lang.SecurityManager
to block such things
Visitor Dispatch
- Contract of method
dispatch
- Determine the closest matching visit method
- Invoke it on the visited node
- Return the result
- If the node is null, return null
- Note that xtc's caching is not threadsafe
- Stepping through
dispatch
- Uses a linked hashmap to cache methods already found.
- The CacheKey uses the hashCode and equals methods of the visitor and the node.
- First check the cache for the method.
- If not found in the cache, get the method with findMethod(), and cache the result.
- Invoke the method on "this", with the GNode as the parameter.
- Return the result
- Stepping through
findMethod
- Get an instance of the
Class
object for the
visitor
- If the visited node
n
is a generic node, then
- use reflection to see if that
Class
object
has a method named "visit" + n.getName()
- otherwise check whether it has method
named
visit
that takes a GNode
or a Node
.
- The type parameter distinguishes between overloaded methods
- If the visited node
n
is not a generic node,
then
- look whether the
Class
object for the
visitor has a method named visit
that takes an
object of n
's class.
- If it doesn't, then get the interfaces that the class of
n
implements, and look for
the visit
methods accepting objects of these
interface types
- If the methods are still not found, repeat the
search on the superclass of
n
's class
- Throw an exception if no visit method has been found.
- Otherwise, return the method.