designing Layout for JUNG 3.0: types and type parameters
tl;dr: as the lead JUNG designer, I'm looking for feedback on how we should handle this particular issue. Please comment if you have thoughts on this subject.
As it currently stands in JUNG 2.x, the Layout<V, E> interface has two type parameters: V for nodes and E for edges.
However, Layout doesn't actually operate on anything relating to edges; it only specifies node positions. So, with one exception, there's nothing about it that should require an edge type parameter.
The catch is that Layout also provides a getGraph() method that returns the graph whose node positions are specified by the Layout. This is the reason why it's historically needed the E parameter: so that the type returned by getGraph() could be fully parameterized as a Graph<V, E>.
JUNG 3.0 will replace the JUNG graph types with Guava's common.graph types: Graph<N>, ValueGraph<N, V>, and Network<N, E>. Network has an asGraph() method which returns a Graph<N> (and ValueGraph<N, V> likely will have asGraph() as well once the dust settles).
For the moment, the visualization system will probably still operate on Networks (which are the closest analog to the JUNG 2.x Graph type). But we'd like to leave the door open for being able to use this visualization system to handle other graph types.
To sum up: Layout needs N for actually laying out nodes, but it only needs an edge type parameter (E or V) in order to be able to return a fully-specified Network or ValueGraph.
I see a few possibilities; there may be others.
(1) Layout keeps an edge type parameter, and supports hanging onto (and providing) a reference to its graph:
(1a) for Network only, i.e., getGraph() returns Network (status quo, essentially)
(1b) for Graph, ValueGraph, and Network (separate getGraph(), getValueGraph(), getNetwork() methods, only one of which will work for any given layout instance)
(I thought about (1c), which would introduce a generic graph type, something like Layout<G<N, E> extends Object, N, E>, such that Layout::getGraph() would return G, but that appears to break down for Graph<N>.)
(2) Layout gets rid of its edge type parameter and no longer provides a getGraph() method.
Instead of taking a graph as its input, it would take a Set<N> (or possibly an Iterable<N>).
(3) Create separate subtypes of Layout: NetworkLayout, GraphLayout, etc. These then would each provide their own getGraph() methods with appropriate return types. (You might also want a convenience method to provide the type, so as to help the user avoid repeated instanceof calls.)
(1a) works but doesn't get us any closer to resolving the underlying issue that we'd like to support other graph types for visualization.
(1b) would be kind of a mess: you'd have to have two methods for each supported graph type (one for specifying the graph in the construction and one for providing it), plus (perhaps) an extra convenience method to tell you which type of graph was actually being operated on (so you'd know which query method to call).
(2) works, but at the cost of refactoring the visualization system so that the layout isn't the object that's responsible for providing the graph reference as needed. It also means that the connection between the layout and the graph would be lost, which seems unfortunate.
(3) works, but feels like it makes the layout type more complex than I'd like (and the visualization system, likewise).
I'm leaning towards (2) at the moment, but I'm open to other ideas, and I'd be interested to know what other people think.
Hrm... do you know what sorts of things people have used Layout::getGraph for in the past? I personally have no idea, as I'm not a user of Layout myself (or JUNG for that matter anymore), but I wonder if GrepCode could help you figure out who is using it, how often it's being used and why.
If it was me, I'd be inclined to go for either (2) or (3). (1a), as you say, doesn't get one any closer towards solving the problem, and (1b) seems inelegant to me.
I'm currently leaning more towards (3), as I wouldn't want to remove Layout::getGraph in case it's important for someone. However, if GrepCode shows that Layout::getGraph is in fact hardly ever used, then I'd lean more towards (2) instead.
@jrtom Do Google use JUNG internally? I don't know if you have the right and ability to search through Google's code base, but if you do, then that might be another source of information on top of GrepCode that you can use to figure out how often and why Layout::getGraph is used.
Would it make sense to define Layout's getGraph something like this:
public <E> Network<N,E> getGraph();
so a used would call Network<MyNode,MyEdge> network = layoutInstance.<MyEdge>getGraph();
This could be a dumb idea, or it could work fine. Sorry if it is the former.
On Fri, Dec 23, 2016 at 6:49 PM, Jonathan Bluett-Duncan < [email protected]> wrote:
@jrtom https://github.com/jrtom Do Google use JUNG internally? I don't know if you have the right and ability to search through Google's code base, but if you do, that might be another source of information on top of GrepCode for figuring out how often and why Layout::getGraph is used.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/jrtom/jung/issues/72#issuecomment-269057765, or mute the thread https://github.com/notifications/unsubscribe-auth/AAGbB3TSpksp1QQ6QfWu9BTRygHN_VG2ks5rLF33gaJpZM4LVFwG .
@jbduncan JUNG is used by Google internally, and I can look there (since I work there :) ). However, I'm going to need to migrate the JUNG 2.x code to use JUNG 3.0 internally anyway, so this would likely be a fairly minor aspect of that migration if it were necessary.
I hadn't known that GrepCode allowed searching through repositories as well; that's handy, thanks. It would be nice if I could find out how many such matches there were, but so far all I'm finding is one repository besides JUNG itself that uses Layout::getGraph().
@tomnelson if that works (I don't trust anything beyond trivial generics until I've seen it compile :) ) it would solve the problem of what Layout's type parameters need to be, but it doesn't exactly address the question of how (or whether) we should be providing support for fetching the graph from other types.
@jbduncan Can I assume that you don't use JUNG at this point because you're using Guava's common.graph instead? :)
@jrtom Yep, that's a fair assumption to make! I'm now purely a Guava-common.graph user. :)
Hi @jrtom, I just wondered if you managed to find any data since the last time this issue was discussed, to support either keeping or removing Layout.getGraph()?
@jbduncan To answer your question, I have not sought out further usage data. Currently Layout.getGraph() does not exist, and the visualization architecture has been refactored so that the VisualizationModel holds a reference to the graph being visualized (although the details of that still need to be worked out; it seems pretty clear that there are bugs in the current implementation).
As a side point, I am putting together a proposal for common.graph that may make some of this easier to manage (on the input side, at least). (Briefly, I think I can define a common supertype of Graph/ValueGraph/Network; at that point we can supply that to the Layout instance, although some Layouts should be able to work fine with a start (root) node and a SuccessorsFunction.)
That said: while it's certainly going to be the case that most Layout implementations are going to need a reference to the graph of their own, I'm still inclined to think that:
(a) it should be the visualization model's job to maintain a reference to the graph for the visualization, not the layout's job
(b) the graph for a Layout should be final, i.e., if you want to replace the graph, create a new Layout instance
(c) there is no obvious use case, outside the context of visualization (which we've already covered), in which one would need to ask a layout for the graph it's operating on.