Why you should avoid Linked Lists

Performance durch Einsatz von Assembler, PHP oder JS ist (je nach Einstellung) nicht akzeptabel,
Performance durch GC-Mühsal ist nicht akzeptabel,
Performance durch Achten auf ordentliche Datenstrukturen wie ArrayList, Set & Co. in einem sauberen OO-Programm ist akzeptabel,

wenn dann jemand darauf hinweist dass es anders, wie von dir am Anfang schon als mögliche Konsquenz angedeutet ganz ohne OO-Ebene,
viel schneller ginge, ist das leicht zu akzeptieren aber begründet darauf zu verzichten

mag gerne sein dass Funktionalität genug bietet, um auch über evtl. Nachteile bei Head-Tail-Listen hinwegzusehen,
aber genauso ist die Nennung der Fakten zu akzeptieren, dass Head-Tail-Listen auf dem hohen Level der Datenstrukturen für sich gravierende Performance-Bedenken haben


diese Parallelisierung könnte man genauso mit zustandsbehafteten Listen in der jeweiligen internen Verarbeitung haben, ist ja auch nicht verboten sie teils explizit einzusetzen,

eine Verrechnung dieses denkbaren Vorteils gegenüber des realen Nachteils der Listen-Kopien verbietet sich eher, unabhängig voneinander zwei Punkte

GC ist im Grunde keine Eigenschaft der Sprache, sondern der Plattform und betrifft damit auch funktionale Sprachen die auf der JVM laufen.

Node.JS ist „gross“ (lmao) aus demselben grund weswegen auch Ruby „gross“ ist, time to market und for allem: Hype

Wenn man Richtung SaaS geht, also „Cloud macht“, kann es schon schnell passieren das man nur 2 virtuelle Kerne pro VM hat, und manchmal muss man auch die auch noch teilen…

IMHO hat man in den seltensten Faellen keine bzw. weniger Einschraenkungen nur weil man funktionale anstatt OO entwickelt, DBs und andere ressourcen muessen nunmal geteilt werden.

Verdammt, jetzt diskutiere ich schon wieder um OO vs. Funktional, alles SlaterBs Schuld :slight_smile:

Irgendwie vermisse ich benchmarks fuer reale probleme, dafuer lese ich hypothesen fuer synthesische Probleme welche Religion… aehm Sprache schneller ist.

Ja eben, und da der GC den wohl groessten Effekt auf die Laufzeit und Resourcenverhalten hat, kommt der relevanteste Performancegewinn eben dadurch, den GC abzuschalten (wenns geht) oder auszutricksen (int statt ArrayList).

Sicher, Hype spielt da immer eine grosse Rolle. Aber ganz ohne irgendwelche neuen, coolen oder interessanten Ideen oder Konzepte wuerde so eine „neue“ (oder neu gemachte, wie auch immer) Technologie auch keinen Hype erfahren.

Bei Ruby war das Ruby on Rails mit dem Grundsatz ‚Convention over Configuration‘. Das haben alle wichtigen Frameworks (egal welche Sprache) uebernommen.
Bei Node.Js ist das die Idee, alles asynchron ablaufen zu lassen - so dass Request 2 bereits verarbeitet werden kann, waehrend die Abarbeitung von Request 1 noch auf ein Ergebnis einer DB-Abfrage wartet (non blocking). Um sowas umzusetzen, ist funktionaler Code (genauer: pure functions) extrem hilfreich.

Also fuer mich bedeutet „Cloud“, dass ich mir in maximal 1 Minute 20 neue Rechnerinstanzen erzeugen lassen kann, die dann Spitzenlast abfangen.

Das ist auch schwierig, weil man kaum eine exakt gleiche Anwendung mehrfach implementieren wuerde (funktional, oop, c) um irgendwelche Benchmarks zu fahren. Wichtig ist aber schon, mal moeglichst alle Konzepte nicht nur gehoert oder gesehen zu haben - sondern auch mal programmiert zu haben. Einfach um zu wissen, wann, welches Konzept geeignet ist.

Auch das kommt auf den Anwendungsfall an.

Dynamische Sprachen haben theoretisch auf einen grossen Nachteil gegenueber statischen, macht in der Realitaet dann nicht immer einen merklichen Unterschied… Laufzeitperformanz ist ein Aspekt, Entwicklungsgeschwindigkeit eine andere.

… oder einfach nur Marketing (das man aberwitzigen Summen finanziert wird) um alte Kamellen als Innovation zu vertickern.

[quote=schalentier;132546]Bei Ruby war das Ruby on Rails mit dem Grundsatz ‚Convention over Configuration‘. Das haben alle wichtigen Frameworks (egal welche Sprache) uebernommen.
Bei Node.Js ist das die Idee, alles asynchron ablaufen zu lassen - so dass Request 2 bereits verarbeitet werden kann, waehrend die Abarbeitung von Request 1 noch auf ein Ergebnis einer DB-Abfrage wartet (non blocking). Um sowas umzusetzen, ist funktionaler Code (genauer: pure functions) extrem hilfreich.[/quote]
Konventionen, mehrere Requests auf einmal zu verarbeiten… hm… Frameworks, und dann sowas wie FastCGI? :smiley:

Nicht falsch verstehen, sind alles gute Dinge, aber keinesfalls neue Innovationen.
Das funktionale Sprachen weniger Probleme haben weil Zustaende und damit zeitliche Abhaengigkeiten zum Grossenteil vermieden werden koennen ist kein Geheimnis, aber Lesbarkeit und Wartbarkeit bieten auch viel wenn es darum geht Probleme zu vermeiden, sogar langfristig.
Nur weil es funktional ist ist keine Garantie dass es wirklich parallelisierbar ist.

PaaS, klar, je nachdem was man wie provisionieren laesst sind 60 sekunden moeglich, unmoeglich oder irrelevant, AWS schafft das IME nicht, ausser natuerlich man haelt sich laufende Instanzen vor :wink:
Oder sind das keine „echten“ Rechnerinstanzen sondern „nur“ Container wie Docker und Konsorten?
BigData mit Hadoop zu crunchen wird auch als „Cloud“ bezeichnet, aber da gibt es meist keine VMs, ist echtes Blech weil IO da wichtig ist.
Der Kellner im Cafe um die Ecke hat seine Tittenbilder in der „Cloud“ weil er damit sowohl vom Handy als auch von seinem Rechner inspiration findet um an sich rumzuspielen… :smiley:

Absolut, lernen schadet nicht, jammern hilft nicht, Dinge die man nicht kennt/versteht machen einem Angst…

Beweisst man diese theoretischen Vorteile eigentlich, mit Benchmark und anderen Messungen?

Falls ja, und man gar keine Vergleichsmoeglichkeiten hat, ist es dann nur Glaube der einen von den Vorteilen „ueberzeugt“?
Wann weiss man ob man nur einem Marketing Gag auf den Leim gegangen ist?

Es waere nicht so schwer in Java eine mittelgrosse Anwendung von ArrayList auf LinkedList umzustellen, einfach mal so, um zu messen um wieviel schneller der User seine Fehleingabe angezeigt bekommt …

Ist das eigentlich wichtig, solange man Freude daran hat in Sprache X mit dem Paradigma Y zu arbeiten, seine Kollegen/Vorgesetzten davon ueberzeugen kann um dass dann auch durchzuziehen?
Fast alle gehypten Dinge verschwinden ganz schnell wieder vom IT Olymp, der Code bleibt, falls das Produkt bzw. die Firma erfolgreich ist, ist dann alles „Legacy“ :wink:

Das ist ja dann doch etwas ausdifferenzierter geworden. Viel schreibe ich dann jetzt heute auch nicht mehr (nachdem ich heute auf der parallelcon war (der einzige hier?) - obwohl das eigentlich zum Thema passt). Ich habe nur gerade mal schnell einen Test hingepfuscht, der BILLIGST-plakativ und ohne den Anspruch, irgendeine Aussage zu bestätigen … SlaterB’s Aussagen bestätigt :smiley: Nee, mal im Ernst, ich war gerade (speziell nach dem hier) neugierig, wie javaslang bei irgendeinem (ja, nochmal: sinnlosen) dummy-Workload so abschneidet…:

package bytewelt;

import java.util.Random;


public class SlangListTest
{
    private static final int RUNS = 10;

    public static void main(String[] args)
    {
        for (int n=10; n<=10000; n*=10)
        {
            javaslang.collection.List<String> listSlang =  
                javaslang.collection.List.empty();
            testSlang(listSlang, n);

            java.util.List<String> arrayListJava =  
                new java.util.ArrayList<String>();
            testJava("Array", arrayListJava, n);

            java.util.List<String> linkedListJava =  
                new java.util.LinkedList<String>();
            testJava("Linked", linkedListJava, n);
        }
    }
    
    private static void testSlang(javaslang.collection.List<String> list, int n)
    {
        long before = 0;
        long after = 0;
        
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n; i++)
            {
                String s = String.valueOf(i);
                list = list.append(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%10s %8d create took %10.3f
",
            "slang", n, (after-before) / 1e6);
        
        Random random = new Random(0);
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n/2; i++)
            {
                String s = String.valueOf(random.nextInt(n));
                list.remove(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%10s %8d remove took %10.3f
",
            "slang", n, (after-before) / 1e6);
    }
    
    private static void testJava(String name, java.util.List<String> list, int n)
    {
        long before = 0;
        long after = 0;
        
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n; i++)
            {
                String s = String.valueOf(i);
                list.add(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%10s %8d create took %10.3f
",
            name, n, (after-before) / 1e6);
        
        Random random = new Random(0);
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n/2; i++)
            {
                String s = String.valueOf(random.nextInt(n));
                list.remove(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%10s %8d remove took %10.3f
",
            name, n, (after-before) / 1e6);
    }
}

     slang       10 create took     80,144
     slang       10 remove took      0,348
     Array       10 create took      0,102
     Array       10 remove took      0,178
    Linked       10 create took      0,107
    Linked       10 remove took      0,126
     slang      100 create took     42,383
     slang      100 remove took      5,210
     Array      100 create took      0,234
     Array      100 remove took      2,105
    Linked      100 create took      0,842
    Linked      100 remove took      1,488
     slang     1000 create took   1556,000
     slang     1000 remove took     79,105
     Array     1000 create took      1,033
     Array     1000 remove took     36,790
    Linked     1000 create took      0,982
    Linked     1000 remove took     36,279
     slang    10000 create took 218327,981
     slang    10000 remove took   5774,545
     Array    10000 create took      6,886
     Array    10000 remove took   5832,525
    Linked    10000 create took      9,431
    Linked    10000 remove took   8999,439

(Ja, das sagt erstmal nicht viel aus. Für einen „richtigen“ oder „besseren“ Benchmark (ggf. mit JMH) fehlt mir gerade die Zeit. Aber die 218 Sekunden (im Vergleich zu 6 Millisekunden) sind schonmal ne Hausnummer).
(Ich rechne aber damit, dass mich morgen jemand auf einen peinlichen Fehler aufmerksam macht, der das verursacht, und den ich jetzt schonmal Präventiv auf meine Übermüdung schiebe :smiley: )

Du könntest fairerweise die Slang-Liste von vorn befüllen, hinten anhängen muss ja mindestens quadratische Komplexität haben.

Bevor gleich wieder aus bekannter Richtung die Blutgrätsche kommt: Wenn man eine Datenstruktur braucht, die an beiden Enden gute Zeiten liefern, kann man zwei dieser Listen mit den “Hintern” aneinanderkleben (Banker’s Queue). Wenn nur an einer Region - egal wo - eingefügt werden soll, kommt auch ein Zipper (wieder zwei Listen, nur diesmal mit dem “Gesicht” zueinander) in Betracht. Und wenn man wahlfreien Zugriff braucht, sind persistente Listen einfach die falsche Datenstruktur.

und warum sollte man so fair sein, so fair sein müssen?
welche Grundkonstante der Programmierung spricht davon, ausgerechnet neue Elemente irgendwo vorne anzufügen?
das ist so abwegig, schon erstaunlich,

selbst der modernste filter-map-Stream liefert am Ende seine Ergebnisliste sicher in richtiger Reihenfolge, erste Ergebnisse am Anfang, weitere hinten dran,
man kann wohl vom Glück sagen dass die interne Programmierung so unnatürlich effizient ist, die Liste erst andersrum zu bauen und am Ende umzudrehen

jedem Programmierer wird der normale Umgang mit Listen verwehrt,

edit: das passt zumindest zum Gedanken, alle Schleifen, alle normalen Arbeiten zu eliminieren,
es gibt nur Streams, sonst nix, man könnte es ja falsch machen…


eine ArrayList wäre freilich andersrum genauso quadratisch langsamer, würde man alles vorne einfügen,
aber dazu kommt man doch eher selten, widerspricht etwa einer Befüllung eines noch natürlicheren Arrays oder allem in der realen Welt (Buch-Seiten usw.),
mit add(0,element) statt dem normalen add(element) auch ein wenig davor geschützt, die normale Methode ist die effiziente,

bei der Slang-Liste hat man sich halb davor gedrückt, append() und prepend() sind gleichwertig,
aber damit eigentlich immer noch unverantwortlich, besser append() in appendAreYourCrazySerious() umbenennen :wink:

benutzt man eine solche Liste auf die natürliche Weise mit append(), dann Desaster, wie kann man das der Welt zumuten?

das endgültige Urteil :stuck_out_tongue:
und diese Liste ist der empfohlende Standard…

War ja sooo klar. Falls du auf Scala anspielst: Dort ist die “empfohlene” Vorgehensweise für das Anfügen am Ende, entweder dafür einmal einen ListBuffer zu verwenden, und diesen dann für die Weiterarbeit in eine Liste umzuwandeln, oder - wenn man immer hinten einfügen muss - eine Datenstruktur wie Dequeue zu nutzen.

Es ist einfach so, dass man die Tools kennen muss, mit denen man arbeitet, dass ist in Java nichts anders: Wo wird da davor gewarnt, bei einer LinkedList in der Mitte einzufügen, oder in einer ArrayList fortlaufend am Anfang? Das kommt dir nur deshalb nicht komisch vor, weil du es gewöhnt bist. Mit deiner Einschätzung bist du also sehr wohl “unfair”, weil du das einfach als “gegeben” voraussetzt, dich aber nicht einen Millimeter auf die andere Funktionalität einlassen willst. Wenn du damit nicht arbeiten willst, lass es doch einfach, aber versuche nicht, etwas schlecht zu machen, von dem du entweder wirklich keine Ahnung hast, oder dich absichtlich so dumm stellst, dass nur Blödsinn herauskommen kann.

Nun, man kann natürlich eine

halbherzige Erweiterung
[spoiler]

package bytewelt;
 
import java.util.Random;
 
 
public class SlangListTest2
{
    private static final int RUNS = 10;
 
