Meine Hauptsprache ist statisch (Java). In Java müssen Sie von jeder Methode einen einzelnen Typ zurückgeben. Sie können beispielsweise keine Methode haben, die bedingt a String
oder bedingt a zurückgibt Integer
. In JavaScript ist dies beispielsweise sehr gut möglich.
In einer statisch getippten Sprache verstehe ich, warum dies eine schlechte Idee ist. Wenn jede Methode zurückgegeben wird Object
(das gemeinsame übergeordnete Element, von dem alle Klassen erben), wissen Sie und der Compiler nicht, womit Sie es zu tun haben. Sie müssen alle Ihre Fehler zur Laufzeit entdecken.
In einer dynamisch getippten Sprache gibt es möglicherweise nicht einmal einen Compiler. In einer dynamisch getippten Sprache ist mir nicht klar, warum eine Funktion, die mehrere Typen zurückgibt, eine schlechte Idee ist. Aufgrund meines Hintergrunds in statischen Sprachen vermeide ich es, solche Funktionen zu schreiben, aber ich fürchte, ich bin sehr gespannt auf eine Funktion, die meinen Code auf eine Weise bereinigen könnte, die ich nicht sehen kann.
Bearbeiten : Ich werde mein Beispiel entfernen (bis ich mir ein besseres vorstellen kann). Ich denke, es lenkt die Leute, auf einen Punkt zu antworten, den ich nicht anstrebe.
quelle
(coerce var 'string)
Ausbeuten astring
oder(concatenate 'string this that the-other-thing)
ähnlich. Ich habe auch Dinge wie geschriebenThingLoader.getThingById (Class<extends FindableThing> klass, long id)
. Und dort könnte ich nur etwas zurückgeben, dasloader.getThingById (SubclassA.class, 14)
SubclassB
SubclassA
Antworten:
Im Gegensatz zu anderen Antworten gibt es Fälle, in denen die Rückgabe unterschiedlicher Typen akzeptabel ist.
Beispiel 1
In einigen statisch typisierten Sprachen ist dies mit Überladungen verbunden, sodass wir davon ausgehen können, dass es mehrere Methoden gibt, von denen jede den vordefinierten festen Typ zurückgibt. In dynamischen Sprachen kann dies dieselbe Funktion sein, die implementiert ist als:
Gleiche Funktion, verschiedene Arten von Rückgabewerten.
Beispiel 2
Stellen Sie sich vor, Sie erhalten eine Antwort von einer OpenID / OAuth-Komponente. Einige OpenID / OAuth-Anbieter enthalten möglicherweise weitere Informationen, z. B. das Alter der Person.
Andere hätten das Minimum, wäre es eine E-Mail-Adresse oder das Pseudonym.
Wieder gleiche Funktion, unterschiedliche Ergebnisse.
Hier ist der Vorteil der Rückgabe verschiedener Typen besonders wichtig, wenn Sie sich nicht für Typen und Schnittstellen interessieren, sondern für welche Objekte sie tatsächlich enthalten. Stellen wir uns zum Beispiel vor, eine Website enthält eine ausgereifte Sprache. Dann
findCurrent()
kann das so verwendet werden:Das Umgestalten in Code, bei dem jeder Anbieter seine eigene Funktion hat, die einen genau definierten, festen Typ zurückgibt, würde nicht nur die Codebasis verschlechtern und eine Code-Duplizierung verursachen, sondern auch keinen Nutzen bringen. Man kann am Ende Horror machen wie:
quelle
sum
Beispiel keine Überladung .sum :: Num a => [a] -> a
. Sie können eine Liste von allem zusammenfassen, das eine Zahl ist. Wenn Sie im Gegensatz zu Javascript versuchen, etwas zu summieren, das keine Zahl ist, wird der Fehler beim Kompilieren abgefangen.Iterator[A]
eine Methodedef sum[B >: A](implicit num: Numeric[B]): B
, die es erlaubt, beliebige Zahlen zu addieren. Sie wird beim Kompilieren überprüft.+
für Zeichenfolgen (durch ImplementierungNum
, was eine schreckliche Idee ist, die aber rechtmäßig ist) oder einen anderen Operator / eine andere Funktion erfinden müssen, die durch Ganzzahlen und Zeichenfolgen überladen ist beziehungsweise. Haskell hat einen Ad-hoc-Polymorphismus über Typklassen. Eine Liste, die sowohl Ganzzahlen als auch Zeichenfolgen enthält, ist viel schwieriger (möglicherweise ohne Spracherweiterungen unmöglich), aber eine ganz andere Angelegenheit.null
Werten.Im Allgemeinen ist es aus den gleichen Gründen eine schlechte Idee, dass das moralische Äquivalent in einer statisch typisierten Sprache eine schlechte Idee ist: Sie haben keine Ahnung, welcher konkrete Typ zurückgegeben wird, Sie haben also keine Ahnung, was Sie mit dem Ergebnis tun können (abgesehen von einige Dinge, die mit jedem Wert getan werden können). In einem statischen Typsystem verfügen Sie über vom Compiler überprüfte Annotationen von Rückgabetypen und dergleichen, aber in einer dynamischen Sprache ist das gleiche Wissen immer noch vorhanden - es ist nur informell und wird in den Köpfen und in der Dokumentation gespeichert, nicht im Quellcode.
In vielen Fällen gibt es jedoch einen Reim und einen Grund, zu dem der Typ zurückgegeben wird, und der Effekt ähnelt der Überladung oder dem parametrischen Polymorphismus in statischen Typsystemen. Mit anderen Worten, der Ergebnistyp ist vorhersehbar und nicht ganz so einfach auszudrücken.
Beachten Sie jedoch, dass eine bestimmte Funktion möglicherweise aus anderen Gründen nicht richtig entworfen wurde: Eine
sum
Funktion, die bei ungültigen Eingaben false zurückgibt, ist in erster Linie deshalb eine schlechte Idee, weil dieser Rückgabewert unbrauchbar und fehleranfällig ist (0 <-> false confusion).quelle
NaN
es überhaupt "Kontrapunkt" ist. NaN ist tatsächlich eine gültige Eingabe für jede Gleitkommaberechnung. Sie können alles damit machenNaN
, was Sie mit einer tatsächlichen Nummer machen könnten. Zwar ist das Endergebnis dieser Berechnung für Sie nicht sehr nützlich, es führt jedoch nicht zu merkwürdigen Laufzeitfehlern, und Sie müssen es nicht ständig überprüfen - Sie können es nur einmal am Ende von a überprüfen Reihe von Berechnungen. NaN ist kein anderer Typ , es ist nur ein spezieller Wert , ähnlich einem Null-Objekt .NaN
neigt das Objekt, wie das Nullobjekt, dazu, sich zu verstecken, wenn Fehler auftreten, nur damit sie später angezeigt werden . Zum Beispiel wird Ihr Programm wahrscheinlich explodieren, wenn esNaN
in eine Schleifenbedingung gerät.NaN
Wert (a) eigentlich kein anderer Rückgabetyp ist und (b) eine gut definierte Gleitkommasemantik hat und sich daher nicht als Analogon zu einem variabel typisierten Rückgabewert qualifiziert. Eigentlich ist es in der Ganzzahl-Arithmetik gar nicht so anders als Null . Wenn eine Null "versehentlich" in Ihre Berechnungen einfließt, erhalten Sie häufig entweder eine Null als Ergebnis oder einen Fehler beim Teilen durch Null. Sind die durch IEEE-Gleitkomma definierten "Unendlich" -Werte auch böse?In dynamischen Sprachen sollten Sie nicht fragen, ob unterschiedliche Typen, sondern Objekte mit unterschiedlichen APIs zurückgegeben werden sollen . Da sich die meisten dynamischen Sprachen nicht wirklich für Typen interessieren, sondern verschiedene Versionen von Duck Typing verwenden .
Bei Rücksendung sind unterschiedliche Typen sinnvoll
Zum Beispiel ist diese Methode sinnvoll:
Da sowohl file als auch eine Liste von Strings (in Python) iterable sind, wird der String zurückgegeben. Sehr unterschiedliche Typen, dieselbe API (es sei denn, jemand versucht, Dateimethoden in einer Liste aufzurufen, dies ist jedoch eine andere Geschichte).
Sie können bedingt
list
oder zurückgebentuple
(tuple
ist eine unveränderliche Liste in Python).Formal sogar dabei:
oder:
gibt verschiedene Typen zurück, da sowohl Python
None
als auch Javascriptnull
eigenständige Typen sind.Alle diese Anwendungsfälle hätten ihre Entsprechung in statischen Sprachen, die Funktion würde nur eine richtige Schnittstelle zurückgeben.
Bei der bedingten Rückgabe von Objekten mit unterschiedlicher API ist eine gute Idee
In den meisten Fällen ist es nicht sinnvoll, verschiedene APIs zurückzugeben. Nur ein sinnvolles Beispiel, das mir in den Sinn kommt, kommt dem, was @MainMa gesagt hat, sehr nahe : Wenn Ihre API unterschiedliche Detaillierungsgrade liefern kann, ist es möglicherweise sinnvoll, mehr Details zurückzugeben, wenn diese verfügbar sind.
quelle
do_file
Dateibeispiel wird in beiden Fällen eine Iteration von Zeichenfolgen zurückgegeben.iter()
sowohl die Liste als auch die Datei aufrufen , um sicherzustellen, dass das Ergebnis nur in beiden Fällen als Iterator verwendet werden kann.None or something
ist ein Killer für die Leistungsoptimierung, die Tools wie PyPy, Numba, Pyston und andere leisten. Dies ist einer der Python-Ismen, die Python nicht so schnell machen.Ihre Frage bringt mich dazu, ein wenig zu weinen. Nicht für die von Ihnen angegebene Beispielnutzung, sondern weil jemand diesen Ansatz unabsichtlich zu weit gehen wird. Es ist nur ein kurzer Schritt von lächerlich nicht zu wartendem Code entfernt.
Der Anwendungsfall der Fehlerbedingung macht Sinn, und das Nullmuster (alles muss ein Muster sein) in statisch typisierten Sprachen macht das Gleiche. Ihr Funktionsaufruf gibt ein
object
oder zurücknull
.Aber es ist nur ein kurzer Schritt, um zu sagen, "Ich werde dies verwenden, um ein Fabrikmuster zu erstellen " und entweder
foo
oderbar
oderbaz
je nach Stimmung der Funktion zurückzukehren. Das Debuggen wird zu einem Albtraum, wenn der Anrufer dies erwartet, esfoo
aber erhalten hatbar
.Ich glaube also nicht, dass Sie aufgeschlossen sind. Sie sind in Bezug auf die Verwendung der Sprachfunktionen entsprechend vorsichtig.
Offenlegung: Mein Hintergrund liegt in statisch typisierten Sprachen vor, und ich habe im Allgemeinen in größeren, unterschiedlichen Teams gearbeitet, in denen ein relativ hoher Bedarf an wartbarem Code bestand. Meine Perspektive ist also wahrscheinlich auch verzerrt.
quelle
Wenn Sie Generics in Java verwenden, können Sie einen anderen Typ zurückgeben, ohne die statische Typensicherheit zu beeinträchtigen. Sie geben einfach den Typ an, den Sie im generischen Typparameter des Funktionsaufrufs zurückgeben möchten.
Ob Sie einen ähnlichen Ansatz in Javascript verwenden könnten, ist natürlich eine offene Frage. Da Javascript eine dynamisch typisierte Sprache ist,
object
erscheint es naheliegend, eine zurückzugeben.Wenn Sie wissen möchten, wo ein dynamisches Rückgabeszenario funktionieren kann, wenn Sie an die Arbeit in statisch typisierter Sprache gewöhnt sind, sollten Sie sich das
dynamic
Schlüsselwort in C # ansehen. Rob Conery konnte mit dem Schlüsselwort erfolgreich einen objektrelationalen Mapper in 400 Codezeilen schreibendynamic
.Natürlich ist alles, was
dynamic
wirklich getan wird, eineobject
Variable mit einer gewissen Laufzeitsicherheit zu verpacken .quelle
Ich denke, es ist eine schlechte Idee, verschiedene Typen unter bestimmten Bedingungen zurückzugeben. Eine der für mich häufig vorkommenden Möglichkeiten ist, ob die Funktion einen oder mehrere Werte zurückgeben kann. Wenn nur ein Wert zurückgegeben werden muss, kann es sinnvoll sein, den Wert nur zurückzugeben, anstatt ihn in ein Array zu packen, um zu vermeiden, dass er in der aufrufenden Funktion entpackt werden muss. In diesem (und den meisten anderen Fällen) ist der Anrufer jedoch verpflichtet, beide Typen zu unterscheiden und zu behandeln. Die Funktion ist einfacher zu überlegen, wenn immer derselbe Typ zurückgegeben wird.
quelle
Die "schlechte Praxis" besteht unabhängig davon, ob Ihre Sprache statisch geschrieben ist. Die statische Sprache lenkt Sie eher von diesen Praktiken ab, und möglicherweise finden Sie mehr Benutzer, die sich über "schlechte Praktiken" in einer statischen Sprache beschweren, da es sich um eine formalere Sprache handelt. Die zugrunde liegenden Probleme liegen jedoch in einer dynamischen Sprache vor, und Sie können bestimmen, ob sie gerechtfertigt sind.
Hier ist der unangenehme Teil dessen, was Sie vorschlagen. Wenn ich nicht weiß, welcher Typ zurückgegeben wird, kann ich den Rückgabewert nicht sofort verwenden. Ich muss etwas "entdecken".
Oft ist diese Art der Codeumschaltung einfach eine schlechte Übung. Dies erschwert das Lesen des Codes. In diesem Beispiel sehen Sie, warum das Auslösen und Abfangen von Ausnahmefällen beliebt ist. Anders ausgedrückt: Wenn Ihre Funktion nicht das tun kann, was sie sagt, sollte sie nicht erfolgreich zurückkehren . Wenn ich Ihre Funktion aufrufe, möchte ich Folgendes tun:
Da die erste Zeile erfolgreich zurückgegeben wird, gehe ich davon aus, dass sie
total
tatsächlich die Summe des Arrays enthält. Wenn es nicht erfolgreich zurückkehrt, springen wir zu einer anderen Seite meines Programms.Lassen Sie uns ein anderes Beispiel verwenden, das sich nicht nur mit der Verbreitung von Fehlern befasst. Vielleicht versucht sum_of_array, schlau zu sein und in einigen Fällen eine von Menschen lesbare Zeichenfolge zurückzugeben, wie "Das ist meine Schließfachkombination!" genau dann, wenn das Array [11,7,19] ist. Mir fällt es schwer, ein gutes Beispiel zu finden. Auf jeden Fall gilt das gleiche Problem. Sie müssen den Rückgabewert überprüfen, bevor Sie etwas damit anfangen können:
Sie könnten argumentieren, dass es nützlich wäre, wenn die Funktion eine Ganzzahl oder einen Gleitkomma zurückgibt, zB:
Für Sie sind diese Ergebnisse jedoch keine unterschiedlichen Typen. Sie werden beide als Zahlen behandeln, und das ist alles, was Sie interessiert. Sum_of_array gibt also den Nummerntyp zurück. Darum geht es beim Polymorphismus.
Es gibt also einige Vorgehensweisen, gegen die Sie möglicherweise verstoßen, wenn Ihre Funktion mehrere Typen zurückgeben kann. Wenn Sie diese kennen, können Sie feststellen, ob Ihre bestimmte Funktion ohnehin mehrere Typen zurückgeben soll.
quelle
Tatsächlich ist es nicht sehr ungewöhnlich, unterschiedliche Typen auch in einer statisch typisierten Sprache zurückzugeben. Deshalb haben wir zum Beispiel Gewerkschaftstypen.
Tatsächlich geben Methoden in Java fast immer einen von vier Typen zurück: eine Art Objekt
null
oder eine Ausnahme oder sie geben überhaupt nichts zurück.In vielen Sprachen werden Fehlerzustände als Unterprogramme modelliert, die entweder einen Ergebnistyp oder einen Fehlertyp zurückgeben. Zum Beispiel in Scala:
Das ist natürlich ein dummes Beispiel. Der Rückgabetyp bedeutet "entweder eine Zeichenfolge oder eine Dezimalzahl zurückgeben". Konventionell ist der linke Typ der Fehlertyp (in diesem Fall eine Zeichenfolge mit der Fehlermeldung) und der rechte Typ der Ergebnistyp.
Dies ähnelt Ausnahmen, mit der Ausnahme, dass Ausnahmen auch Kontrollflusskonstrukte sind. Sie sind in der Tat gleichbedeutend mit
GOTO
.quelle
Unit
(eine Methode ist überhaupt nicht erforderlich, um zurückzukehren). Sie verwenden dasreturn
Schlüsselwort zwar nicht wirklich , aber es ist ein Ergebnis, das dennoch von der Methode stammt. Mit überprüften Ausnahmen wird dies sogar explizit in der Typensignatur erwähnt.GOTO
tatsächlich gleich in der Ausdruckskraft zu ).Es gibt noch keine Antwort auf die SOLID-Prinzipien. Insbesondere sollten Sie dem Liskov-Substitutionsprinzip folgen, dass jede Klasse, die einen anderen als den erwarteten Typ empfängt, mit allem, was sie erhalten, arbeiten kann, ohne zu testen, welcher Typ zurückgegeben wird.
Wenn Sie also ein paar zusätzliche Eigenschaften auf ein Objekt werfen oder eine zurückgegebene Funktion mit einer Art Dekorator umschließen, der immer noch das leistet, was die ursprüngliche Funktion erreichen soll, sind Sie gut, solange sich kein Code, der Ihre Funktion aufruft, jemals darauf stützt Verhalten in einem beliebigen Codepfad.
Anstatt einen String oder eine Ganzzahl zurückzugeben, könnte ein besseres Beispiel darin bestehen, ein Sprinklersystem oder eine Katze zurückzugeben. Dies ist in Ordnung, wenn der aufrufende Code nur functionInQuestion.hiss () aufruft. Tatsächlich haben Sie eine implizite Schnittstelle, die der aufrufende Code erwartet, und eine dynamisch typisierte Sprache wird Sie nicht zwingen, die Schnittstelle explizit zu machen.
Leider werden Ihre Mitarbeiter dies wahrscheinlich tun, sodass Sie wahrscheinlich in Ihrer Dokumentation die gleiche Arbeit ausführen müssen, es sei denn, es gibt keine allgemein akzeptierte, knappe und maschinenanalysierbare Methode, wie dies bei der Definition einer Schnittstelle der Fall ist in einer Sprache, die sie hat.
quelle
Der eine Ort, an dem ich sehe, dass ich verschiedene Typen sende, ist für ungültige Eingaben oder "Ausnahmen für schlechte Leute", bei denen die "außergewöhnliche" Bedingung nicht sehr außergewöhnlich ist. Zum Beispiel aus meinem Repository von PHP-Utility-Funktionen dieses verkürzte Beispiel:
Die Funktion gibt nominal ein BOOLEAN zurück, bei ungültiger Eingabe jedoch NULL. Beachten Sie, dass sich seit PHP 5.3 alle internen PHP-Funktionen auch so verhalten . Zusätzlich geben einige interne PHP-Funktionen bei nominaler Eingabe FALSE oder INT zurück, siehe:
quelle
null
(a) dass sie laut ausfällt , sodass sie eher in der Entwicklungs- / Testphase behoben wird, (b) dass sie einfach zu handhaben ist, da ich alle seltenen / unerwarteten Ausnahmen ein einziges Mal abfangen kann meine gesamte Anwendung (in meinem Front-Controller) und logge sie einfach ein (normalerweise sende ich E-Mails an das Entwicklerteam), damit sie später behoben werden kann. Und ich hasse es tatsächlich, dass die Standard-PHP-Bibliothek meistens den "return null" -Ansatz verwendet - das macht PHP-Code wirklich fehleranfälliger, es sei denn, Sie überprüfen alles mitisset()
, was einfach zu viel Belastung ist.null
auf einen Fehler zurückkommen , machen Sie dies bitte in einem Dokumentblock (z. B.@return boolean|null
) deutlich. Wenn ich also eines Tages auf Ihren Code stoße , müsste ich den Funktions- / Methodenkörper nicht überprüfen.Ich halte das nicht für eine schlechte Idee! Im Gegensatz zu dieser gängigsten Meinung und wie bereits von Robert Harvey hervorgehoben, haben statisch getippte Sprachen wie Java Generics genau für Situationen wie die von Ihnen angeforderte eingeführt. Tatsächlich versucht Java (wo immer möglich), die Typensicherheit während der Kompilierung beizubehalten, und manchmal vermeiden Generics die Vervielfältigung von Code. Warum? Weil Sie dieselbe Methode oder dieselbe Klasse schreiben können, die unterschiedliche Typen behandelt / zurückgibt . Ich mache nur ein sehr kurzes Beispiel, um diese Idee zu zeigen:
Java 1.4
Java 1.5+
In einer dynamischen typisierten Sprache können Sie, da Sie zur Kompilierungszeit keine Typensicherheit haben, den Code schreiben, der für viele Typen funktioniert. Da auch in einer statisch typisierten Sprache Generics eingeführt wurden, um dieses Problem zu lösen, ist es eindeutig ein Hinweis darauf, dass das Schreiben einer Funktion, die verschiedene Typen in einer dynamischen Sprache zurückgibt, keine schlechte Idee ist.
quelle
Die Entwicklung von Software ist im Grunde eine Kunst und ein Handwerk, um mit Komplexität umzugehen. Sie versuchen, das System an den Punkten einzugrenzen, die Sie sich leisten können, und die Optionen an anderen Punkten einzuschränken. Die Schnittstelle der Funktion ist ein Vertrag, mit dessen Hilfe die Komplexität des Codes verwaltet werden kann, indem das für die Arbeit mit einem Code erforderliche Wissen begrenzt wird. Durch die Rückgabe verschiedener Typen erweitern Sie die Schnittstelle der Funktion erheblich, indem Sie alle von Ihnen zurückgegebenen Schnittstellen verschiedener Typen hinzufügen UND nicht offensichtliche Regeln hinzufügen, welche Schnittstelle zurückgegeben wird.
quelle
Perl verwendet dies häufig, da die Funktionsweise von seinem Kontext abhängt . Beispielsweise kann eine Funktion ein Array zurückgeben, wenn sie im Listenkontext verwendet wird, oder die Länge des Arrays, wenn sie an einer Stelle verwendet wird, an der ein skalarer Wert erwartet wird. Aus dem Tutorial, das der erste Treffer für "Perl-Kontext" ist , wenn Sie Folgendes tun:
Dann ist @now eine Array-Variable (das bedeutet @) und enthält ein Array wie (40, 51, 20, 9, 0, 109, 5, 8, 0).
Wenn Sie die Funktion stattdessen so aufrufen, dass das Ergebnis ein Skalar sein muss, mit ($ -Variablen sind Skalare):
dann macht es etwas ganz anderes: $ now wird so etwas wie "Fri Jan 9 20:51:40 2009".
Ein weiteres Beispiel ist die Implementierung von REST-APIs, bei denen das Format der zurückgegebenen Daten von den Anforderungen des Clients abhängt. ZB HTML oder JSON oder XML. Obwohl dies technisch gesehen alles Ströme von Bytes sind, ist die Idee ähnlich.
quelle
String
. Jetzt werden Unterlagen zum Rückgabetyp angefordert. Die Java-Tools können es automatisch generieren, wenn ich eine Klasse zurückgebe, aber da ich ausgewähltString
habe, kann ich die Dokumentation nicht automatisch generieren. Im Nachhinein / Moral der Geschichte wünschte ich, ich hätte einen Typ pro Methode zurückgegeben.Im dynamischen Land dreht sich alles um das Tippen von Enten. Am verantwortungsvollsten ist es, potenziell unterschiedliche Typen in einen Wrapper zu packen, der ihnen dieselbe Schnittstelle bietet.
Es mag gelegentlich sinnvoll sein, verschiedene Typen ganz ohne generischen Wrapper auszugeben, aber im siebten Jahr des Schreibens von JS habe ich es nicht für sinnvoll oder zweckmäßig befunden, dies sehr oft zu tun. Meistens würde ich das in geschlossenen Umgebungen tun, wie im Inneren eines Objekts, in dem Dinge zusammengefügt werden. Aber es ist nicht etwas, was ich oft genug getan habe, um Beispiele in den Sinn zu bringen.
Meistens würde ich raten, dass Sie aufhören, so viel über Typen nachzudenken. Sie beschäftigen sich mit Typen, wenn Sie eine dynamische Sprache benötigen. Nicht mehr. Es ist der springende Punkt. Überprüfen Sie nicht die Art jedes einzelnen Arguments. Das ist etwas, zu dem ich nur in einer Umgebung versucht wäre, in der die gleiche Methode auf nicht offensichtliche Weise inkonsistente Ergebnisse liefern könnte (also definitiv nicht so etwas tun). Aber es ist nicht der Typ, auf den es ankommt, sondern wie das, was du mir gibst, funktioniert.
quelle