Java Forum / First Aid / March 2006
Once again problems with wildcards/generic methods
Hendrik Maryns - 27 Feb 2006 12:28 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Hi,
I have successfully applied generics a few times now, but once again, it gets a bit more complicated, and Eclipse?s error messages are a bit too cryptic.
So I have this method public <T extends State> List<Set<List<T>>> arrangeStates(Set<T> states)
Here, I need the parameter T, because I want to be able to give subtypes of State to the method, and get a result with the same subtypes (as in Sun?s Generics Tutorial: parametrised methods should be used if you want to express a relation between the types of the arguments and/or return type.) I had to introduce the T, because I want to invoke the method with a subtype of State (worked fine with State before).
Now another method, public List<Set<FunctionInputTuple>> sortForArities(Set<? extends State> states) invokes arrangeStates like so:
List<Set<List<State>>> arrangedStates = this.arrangeStates(states);
and then goes on doing stuff with it. Here, I did not use a type parameter, as wildcards are sufficient. But as the knowledgeable will have noticed, the above line does not compile. How can I change it such that I can invoke arrangeStates on Set<? extends State>?
The compiler message is this: Error Type mismatch: cannot convert from List<Set<List<capture-of ? extends State>>> to List<Set<List<State>>> Signature.java
Eclipse?s Quick Fix proposes to change the type of arrangedStates to List<Set<List<? extends State>>>, but that gives another warning, and its suggestions stay the same...
Thanks, H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Hendrik Maryns - 27 Feb 2006 12:32 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Hendrik Maryns schreef:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 [quoted text clipped - 35 lines] > List<Set<List<? extends State>>>, but that gives another warning, and > its suggestions stay the same... I should add to this that I do not need arrangedStates to be anything more specific than a list of sets of lists of states (indeed, this is something cartesian-product like). Whether they are a subtype of states is not important.
H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Hendrik Maryns - 28 Feb 2006 12:54 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Is there no Knowledgeable Person (TM), that can give me a hand here? Please, I?ve been reading FAQs about generics for some hours now, and did not find anything helpful (yet).
TIA, H.
>> Hi, >> [quoted text clipped - 38 lines] > > H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Bart Cremers - 28 Feb 2006 13:29 GMT List<Set<List<? extends State>>> arrangedStates = this.arrangeStates(states);
Bart
Bart Cremers - 28 Feb 2006 13:31 GMT Oops, didn't read carefull enough. Could you post a complete code example?
Bart
Hendrik Maryns - 01 Mar 2006 10:16 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Bart Cremers schreef:
> Oops, didn't read careful enough. Indeed:-)
Could you post a complete code
> example? My pleasure, should?ve done that from the start, I guess. The additional class SignatureSymbol is just a wrapper around a String (getName) and an int (getArity), whereas FunctionInputTuple is a wrapper around a SignatureSymbol and a list of States, which checks that the length of the list is the same as the symbol?s arity. State is a class that does nothing special except existing.
FunctionInputTuple.getInstance(symbol, states) is a factory method. It returns the single instance with the given symbol and states. (Sort of cache management).
import java.util.*;
/** * A class representing a signature of an automaton. It holds the alphabet of * symbols on which the automaton works. Signatures are immutable. */ public class Signature implements Iterable<SignatureSymbol> {
/** * Initialise a new signature, with given set of symbols. * * @param symbols */ public Signature(Set<SignatureSymbol> symbols) { this.symbols = new ArrayList<SignatureSymbol>(symbols); Collections.sort(this.symbols, new Comparator<SignatureSymbol>() {
public int compare(SignatureSymbol sym1, SignatureSymbol sym2) { return sym1.getArity() - sym2.getArity(); }
}); }
/** * The symbols of the signature. They are stored in a list, sorted by * arity. */ final private List<SignatureSymbol> symbols;
/** * Return a list of sets, where every symbol in the ith set has arity i. * * @return Every symbol with arity i belongs to the ith set. * | for each symbol in this * | result.get(symbol.getArity()).contains(symbol) * @return The ith set in the list contains only elements of arity i. * | for 0 <= i < result.size() * | for each symbol in result.get(i) * | symbol.getArity() == i */ public List<Set<SignatureSymbol>> getSymbolsSorted() { List<Set<SignatureSymbol>> result = new ArrayList<Set<SignatureSymbol>>(); for (int i = 0; i <= getMaximalArity(); i++) { result.add(i, new HashSet<SignatureSymbol>()); } for (SignatureSymbol symbol : this) { result.get(symbol.getArity()).add(symbol); } // make all sets unmodifiable for (int i = 0; i < result.size(); i++) { result.set(i, Collections.unmodifiableSet(result.get(i))); } return result; // TODO: improve/remove this for list }
/** * Return the maximal arity of an element in this signature. */ public int getMaximalArity() { return symbols.get(symbols.size()-1).getArity(); }
/** * Arrange the states in lists, such that every combination of i states is * in a list in the ith set.
* THIS FUNCTION WORKS FINE (I THINK)
* @param states * The states to arrange. * @return The ith set represents the ith power of the set of states * (cartesian product). It goes on until getMaximalArity(). */ public <T extends State> List<Set<List<T>>> arrangeStates(Set<T> states) { List<Set<List<T>>> result = new ArrayList<Set<List<T>>>(); Set<List<T>> setI = new HashSet<List<T>>(); setI.add(new ArrayList<T>()); result.add(0, setI); for (int i = 1; i <= getMaximalArity(); i++) { setI = new HashSet<List<T>>(); result.add(i, setI); for (T state : states) { for (List<T> list : result.get(i - 1)) { List<T> newList = new ArrayList<T>(); newList.add(0, state); // copy list into newList from position 1 newList.addAll(1, list); setI.add(newList); } } } return result; }
/** * Sort the given states such that for each symbol of this signature, if its * arity is i, all possible FunctionInputTuples with combinations of states * of length i are in the ith set in the resulting list. * * @param states * The states to sort. * @return Every tuple in set i has a symbol of arity i. * | for each 0 < i <= result.size() * | for each tuple in result.get(i) * | tuple.getSymbol().getArity() == i * @return Every possible combination of i states is in set i for each * symbol of arity i. * | for each 0 < i <= result.size() * | for each symbol in this * | if (symbol.getArity() == i) * | then for each s_1 ... s_i in states * | result.get(i).contains( * | FunctionInputTuple.getInstance(symbol, s_1, ... s_i) */ public List<Set<FunctionInputTuple>> sortForArities(Set<? extends State> states) { List<Set<SignatureSymbol>> sortSyms = getSymbolsSorted(); List<Set<FunctionInputTuple>> result = new ArrayList<Set<FunctionInputTuple>>();
// HERE IS THE PROBLEM List<Set<List<State>>> arrangedStates = this.arrangeStates(states);
for (Set<SignatureSymbol> set : sortSyms) { Set<FunctionInputTuple> aritySet = new HashSet<FunctionInputTuple>(); result.add(aritySet); // to the end! for (SignatureSymbol symbol : set) { for (List<State> stateArr : arrangedStates.get(symbol.getArity())) { try { aritySet.add(FunctionInputTuple.getInstance(symbol, stateArr)); } catch (FunctionArgumentsMismatchException e) { // should not occur } } } } return result; }
}
I hope it is readable, if necessary, I can trim down some more. Thanks for any help, H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Hendrik Maryns - 01 Mar 2006 12:29 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Hendrik Maryns schreef:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 [quoted text clipped - 45 lines] > something cartesian-product like). Whether they are a subtype of states > is not important. Hi all,
After reading in the very interesting Java Generics FAQ from Angelika Langer, I finally found the answer in the article about multilevel wildcards: http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#What%20 do%20multilevel%20wildcards%20mean? or http://tinyurl.com/h3j8y.
Also the part about Type System http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Type %20System explains what happens in nested type arguments (stuff like List<? extends Set<? super Long>>).
Roedy, might be something interesting to link to...
The problem is that the type arguments are nested, and wildcard capturing.
Anyway, the solution was to make sortForArities a parametrised method, like this:
public <T extends State> List<Set<FunctionInputTuple>> sortForArities( Set<T> states) { List<Set<SignatureSymbol>> sortSyms = getSymbolsSorted(); List<Set<FunctionInputTuple>> result = new ArrayList<Set<FunctionInputTuple>>(); List<Set<List<T>>> arrangedStates = this.arrangeStates(states); for (Set<SignatureSymbol> set : sortSyms) { Set<FunctionInputTuple> aritySet = new HashSet<FunctionInputTuple>(); result.add(aritySet); // to the end! for (SignatureSymbol symbol : set) { for (List<T> stateArr : arrangedStates.get(symbol .getArity())) { try { aritySet.add(FunctionInputTuple.getInstance(symbol, stateArr)); } catch (FunctionArgumentsMismatchException e) { // should not occur } } } } return result; }
That works. I have to think a bit more about why exactly this is necessary and whether this would be possible with wildcards, because only seeing the method signature, it seems unnecessary to use the generic method form. This should be possible with wildcards. This breaks encapsulation: by changing this into a generic method, I give away that I cannot implement it with wildcards, which says something about the constructs used.
Thanks to all, and to Angelika Langer specifically.
H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Hendrik Maryns - 02 Mar 2006 20:35 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Hendrik Maryns uitte de volgende tekst op 03/01/2006 01:29 PM:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 [quoted text clipped - 101 lines] > away that I cannot implement it with wildcards, which says something > about the constructs used. Forget that. The trick is, to make the method above private, then invoke that one from the public one which uses wildcards. A bit unclean, but works and the only way. See http://tinyurl.com/o4a82, in Angelika?s FAQ again.
> Thanks to all, and to Angelika Langer specifically. again.
H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Roedy Green - 28 Feb 2006 17:36 GMT On Mon, 27 Feb 2006 13:28:31 +0100, Hendrik Maryns <hendrik_maryns@despammed.com> wrote, quoted or indirectly quoted someone who said :
>public List<Set<FunctionInputTuple>> sortForArities(Set<? extends State> >states) >invokes arrangeStates like so: To better understand what you are doing, please define State, FunctionTuple and tell us what is a subset of what.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Hendrik Maryns - 01 Mar 2006 10:21 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Roedy Green schreef:
> On Mon, 27 Feb 2006 13:28:31 +0100, Hendrik Maryns > <hendrik_maryns@despammed.com> wrote, quoted or indirectly quoted [quoted text clipped - 6 lines] > To better understand what you are doing, please define State, > FunctionTuple and tell us what is a subset of what. Ok, sorry. As I answered to Bart?s post: State is just a dummy class that represents a state of an automaton, but does nothing. It just registers a name. It does have a subclass, not mentioned here, which I want to be able to use the method with, too. (StateSet, a state which contains other states.)
FunctionInputTuple is a wrapper around a SignatureSymbol and a list of states. It checks that the length of the list is the same as the arity of the symbol.
A SignatureSymbol is a wrapper around a String (its name) and an int (its arity), with appropriate getters. It also does nothing.
Hope this helps, the whole class can be seen in the other post.
TIA, H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|