# dynamische return-Werte



## hdi (28. Mrz 2009)

Hallo,
in einem anderen Thread hat jmd gefragt, wie er am besten folgende Situation designed:

Er hat eine Klasse die u.a. eine Methode getTerminal() hat. Im Moment returned die String.

Nun hat er an einer globalen Stelle im Programm eine Liste solcher Terminal-Infos.
Im Moment natürlich List<String>.

Die Frage war: Was ist, wenn sich das ändert? Wenn man zB keinen einfachen String
mehr haben möchte, sondern ein komplexes Objekt einer neuen Klasse, oder sonst was?

Meine Idee war folgende:

[HIGHLIGHT="Java"]Interface TerminalSymbol<T>{
    public <T> getTerminal()
}[/HIGHLIGHT]

Eine Implementierung davon könnte das T nun durch String erstezen, eine andere
könnte es durch ein komplexe Objekt ersetzen.

Auf jeden Fall hat man aber an der globalen Stelle nun eine Liste

[HIGHLIGHT="Java"]List<TerminalSymbol>
[/HIGHLIGHT]
und da steckt dynamisch zur Laufzeit das drin, von welcher Implementierung ein Objekt
des Interfaces TerminalSymbol ist.

Sprich wenn man die Liste durchläuft und auf jedem TerminalSymbol ein .getTerminal()
auführt, bekommt man Strings, andere Objekte, whatever.
Es muss nicht mal gemischt sein, sondern wäre ja schon toll, wenn man nix weiter machen
muss als eine neue Interface-Implementierung zu erstellen, und schon nutzen bestimmte
Objekte die neue Implementierung, und returnen keinen String mehr sondern was anderes.

So.. ich hoffe es kommt rüber was das Ziel ist?
Problem: Der code des o.g. Interfaces lässt sich nicht kompilieren.

Geht sowas irgendwie, mit richtiger Anwendung von Generics/Wildcards?

Vielen Dank


----------



## SlaterB (28. Mrz 2009)

> public <T> getTerminal()

korrekter:
public T getTerminal()

aber das ist doch jetzt eine Generics-Grundlage, was hat das mit dem ganzen Thema zu tun?

zum Thema weiter:
eine List<TerminalSymbol> enthält nicht generische TerminalSymbol-Objekte, das T ist hier nicht bekannt,
die getTerminal()-Methode liefert Object?, damit kommt man wohl nicht weit


----------



## hdi (28. Mrz 2009)

> aber das ist doch jetzt eine Generics-Grundlage, was hat das mit dem ganzen Thema zu tun?



Sorry wenn ich das nicht trennen kann, denn mit Generics kenn ich mich null aus.



> damit kommt man wohl nicht weit


Aber verstehst du, worauf ich hinauswill?
Kann man das irgendwie anders lösen? Wie macht man sowas am besten, wie
designed man etwas, wenn man weiss dass sich Rückgabewerte von Methoden
ändern könnten.

*EDIT:* "dynamisch" war wohl der falsche Ausdruck :/
Es muss ja nicht dynamisch zur Laufzeit sein, sondern generell so designed, dass
man es möglichst einfach abändern kann ohne das Rest-Programm gross anfassen zu müssen.

Das find ich grad hoch interessant. Für Funktionalität usw gibts Interfaces und das is alles
klar, aber wie designed man Methoden mit "wackligem" Rückgabewert möglichst schlau?


----------



## SlaterB (28. Mrz 2009)

ich sehe noch nicht ganz das Ziel,
klassisch generisch möchte ich eine  List<String> und eine List<Integer> erstellen können, von denen get() mal String und mal Integer zurückgibt,
aber das Generic erspart mir dabei vor allem, spezielle Unterlisten StringList, IntegerList zu schreiben, was bei der Vielfalt von ArrayList, LinkedList usw. zu exponentiell vielen Klassen führen würde,

wenn ich dagegen irgendeine Liste oder meinetwegen ein TerminalSymbol habe und nicht weiß, 
ob der Rückgabewert nun String oder Integer ist, dann sehe ich noch keinen Vorteil von Generics in dieser Situation,
ich muss immer noch mit if/ else den Typ unterscheiden und unterschiedliche Verarbeitungen anstoßen


----------



## Illuvatar (28. Mrz 2009)

hdi hat gesagt.:


> Aber verstehst du, worauf ich hinauswill?



Also, ich verstehs jedenfalls nicht so ganz 
Ok, der Rückgabewert kann sich ändern. Und so wie du es beschreibst, gibt es bei diesem Rückgabewert keine Gemeinsamkeit irgendwelcher Art. Das heißt, du wirst auf jeden Fall immer Code ändern müssen, wenn sich der Rückgabewert ändert.
In dem Fall musst du die Liste aber trotzdem Beispielsweise als
[HIGHLIGHT="Java"]List<TerminalSymbol<String>>[/HIGHLIGHT]
deklarieren. In dem Fall kriegst du immer Strings da raus. Wenn du das Interface änderst - musst du die Liste ändern und sämtlichen Code der die Liste verwendest.

Angenommen es gäbe ein Interface oder eine Klasse Foo und du wüsstest, dass das was du aus dem TerminalSymbol rauskriegst immer ein Foo ist, und du verwendest nirgends in deinem Code andere Eigenschaften davon, als die von Foo deklarierten. Dann kannst du TerminalSymbol möglicherweise gleich so definieren (musst aber nicht):
[HIGHLIGHT="Java"]interface TerminalSymbol<T extends Foo>[/HIGHLIGHT]
Die Liste deklarierst du dann in jedem Fall am besten als
[HIGHLIGHT="Java"]List<TerminalSymbol<? extends Foo>>[/HIGHLIGHT]
und da kannst du dann TerminalSymbol<Foo>-Objekte rausholen.
Hinweis: In so eine Liste kannst du natürlich nichts einfügen - für eine beliebiges TerminalSymbol<Bar> weißt du ja nie, ob ein TerminalSymbol<Bar> jetzt gerade tatsächlich in die Liste passt. Du musst also irgendwo, wo du die Liste erzeugst, trotzdem eine konkrete List<TerminalSymbol<Bar>> erzeugen, die du dann später der oben besprochenen Listenvariable zuweist. Da ich nicht weiß woher die Liste kommt, vermute ich trotzdem mal, dass das das sinnvollste ist.


----------



## hdi (28. Mrz 2009)

Ok, ich habe nun Foo-Elemente in der Liste, aber das ändert das Problem ja nicht.
Ich will jetzt eine Methode darauf aufrufen. Bei void-Methoden könnte man das super
lösen, und es wäre zur Lauzteig sogar dynamisch.

Aber wenn sie etwas returned, was returned sie? Vllt am besten noch eine Klasse, 
die abstrakt definiert ist? Dann geht das gleiche wieder in dieser Klasse los...

Also, wie man's dreht und wendet: Irgendwo muss ich einen Rückgabewert hinschreiben.
Ich kann mir grad nicht vorstellen dass für sowas nicht ein Design-Pattern vorliegt?

Ich meine: Ich hab Objekte, von denen kann ich ne Info abfragen. 
Diese Info ist irgendwie geartet. Ob das Strings sind oder ints oder sonst was.
Je nach konkreter Sub-Klasse dieser Objekt-Klasse / bzw. Implementierung falls es sich
um ein Interface handelt.

Bsp:
Ich hab ne Tüte, da sind Würfel drin und Vokabelkärtchen.
Von einem Würfel möchte ich seine Augenzahl (int), von dem Kärtchen den Inhalt (String).

Also eine Tüte, die "getSomeInfoable" -Objekte drin hat.
Also im Endeffekt: Wie programmier ich getSomeInfoable?

Kann gut sein dass ich mich hier grad total verstricke, aber mir kommt grad keine 
elegante Lösung dafür. Angenommen ich möchte eine Funktion getInfo() aufrufen,
und die Ergebnisse auf die Konsole printen.
Der würfel retruned ein int, die Karte ein String, beides kann ich ausgeben per print().
Aber wie sieht die Signatur der getInfo() Methode aus? Wie der Rückgabewert?

Geht sowas echt nicht ohne instanceof oder if-else?


----------



## SlaterB (28. Mrz 2009)

Illuvatar hat gesagt.:


> Hinweis: In so eine Liste kannst du natürlich nichts einfügen - für eine beliebiges TerminalSymbol<Bar> weißt du ja nie, ob ein TerminalSymbol<Bar> jetzt gerade tatsächlich in die Liste passt.


ganz so schlimm ist es nicht, in der Liste sind TerminalSymbol-Objekte drin, also ist es auch ok, diese einzufügen,
was anderes wäre es, wenn es eine 
List<? extends TerminalSymbol<? extends Foo>> 
wäre 

siehe folgendes Beispiel, in welchem ich zur Sicherheit das noch mal nachgeprüft habe,
hab mich schon oft genug geirrt  ,
kompiliert:

```
public class Test {

	public static void main(String argv[]) throws Exception {
		List<TerminalSymbol<? extends Foo>> list = null;
		list.add(new TerminalSymbolImpl<Foo>());
		list.add(new TerminalSymbolImpl<FooSub>());
	}

}

class Foo {

}

class FooSub extends Foo {

}

interface TerminalSymbol<T> {
	public T getTerminal();
}

class TerminalSymbolImpl<T> implements TerminalSymbol<T> {
	public T getTerminal() {
		return null;
	}
}
```


----------



## SlaterB (28. Mrz 2009)

> Aber wie sieht die Signatur der getInfo() Methode aus? Wie der Rückgabewert?

entweder Object oder gleich String, 
der Aufrufer kann sowieso nicht unterscheiden, ob das nun int oder String oder sonstwas ist,
das soll nur ausgegeben werden,
also kann ruhig jede Klasse selber ihre Info als String zusammenstellen -> Rückgabewert String,
Object ginge auch mit dessen toString()-Methode, falls das irgendwie simpler zu machen ist 

du musst dir überlegen, was der Aufrufer damit machen soll/ will, davon geht alles aus

edit:
die toString()-Methode selber hat quasi die gleiche Aufgabe, und die braucht seit Java 1.0 keinen neumodischen Kram wie Generics


----------



## hdi (28. Mrz 2009)

Okay, das mit dem toString() hat mir jetzt weitergeholfen. 
Ein Objekt muss sich einfach selbt organisieren, wenn es für eine aussenstehende Stelle
zu kompliziert sein würde.

Ist wohl ein typischer Fall von einer zu allgemeinen Überlegung. Wenn man konkret
etwas realisieren will, wird man es wohl irgendwie hinkriegen, dass die Objekte das selbst
übernehmen können.

Stimmt schon, wofür denn global einen x-typisierten Wert rausholen? Wofür? Na 
weil man damit ja anscheinend weiter etwas machen möchte. 
Und genau das sollte dann halt auch gleich das Objekt für sich übernehmen!

Okay, also ich denk das war die Antwort. Danke SlaterB und alle :toll:
(Wenn ihr das nicht so einfach seht, widersprecht bitte!)


----------



## Illuvatar (28. Mrz 2009)

@SlaterB Stimmt, da hast du recht.

Und dieser Code:
[HIGHLIGHT="Java"]import java.util.*;

public class Test {

  public static void main(String argv[]) throws Exception {
    List<TerminalSymbol<FooSub>> list1 = new ArrayList<TerminalSymbol<FooSub>>();
    List<TerminalSymbol<? extends Foo>> list2 = list1;
    list2.add(new TerminalSymbolImpl<Foo>());
    list1.get(0).getTerminal().bar();
  }

}

class Foo {

}

class FooSub extends Foo {
  void bar(){}
}

interface TerminalSymbol<T> {
  public T getTerminal();
}

class TerminalSymbolImpl<T> implements TerminalSymbol<T> {
  public T getTerminal() {
    return null;
  }
}[/HIGHLIGHT]
gibt zum Glück einen Error in Zeile 7.

Aber was wäre denn dann die Syntax für das was ich machen will?  Also für eine Liste, die TerminalObjekte eines Typs T aufnimmt, T ist eine Unterklasse von Foo - aber sozusagen in der Liste immer gleich?


----------



## SlaterB (28. Mrz 2009)

hmm, ich denke, dass geht nicht 'von selbst' wie bei
List<? extends Foo>
wo genau ein generischer Parameter genau eines Objektes festgelegt wird,
über verschiedene Objekte ist das weitaus schwieriger, etwa auch bei dem interessanten Fall
Map<? extends Foo,List<? extends Foo>>
bei dem die Liste zum Key passen soll

mir scheint nur die Variante
List<TerminalSymbol<T>> 
denkbar, wobei T ein vorher definierter Typ sein muss, entweder der generische Typ/ Parameter der Klasse oder der einer einzelnen Methode:

public <T extends Foo> void x(T parameterDerDenTypBestimmt) {
List<TerminalSymbol<T>>  tstList;
}


----------



## 0x7F800000 (28. Mrz 2009)

Hmm, rein zufällig habe ich mir gestern erst gedanken drüber gemacht, wie ich Grammatiken sinnvoll darstellen soll, und obwohl ich mich mit Generics mittlerweile ganz gut verstehe, ist mir am ende nichts sinnvolleres eingefallen, als einfach nur permanent mit Object bzw String zu arbeiten. Vor allem ist mir bisher nicht aufgefallen, wozu ich mehr bräuchte. Wenn ich einfach irgendeine rechnerei mit Grammatik darstellen will, dann sind Strings zum lesen schon gut genug, wenn ich mir einen parser-generator bastle, dann sehe ich (bisher!) auch keinen Grund, die abstrakten Symbole der Grammatik mit_ irgendwelchen_ Eigenschaften auszustatten: am ende ist das im ausgabe-code doch eh alles nicht vorhanden.???:L Ich versuch's mal mit Strings. Wenn ich mir heute LR(0) beigebracht habe, bin ich glücklich


