Note that there are some explanatory texts on larger screens.

plurals
  1. POGeneric methods returning dynamic object types
    primarykey
    data
    text
    <p>Possibly a question which has been asked before, but as usual the second you mention the word generic you get a thousand answers explaining type erasure. I went through that phase long ago and know now a lot about generics and their use, but this situation is a slightly more subtle one.</p> <p>I have a container representing a cell of data in an spreadsheet, which actually stores the data in two formats: as a string for display, but also in another format, dependent on the data (stored as object). The cell also holds a transformer which converts between the type, and also does validity checks for type (e.g. an IntegerTransformer checks if the string is a valid integer, and if it is returns an Integer to store and vice versa). </p> <p>The cell itself is not typed as I want to be able to change the format (e.g. change the secondary format to float instead of integer, or to raw string) without having to rebuild the cell object with a new type. a previous attempt did use generic types but unable to change the type once defined the coding got very bulky with a lot of reflection. </p> <p>The question is: how do I get the data out of my Cell in a typed way? I experimented and found that using a generic type could be done with a method even though no constraint was defined</p> <pre><code>public class Cell { private String stringVal; private Object valVal; private Transformer&lt;?&gt; trans; private Class&lt;?&gt; valClass; public String getStringVal(){ return stringVal; } public boolean setStringVal(){ //this not only set the value, but checks it with the transformer that it meets constraints and updates valVal too } public &lt;T&gt; T getValVal(){ return (T) valVal; //This works, but I don't understand why } } </code></pre> <p>The bit that puts me off is: that is ? it can't be casting anything, there is no input of type T which constrains it to match anything, actually it doesn't really say anything anywhere. Having a return type of Object does nothing but give casting complications everywhere.</p> <p>In my test I set a Double value, it stored the Double (as an object), and when i did Double testdou = testCell.getValVal(); it instantly worked, without even an unchecked cast warning. however, when i did String teststr = testCell.getValVal() I got a ClassCastException. Unsurprising really.</p> <p>There are two views I see on this:</p> <p>One: using an undefined Cast to seems to be nothing more than a bodge way to put the cast inside the method rather than outside after it returns. It is very neat from a user point of view, but the user of the method has to worry about using the right calls: all this is doing is hiding complex warnings and checks until runtime, but seems to work.</p> <p>The second view is: I don't like this code: it isn't clean, it isn't the sort of code quality I normaly pride myself in writing. Code should be correct, not just working. Errors should be caught and handled, and anticipated, interfaces should be foolproof even if the only expecter user is myself, and I always prefer a flexible generic and reusable technique to an awkward one off. The problem is: is there any normal way to do this? Is this a sneaky way to achieve the typeless, all accepting ArrayList which returns whatever you want without casting? or is there something I'm missing here. Something tells me I shouldn't trust this code!</p> <p>perhaps more of a philosophical question than I intended but I guess that's what I'm asking.</p> <p>edit: further testing.</p> <p>I tried the following two interesting snippets:</p> <pre><code>public &lt;T&gt; T getTypedElem() { T output = (T) this.typedElem; System.out.println(output.getClass()); return output; } public &lt;T&gt; T getTypedElem() { T output = null; try { output = (T) this.typedElem; System.out.println(output.getClass()); } catch (ClassCastException e) { System.out.println("class cast caught"); return null; } return output; } </code></pre> <p>When assigning a double to typedElem and trying to put it into a String I get an exception NOT on the cast to , but on the return, and the second snippet does not protect. The output from the getClass is java.lang.Double, suggesting that is being dynamically inferred from typedElem, but that compiler level type checks are just forced out of the way. </p> <p>As a note for the debate: there is also a function for getting the valClass, meaning it's possible to do an assignability check at runtime.</p> <p>Edit2: result</p> <p>After thinking about the options I've gone with two solutions: one the lightweight solution, but annotated the function as @depreciated, and second the solution where you pass it the class you want to try to cast it as. this way it's a choice depending on the situation. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload