overloading with generic arguments

H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I have a complicated question about overloading with generic arguments.
I could not find a satisfying answer in Angelika Langer’s generics FAQ
(http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html), or in
Sun’s generics tutorial
(http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf). I hope
someone here can read better than me.

I have a class which implements a DAG with labelled edges (actually an
MDD). Recently, I decided I needed non-determinism, so multiple edges
starting from one node can have the same label. This also requires the
possibility of there being more than one root (this will occur due to
certain manipulations of the DAG, such as removing a certain layer,
which can be the root layer).

This is implemented by Nodes which have children and so on. These are
inner classes and interfaces of a wrapping class, which stores the root
and offers manipulations of the DAG. This class used to have the
following simple layout:

public class CompactFunction {

private Node root;

public CompactFunction(Node root){
this.root = root;
}

public CompactFunction(BidiNode root){
this.root = root.getUnidirNode();
}

public CompactFunction removeVariable(int index) {...}

// more functions for manipulating and evaluating the function.

public interface Node {
// methods for all nodes
}

public class NonTerminalNode {
// nodes which have children, with methods to manipulate // the children
}

public class TerminalNode {
// nodes which have no children, but store a value
}
}

BidiNode is a node which also points up to its parents, and is used in
the construction of the DAG. Once it is constructed, I want to remove
the now no longer relevant information of the up-pointers, which is done
in the method getUnidirNode().

Now introducing nondeterminism seems simple: change root into a set of
nodes, alter the constructors and make all methods loop through the set
of nodes, as necessary. The problem is the second point; with the
following declaration:

CompactFunction(Set<BidiNode> roots) {
for (NonTerminalBidiNode root : roots) {
this.roots.add(root.getUnidirNode());
}
}

CompactFunction(Set<Node> roots) {
this.roots.addAll(roots);
}

Eclipse gives me the following errors:

Duplicate method CompactFunction(Set<CompactFunctionBuilder.BidiNode>)
in type CompactFunction

for the first constructor, and

Duplicate method CompactFunction(Set<CompactFunction.Node>) in type
CompactFunction

for the second one. I suppose this is because erasure makes the method
signatures the same, but I thought overloading was handled by the
compiler, so this should work fine, right?

So the question: are these error messages correct, and if yes, what is
an alternative solution to achieve my goal?

Thanks for reading this far,
H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFFo3uqe+7xMGD3itQRAnkwAJ9Xh23/TQmfIAG4KHZ5wl+Xw8929QCdGE+g
8A4rE7vVIbTFukegB9VPdt8=
=AMcn
-----END PGP SIGNATURE-----
 
H

Hemal Pandya

Hendrik said:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I have a complicated question about overloading with generic arguments.

Not sure I understand all of this, but I get a similar error when I try
the following, which is perhaps a SSCCE of your code:

import java.util.Set;
class Node {}
class BidiNode extends Node {}

class X
{
X(Set<Node> r) {}
X(Set<BidiNode> r) {}
}

The error I get with Sun javac is: name clash: X(java.util.Set<Node>)
and X(java.util.Set<BidiNode>) have the same erasure

The following equivalent example does not have the compile error. Does
it solve your problem? Of course, it is a lot more verbose.

import java.util.Set;
class Node {}
class BidiNode extends Node {}

interface NodeSet extends Set<Node> {}
interface BidiNodeSet extends Set<BidiNode> {}

class X
{
X(NodeSet r) {}
X(BidiNodeSet r) {}

static class ABC extends java.util.HashSet<Node> implements NodeSet
{}
static void foo()
{
ABC abc = new ABC();
abc.add(new Node());
new X(abc);
}
}
 
D

Daniel Pitts

Hemal said:
Not sure I understand all of this, but I get a similar error when I try
the following, which is perhaps a SSCCE of your code:


The problem is that
public void something(Set<A> blah);
has the same signature as
public void something(Set<B> blah);
and also has the same signature as
public void something(Set blah);

because of erasure.

You have a couple of ways to solve your problem.
1. Use polymorphism of Node and move the differening behaviour from
your constructor to the Node itself. This is what I would recommend
based on what I've seen. That way you could have a Set<Node> which
contains BOTH Bidi nodes and otherwise.
You could also:
2. Have a different class that handles your other type of object.
3. Use Set<? extends Node> so that you have one constructor that takes
bother types of sets.
4. Have a different signature for the second type of constructor (add a
throw-away int)
 
H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Daniel Pitts schreef:
The problem is that
public void something(Set<A> blah);
has the same signature as
public void something(Set<B> blah);
and also has the same signature as
public void something(Set blah);

because of erasure.

Yes, but I thought that which overloaded method to choose was decided at
compile time. Since the compiler knows about generics, it should not be
a problem.
You have a couple of ways to solve your problem.
1. Use polymorphism of Node and move the differening behaviour from
your constructor to the Node itself. This is what I would recommend
based on what I've seen. That way you could have a Set<Node> which
contains BOTH Bidi nodes and otherwise.

This would of course be the most elegant solution. The problem is: The
whole purpose of the Node class is to forget about the bidirectional
stuff. I.e. I have a FunctionBuilder, which needs up pointers, but once
the function has been built, I want to forget them, to save place.
Then, the functions are manipulated in ways that only use down pointers.
So I don’t want to clutter the Function class with anything related to
the bidirectional pointers. Ideally, I would even remove that
constructor, which I will probably do, eventually.

I could make BidiNode extend Node, but then I would have to introduce a
function in Node that is used in the constructor, which is overridden in
BidiNode. I do not want that function.

I think I’ll work with the design some more, and see if something nicer
comes out of it. I suspect that eventually, I will not need the
bidirectional nodes anymore, so then the problem solves itself.

I mainly posed the question out of curiosity why this error occurs.
Which still is not entirely clear, see above.
You could also:
2. Have a different class that handles your other type of object.

I do not understand.
3. Use Set<? extends Node> so that you have one constructor that takes
bother types of sets.

That would once again require BidiNode to extend Node.
4. Have a different signature for the second type of constructor (add a
throw-away int)

Indeed, but *yuk*. :-(

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFFpMVre+7xMGD3itQRAkTbAJ9ss+IhsfakjfISYJt6eJGQvjsIMwCdEil7
qCjN6OePkiks0A4DdVORIyw=
=tTqd
-----END PGP SIGNATURE-----
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top