----------



## hdi (29. Mrz 2009)

Ich meld mich mal wieder, ich lese grad diesen Study Guide für das SCJP Exam,
das ich für dieses Jahr angestrebt habe.
und ich las hier grad über "covariant return types":

Eine overridden Method kann den return Type des Originals ändern, solange er Subtyp ist.
Ist das vllt ein Ansatz? Oder ist die ganze Geschichte noch immer einfach nur ein selbsternanntes
Problem?

Auf jeden Fall, auch wenn ich jetz diesen Thread ein wenig missbrauche
(aber ist ja meiner, damit darf ich tun was ich will... ueh
selbst wenn das jetzt hier nicht weiterhilft: Ich frage mich wann die Nutzung solcher
return types sinnvoll ist. Oder ist es das gar nicht?
Gibt ja einige Sprachfeatures in Java die kein Mensch jemals nutzt...

thx


----------



## SlaterB (29. Mrz 2009)

weiter oben habe ich ja vorgeschlagen, dass der Rückgabetyp Object sein könnte,
niemand wird wirklich ein Object-Objekt erstellen ( new Object() ), sondern das ist ein Beispiel, in welchem Unterklassen andere Dinge zurückgeben wie String, Integer usw., 
solange das Interface des in der Oberklasse angegeben Typ reicht, also das Interface von Object, da nur dessen toString()-Methode benötigt wird, ist das ausreichend

anderes Beispiel: AbstractList kennt eine Methode iterator() bzw. listIterator(), die ein Objekt einer eigenen anonymen inneren Klasse zurückgibt, 
welches mit den allgemeinen Methoden get(index) usw. die Liste durchläuft,

für LinkedList ist das natürlich nix, diese überschreibt die iterator()-Methode und gibt einen speziell angepassten Iterator zurück, der die Verlinkung der Elemente berücksichtigt
(genauer: der neue Iterator ist in der Klasse AbstractSequentialList extends AbstractList definiert, nicht erst in LinkedList),

für ArrayList reicht dagegen die Standard-Methode von AbstractList,

im Interface List ist die Methode mit Rückgabewert Interface Iterator definiert,
zwangsläufig müssen also alle implementieren Klasse eine von Iterator 'erbende' Klasse zurückgeben,

für den Aufrufer ist völlig egal, welche Klasse er genau erhält, das Iterator-Interface gibt die wichtigen Methoden vor,
wie sie letztlich implementiert sind ist relativ egal

ganz normale OO-Vorgänge

edit: und selbst wenn sich der Rückgabewert nicht ändert, kann das zurückgegebene Objekt immer noch von irgendeiner SubKlasse sein/ variieren, siehe Factory:

public List createList(boolean ichMoechteHeuteLinked) {
if (ichMoechteHeuteLinked( {
return new LinkedList();
} else {
return new ArrayList();
}
}


----------



## hdi (29. Mrz 2009)

Ja ich dachte nur vllt hilft einem die Info, dass man weiss welcher konkrete Typ zurückkommt.
Das würde ja der Fall sein bei covariant return types.
Allerdings "weiss" man es ja nicht, man sieht es nur in der Klasse als Programmierer,
aber das sieht man auch beim return.
Zumindest weiss man's nicht nach außen. 

Aber ich glaub ich kann mir jetzt vorstellen wo der Sinn von diesem Feature ist:
man kann leichter *innerhalb* der Subklasse arbeiten, wenn man zB andere Methoden
hat, die eine geerbte Methode aufrufen. (zB public JComponent getComponent())
Statt in einer Methode dort immer alles von JComponent auf JPanel casten zu müssen,
überschreib ich diese Methode mit covariant return type (JComponent -> JPanel)
und erspar mir somit das dauernde casten, weil ich weiss dass es innerhalb der Klasse
ein JPanel sein soll.


----------



## SlaterB (29. Mrz 2009)

stimmt, das ist noch bisschen was anderes,
zum Vergleich: wenn man direkt mit LinkedList arbeitet und dessen iterator() verwendet, 
könnte dieser zusätzliche Methoden zu einem normalen Iterator bieten, die nur mit Verlinkung funktionieren
(könnte, ein ausgedachtes Beispiel)


----------