    public static void main(String[] args)
    {
        for (int n=10; n<=10000; n*=10)
        {
            javaslang.collection.List<String> listSlangA =  
                javaslang.collection.List.empty();
            testSlangFront(listSlangA, n);

            javaslang.collection.List<String> listSlangB =  
                javaslang.collection.List.empty();
            testSlangBack(listSlangB, n);
            
            java.util.List<String> arrayListJavaA =  
                new java.util.ArrayList<String>();
            testJavaFront("Array front", arrayListJavaA, n);
 
            java.util.List<String> arrayListJavaB =  
                new java.util.ArrayList<String>();
            testJavaBack("Array back", arrayListJavaB, n);
 
            java.util.List<String> linkedListJavaA =  
                new java.util.LinkedList<String>();
            testJavaFront("Linked front", linkedListJavaA, n);

            java.util.List<String> linkedListJava =  
                new java.util.LinkedList<String>();
            testJavaBack("Linked back", linkedListJava, n);
        }
    }
   
    private static void testSlangFront(javaslang.collection.List<String> list, int n)
    {
        long before = 0;
        long after = 0;
       
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n; i++)
            {
                String s = String.valueOf(i);
                list = list.prepend(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%16s %8d create took %10.3f
",
            "slang front", n, (after-before) / 1e6);
       
        Random random = new Random(0);
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n/2; i++)
            {
                String s = String.valueOf(random.nextInt(n));
                list.remove(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%16s %8d remove took %10.3f
",
            "slang front", n, (after-before) / 1e6);
    }
   
    private static void testSlangBack(javaslang.collection.List<String> list, int n)
    {
        long before = 0;
        long after = 0;
       
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n; i++)
            {
                String s = String.valueOf(i);
                list = list.append(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%16s %8d create took %10.3f
",
            "slang back", n, (after-before) / 1e6);
       
        Random random = new Random(0);
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n/2; i++)
            {
                String s = String.valueOf(random.nextInt(n));
                list.remove(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%16s %8d remove took %10.3f
",
            "slang back", n, (after-before) / 1e6);
    }
   
    private static void testJavaFront(String name, java.util.List<String> list, int n)
    {
        long before = 0;
        long after = 0;
       
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n; i++)
            {
                String s = String.valueOf(i);
                list.add(0, s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%16s %8d create took %10.3f
",
            name, n, (after-before) / 1e6);
       
        Random random = new Random(0);
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n/2; i++)
            {
                String s = String.valueOf(random.nextInt(n));
                list.remove(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%16s %8d remove took %10.3f
",
            name, n, (after-before) / 1e6);
    }
    
    private static void testJavaBack(String name, java.util.List<String> list, int n)
    {
        long before = 0;
        long after = 0;
       
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n; i++)
            {
                String s = String.valueOf(i);
                list.add(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%16s %8d create took %10.3f
",
            name, n, (after-before) / 1e6);
       
        Random random = new Random(0);
        before = System.nanoTime();
        for (int r=0; r<RUNS; r++)
        {
            for (int i=0; i<n/2; i++)
            {
                String s = String.valueOf(random.nextInt(n));
                list.remove(s);
            }
        }
        after = System.nanoTime();
        System.out.printf("%16s %8d remove took %10.3f
",
            name, n, (after-before) / 1e6);
    }
    
}

[/spoiler]

vornehmen, um dann


     slang front       10 create took      3,402
     slang front       10 remove took     26,428
      slang back       10 create took     43,220
      slang back       10 remove took      0,176
     Array front       10 create took      0,165
     Array front       10 remove took      0,096
      Array back       10 create took      0,021
      Array back       10 remove took      0,064
    Linked front       10 create took      0,058
    Linked front       10 remove took      0,074
     Linked back       10 create took      0,032
     Linked back       10 remove took      0,057
     slang front      100 create took      1,396
     slang front      100 remove took      4,191
      slang back      100 create took     43,064
      slang back      100 remove took      3,701
     Array front      100 create took      0,603
     Array front      100 remove took      1,542
      Array back      100 create took      0,190
      Array back      100 remove took      1,342
    Linked front      100 create took      0,487
    Linked front      100 remove took      3,238
     Linked back      100 create took      0,291
     Linked back      100 remove took      1,183
     slang front     1000 create took      1,866
     slang front     1000 remove took     56,783
      slang back     1000 create took   1273,141
      slang back     1000 remove took     33,671
     Array front     1000 create took      5,008
     Array front     1000 remove took     20,266
      Array back     1000 create took      0,709
      Array back     1000 remove took     18,366
    Linked front     1000 create took      0,841
    Linked front     1000 remove took     26,185
     Linked back     1000 create took      0,713
     Linked back     1000 remove took     23,861
     slang front    10000 create took      6,546
     slang front    10000 remove took   3717,308
      slang back    10000 create took  94599,650
      slang back    10000 remove took   3471,409
     Array front    10000 create took    615,936
     Array front    10000 remove took   1994,952
      Array back    10000 create took      4,744
      Array back    10000 remove took   2101,244
    Linked front    10000 create took      3,398
    Linked front    10000 remove took   2654,178
     Linked back    10000 create took      6,606
     Linked back    10000 remove took   2675,041

zu erhalten, aber nochmal: DAS SOLLTE MAN NICHT ZU ERNST NEHMEN (ist ja eine ziemlich sinnlose Zusammenwürfelung von Operationen), und am Ende ist auch nicht klar, was genau damit gezeigt werden soll. Mehr als “Man sollte die richtige Datenstruktur für die jeweilige Aufgabe verwenden” kann man daraus im Endeffekt nicht ablesen. (BTW: Es gibt einen Benchmark unter https://github.com/javaslang/javaslang/blob/master/javaslang-benchmark/src/test/java/javaslang/benchmark/MicroBenchmark.java , aber keinen Vergleich mit anderen Listen - wäre vielleicht mal eine Überlegung wert). Ich denke, es gibt durchaus Rechtfertigungen für immutable/persistente Datenstrukturen, darüber wurde ja schon an anderen Stellen ausführlich geredet.

@Landei
bemerkst du wie du unentwegt persönliche Beleidigungen wie ‚keine Ahnung‘, ‚absichtlich so dumm stellst‘ postest?
da hier der Inhalt die Lächerlichkeit dieser Aussagen überdeutlich macht, macht es mir mal nichts aus, aber schon erstaunlich wie du dich selber darstellst…,

ich beschreibe wie immer recht objektiv Tatsachen oder zumindest gedachte Umstände, das ein oder andere mal auch falsch :wink: , zur evtl. Korrektur ja das Forum da,
und wenn ich dabei gleichzeitig vor den Gefahren warne und Empfehlungen dazu, also allgemeine Dinge in der Welt, ‚schlecht mache‘,
ist das nichts schlimmes, betrifft niemanden direkt


StringBuilder für einen String, eine große zusammenhängende Zeichenkette ist eine Sache (eine weitere von vielen, die man natürlich hauptsächlich mit append() hinten nutzt),
aber für eine Liste, bewußt modular aufgebaute Datenstruktur, einen Builder zu verwenden statt append(). nach append()-Aufruf,
ist einfach unrealistisch, warum überhaupt erst solche Vorschläge?
jedenfalls nicht im Ton der einfachen Möglichkeit, im Bedauern der Notwendigkeit/ Alternativlosigkeit ginge es ja noch

entweder häufig benötigt, dann häufiger Ärger,
oder selten benötigt, dann böse Gefahr des Vergessens


Datenstrukturen bieten Gefahren, aber an eine Liste hinten dranzufügen ist keine Gewöhnungssache, sondern die Normalität,
in allen seriösen Programmiersprachen sowieso, aber selbst Funktionalität kommt an sich nicht drumherum:
wie gesagt sammelt etwa ein Stream (oder auch quasi alles andere) seine Ergebnisse logisch betracht in Reihenfolge,
würde Liste append() hinten gestatten würde das intern mit Freude verwendet werden

nur durch große Designschwäche ist Stream dazu gezwungen, die Ergebnisliste falschrum aufzubauen und am Ende umzudrehen,
man kann dies für andere Vorteile knirschend akzeptieren, aber für sich betrachtet ist das doch Wahnsinn

jeder ist gewöhnt, an eine Liste hinten dranzufügen, vor allen Zeiten, aktuell und in allen Zeiten, das bleibt immer so,
edit: es heißt immer noch List und nicht Stack! man könnte es ja umbenennen…

Nein, das is einfach Unsinn. Es gibt LIFO und FIFO Listen und man sollte eine fuer den Anwendungsfall passende waehlen.

wenn die eine Klasse die Standardrückgabe, etwa von allgegenwärtigen Streams ist, dann ist nicht groß eigene Wahl möglich…,
und das unter der Voraussetzung, dass es gleichberechtigt zwei Wahlen von List gäbe,
ähnlich fair wie ArrayList vs. LinkedList in Java, wobei dort LinkedList ja noch dramatisch weniger Probleme macht

wenn dagegen List an sich nur Head-Tail ist und die Alternative(n) Richtung

gehen, dann bestände keine faire Wahl, List an sich LIFO, besetzt den Hauptnamen List,
FIFO nur mit umständlichen Alternativen…


wo braucht man LIFO-Listen? für mich besteht da kein betrachtenswertes Gleichkeit

was macht ein Stream mit einer Eingabe, die zu Ergebnis-Liste verarbeitet wird, egal wie viele filter, maps und sonstiges (außer Sortierung) dazwischen?,
er nimmt ein Ergebnis nach dem anderen (FO auf der vorherigen Datenstruktur, die wahrscheinlich auch FIFO war),
und packt dies (logisch betrachtet jedenfalls) in dieser Reihenfolge in Ergebnis-Liste, wieder FI,
der Verwender wird sicherlich auch FO betreiben, jedenfalls den Datentyp dafür gewählt, also FIFO

was macht man mit einer Liste von Kindern in einer DB-Klasse Person? ein neues Kind wird hinten angefügt, Durchlauf von vorne weg, FIFO

wie werden Suchergebnisse in der DB zusammen- und dann im Browser dargestellt? ein Weg gepflastert von FIFO-Verarbeitungen,

FIFO, FIFO über alles, fast schon FIFA-Korruption :wink:
wann kommt je LIFO real zum Einsatz?

FIFO ist das A und O und I und F, und dieser normale Haupteinsatz von Listen wird verweigert…

LIFO ist Stack, für den Normalprogrammierer vielleicht hauptsächlich von Ausbildung/ Studium bekannt, praktisch nie im Einsatz,
und dies soll der Standard sein…

(ich hätte schon lange aufgehört mich aufzuregen, mein erstes Posting war nur zwei Zeilen und alles schon gesagt, die reine Wahrheit, sogar ganz lieb formuliert:

[QUOTE=SlaterB;132338]und Funktionalität, speziell unmodifiable Head-Tail-Listen sind was davon? genau :wink:

neben all den möglichen Problemchen einer LinkedList zusätzlich auch noch der riesige Aufwand, bei mancher Änderung komplett neue Liste zu erzeugen…[/QUOTE]
aber solange unsinnige Gegenrede, solange halt immer mehr Argumente :wink: )

Eine LIFO-Liste ist ja nichts anderes als ein Stack. Und den braucht man bspw. bei jeder aufgerollten Rekursion.

Wird es nicht, du argumentierst nur mit einer speziellen Variante einer Datenstruktur die durch Verwaltung von zusätzlichen Informationen [1] in der Lage ist andere Datenstrukturen zu simulieren. Deshalb ist es eben wichtig, wenn man z.B. auf Listen in der „reinen“ funktionalen Programmierung herumreitet, zu akzeptieren das diese nur einen bestimmten Aspekt deiner speziellen Liste abdecken. Werden, im Bereich von FP, andere Charakteristika benötigt bedient man sich eben einer anderen Datenstruktur.

[1] Meistens Dummyknoten um den Anfang/Ende sofort im Zugriff zu haben.