Swift-evolution

  • Michael
    AFAIR weist einen der Static Analyzer auch darauf hin, dass das mutmaßlich fehlerbehafteter Code sein kann.
    Aber die Swift-Jungs üben ja noch. ^^

    *
    Interessant ist in dem Zusammenhang natürlich, ob es der Funktion überhaupt möglich ist festzustellen, welchen Typ Strideable in dem Moment hat (hauptsächlich: Signed/Unsigned) und ob das Vorhaben aufgehen kann. Auch scheint es mir falsch, den schrittweise Wert negativ darzustellen.

    Ich persönlich bin ja nach wie vor davon überzeugt, dass das Strideable Protokoll nicht als For-Schleifenersatz gedacht ist.
    Conforming types are notionally continuous, one-dimensional values that can be offset and measured.

    Diese Methode liefert eine Sequenz von SignedNumberTypes zurück (Deshalb die Probleme bei Unsigned?), durch die dann iteriert wird.
    Das ist laufzeit- und speichertechnisch ein ganz anderes Kaliber als eine dusselige Variable hochzuzählen und zu vergleichen. Völlig egal welche geilen Compiler-Verrenkungen der Lattner sich dafür ausgedacht hat.

    Für das schrittweise Iterieren mit einer bestimmten Anzahl von Durchläufen ist das for in Konstrukt mit den möglichen Ranges ... und ..< gedacht.
    Wer was Anderes möchte, beispielsweise nur jeden zweiten (a.k.a. geraden) Index abgreifen, muss halt sein Design entsprechend anpassen.
    • Ich habe in meinem Array Karteikarten, jeder gerade Index ist die Vorderseite mit einer Frage und jeder ungerade Index ist die Rückseite mit der dazugehörigen Antwort.
      Das Design wird noch zu viel mehr Problemen führen, denn Vorder- und Rückseite gehören zu einer einzigen Karteikarte. Also beides in ein Objekt und schon ist die Notwendigkeit des geraden Index hinfällig.
    • In einem Kartenspiel für zwei Spieler sollen die Karten gemischt vom Nachziehstapel verteilt werden. Es sollen nur nKarten mit geradem Index beim Spieler landen.
      Es bietet sich hier an, Stapel für beide Spieler anzulegen. Dann geht man immer noch Karte für Karte vom Nachziehstapel durch. Es wird halt nur an Hand des aktuellen Index, an Hand eines Flags oder weiß der Henker woran entschieden, auf welchem Spielerstapel die aktuelle Karte landet.
    • Is jetzt aber wirklich wirklich wichtig, weil...
      Typisch Apple wird diese Abweichung vom Standard mit einer Eigenimplementierung gestraft. In Anbetracht von eine Variable verändern und vergleichen vs. eine Seqenz von Werten abarbeiten sollte hier auch der härteste Swift-Evangelist die alte Bauernweiseheit beherzigen: "Eile mit while!"**

    Ich bin sicher, so lässt sich für jedes 'nur jeder n-te Index' Problem ein besseres Design finden.

    *) Everybody in the thread (ja, auch Du.)
    **) Bauern sprechen bekanntlich Fremdworte genau so aus wie sie sie lesen.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Doch, das Strideable ist dafür da.

    Siehe es so: Eine For-Schleife führt einen Body mit einer Folge von Werten aus, ganz klassisch sind das Ganzzahlen, muss es aber nicht sein. Strdieable soll eben diese Folge von Werten liefern, damit der Body damit ausgeführt werden kann. Das können nur alle möglichen Typen sein.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Michael schrieb:

    stride() muss doch eh prüfen, ob der Zielwert erreicht ist. Dann kann es ja auch gleich auf einen Overflow prüfen. Das würde ich jetzt einfach mal erwarten, wenn es denn als Ersatz dienen soll.
    Swift ist doch rasant schnell. Damit das nicht nur auf Keynote-Folien stimmt, muss man eben jeden Test einsparen.
    Da ist ja der nächste Widerspruch: Swift legt dem Programmierer nahe, aus Optimierungsgründen auf Vererbung und Überschreiben zu verzichten. An einer Generator-basierten Schleife kann ein Optimierer aber nicht mehr viel machen, weil er das Generator-Objekt nicht auseinanderpflücken kann. Der minimale Overhead für dynamische Methodenaufrufe ist anscheinend für die Swift-Entwickler kriegsentscheidender für Perfomance-Schlachten als schlecht optimierbare Schleifen.
    „Meine Komplikation hatte eine Komplikation.“
  • Jo, zum Beispiel kann er nicht einmal sehen, dass die Schleife nie ausgeführt werden kann. Doch, dann, wenn der Generator inline ist. Das bringt wieder lustige Abhängigkeiten bei der Compilierung. Ich hole mir mal nen Kaffee.

    Ich glaube aber, dort ging es um Abstraktion aus Prinzip. Wir machen es, weil es geht. Wie so häufig: Eine Programmiersprache, um den Forschungsdrang von Compilerbauern zu befriedigen. Kann man ja machen, sollte man aber dann auch sagen.

    Übrigens gehen natürlich Schleifengeneratoren auch in Objective-C. Sogar in C, wenn man Closures hinzunimmt. Man muss den Körper ja nur als Argument übergeben.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Michael schrieb:

    stride() muss doch eh prüfen, ob der Zielwert erreicht ist. Dann kann es ja auch gleich auf einen Overflow prüfen. Das würde ich jetzt einfach mal erwarten, wenn es denn als Ersatz dienen soll.
    Swift ist doch rasant schnell. Damit das nicht nur auf Keynote-Folien stimmt, muss man eben jeden Test einsparen.
    Lustigerweise ist genau das Gegenteil der Fall. Swift prüft grundsätzlich immer, ob es einen Overflow gibt. Sonst würde es ja nicht mit EXEC INVOP crashen, sondern so wie C oder Objective-C strunzdoof ad infinitum weiterzählen.

    In C:

    Quellcode

    1. for (unsigned int x = 10; x > 0; x -= 3) {
    2. printf("%u\n", x);
    3. }
    4. // output:
    5. // 10
    6. // 7
    7. // 4
    8. // 1
    9. // 4294967294
    10. // 4294967291
    11. // 4294967288
    12. // ...
    Alles anzeigen

    In Swift:

    Quellcode

    1. for var x: UInt = 10; x > 0; x -= 3 {
    2. print(x)
    3. }
    4. // output:
    5. // 10
    6. // 7
    7. // 4
    8. // 1
    9. // bang!
    Besten Falls hängt man in in C in einer Endlosschleife, bei der dann der User das tun muß, was Swift automatisch macht. Das Programm abzuschießen. Schlimmsten Falls erlaubt man den Zugriff auf falsche Speicherbereiche.

    Wenn jetzt jemand meint Overflows seien aber doch ein absolut super Feature und Swift ist einfach nur sch..., weil man da keine tollen Overflows benutzen kann, dem sei gesagt: Doch. Geht auch in Swift.

    Dafür gibt es in Swift spezielle Overflow Operatoren: &+, &- und &*

    Heißt für o.g. Beispiel:

    Quellcode

    1. for var x: UInt = 10; x > 0; x = x &- 3 {
    2. print(x)
    3. }
    4. // output:
    5. // 10
    6. // 7
    7. // 4
    8. // 1
    9. // 18446744073709551614
    10. // 18446744073709551611
    11. // 18446744073709551608
    12. // ...
    Alles anzeigen
    Overflows sind idR Fehler des Programmierers, die zu Sicherheitsproblemen führen. Swift tut hier genau das Richtige. Bis hierhin und nicht weiter. Sollte man wirklich mit Overflows arbeiten wollen, dann erlaubt es das auch.
  • Der User wird das Problem nicht sehen, weil es sofort beim Debugging auffällt. Wie häufig hast du denn Software in die Produktion geschickt, bei der eine Schleife wegen eines Overflows hing? Nullmal oder 0 Mal?

    Und ist es wirklich ein Feature von Swift, bei Overflows dem Nutzer die Last des Programmabschusses abzunehmen? Very modern!

    Darüber hinaus erzeugt das in C nicht einen Overflow. Es erzeugt ein definiertes, verwendbares Ergebnis:



    WG14/N1256 schrieb:

    A computation involving unsigned operands can never overflow,because a result that cannot be represented by the resulting unsigned integer type isreduced modulo the number that is one greater than the largest value that can berepresented by the resulting type.

    Das ist zuweilen sehr nützlich.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Amin Negm-Awad ()

  • macmoonshine schrieb:

    Wobei der Vollständigkeit halber gesagt werden sollte, dass man die Overflow-Checks ausschalten muss, um auf schnellen Laufzeiten zu kommen, mit denen Apple wirbt. Die Checks fressen Einiges an Rechenzeit.
    Stimmt. Kann man mit -Ounchecked abstellen. Habe ich selber gar nicht mehr dran gedacht. Bin bisher auch noch nicht in die Situation gekommen, das machen zu müssen.

    Nur aus reiner Neugierde. Hast Du irgendwelche Benchmarks zur Hand, die zeigen, wieviel diese Checks tatsächlich kosten?
  • Da gibt's verschiedene kleinere Benchmarks im Netz zu. Der Geschwindigkeitsunterschied ist natürlich auch sehr abhängig vom Problem. Mit folgendem Nonsense-Programm:

    Quellcode

    1. var x: Int64 = 0
    2. var g: Int = 1
    3. for var j in 0..<100 {
    4. var s: Int64 = Int64(j)
    5. for var i: Int64 in Range<Int64>(start:0, end:1000000) {
    6. s += Int64(g) * i * i
    7. g = -g
    8. }
    9. x += s
    10. }
    11. print(x)
    Alles anzeigen
    bekomme ich ungefähr einen Faktor 35 (unoptimiert) und ca. 2 (optimiert mit -O) zu -Ounchecked.
    „Meine Komplikation hatte eine Komplikation.“
  • tsunamix schrieb:

    macmoonshine schrieb:

    Wobei der Vollständigkeit halber gesagt werden sollte, dass man die Overflow-Checks ausschalten muss, um auf schnellen Laufzeiten zu kommen, mit denen Apple wirbt. Die Checks fressen Einiges an Rechenzeit.
    Stimmt. Kann man mit -Ounchecked abstellen. Habe ich selber gar nicht mehr dran gedacht. Bin bisher auch noch nicht in die Situation gekommen, das machen zu müssen.
    Nur aus reiner Neugierde. Hast Du irgendwelche Benchmarks zur Hand, die zeigen, wieviel diese Checks tatsächlich kosten?
    Natürlich kommt man wenn überhaupt nur extrem selten in diese Situation. Ist bei Obejctive-C ja nicht anders.

    Deshalb ist dieses ganze Performance-Argument auch realitätsfern. Das ist so unter "ferner liefen", dass es eigentlich überhaupt keinen Sinn macht, deshab Sprachkonzepte zu ändern. Deshalb verstehe ich auch nicht, warum man jetzt an der Vererbung "herumdoktert". (Übrigens müsste das doch der Ladezeit-Linker gut erledigen können. Der sieht ja schließlich alles.)
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Deshalb ist dieses ganze Performance-Argument auch realitätsfern. Das ist so unter "ferner liefen", dass es eigentlich überhaupt keinen Sinn macht, deshab Sprachkonzepte zu ändern.
    +exakt+

    Amin Negm-Awad schrieb:

    Deshalb verstehe ich auch nicht, warum man jetzt an der Vererbung "herumdoktert".
    Ich habe den Eindruck, dass auf solch bescheuerte Ideen nur jemand kommen kann, der entweder das Konzept nicht verstanden hat oder es nicht mag. Dass es da im Swift-Land anscheinend arge Verständnisprobleme mit der Objekt-Orientierung gibt, sieht man auch an der seltsamen Intialisierungsreihenfolge von Membervariablen und Oberklassenaufruf im Initializer.
    „Meine Komplikation hatte eine Komplikation.“
  • Nun ja, ich habe ja schon immer C++ vorgeworfen, dass das aufgrund der Statik eine zwar klassenbasierte Sprache ist, aber keine objektorientierte. Das gilt für Swift nicht anders. Statik und OOP beißen sich einfach an manchen Ecken und Enden.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Statik und OOP beißen sich einfach an manchen Ecken und Enden.
    Gut, dass einige Sachen schwerlich oder überhaupt nicht gehen, geschenkt.

    Aber diese absichtlichen Einschränkungen sind doch völlig unnötig. Selbst in C++ kann man (Stack-)Strukturen vererben. Da geht Swift ja schon fast weg von Klassen zurück zu abstrakten Datentypen.

    Und die Initialisierungsreihenfolge in Swift ist nicht besonders sinnvoll. Die Initialisierung sollte meines Erachtens immer von Innen nach Außen erfolgen, damit die äußere Klasse gefahrlos auf die Eigenschaften ihrer Oberklasse zugreifen kann.
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    Und die Initialisierungsreihenfolge in Swift ist nicht besonders sinnvoll. Die Initialisierung sollte meines Erachtens immer von Innen nach Außen erfolgen, damit die äußere Klasse gefahrlos auf die Eigenschaften ihrer Oberklasse zugreifen kann.
    Ist dies bei Swift nicht der Fall? D.h. wird immer zuerst die abgeleitete Klasse komplett initialisiert, bevor die Basisklasse initialisiert wird?

    Dann macht Final bei Default natürlich Sinn. Damit lassen sich dann die Fehler aufgrund der falschen Initialisierung ausmerzen. Somit wird Swift seinem Ziel, Fehler bei der Entwicklung zu vermeiden wieder gerecht. :D
  • MCDan schrieb:

    Ist dies bei Swift nicht der Fall? D.h. wird immer zuerst die abgeleitete Klasse komplett initialisiert, bevor die Basisklasse initialisiert wird?
    Im Prinzip ja, z. B.:

    Quellcode

    1. class A {
    2. init(i: Int) {
    3. print("A: \(i)")
    4. }
    5. }
    6. class B: A {
    7. let l: Int
    8. var v: Int
    9. init() {
    10. l = 1
    11. v = 2
    12. super.init(i: 3)
    13. }
    14. }
    Alles anzeigen
    B kann deshalb beispielsweise l niemals in Abhängigkeit von A setzen. :(


    Ganz einfach ist die Initialisierung auch nicht: Initialization
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    Und die Initialisierungsreihenfolge in Swift ist nicht besonders sinnvoll. Die Initialisierung sollte meines Erachtens immer von Innen nach Außen erfolgen, damit die äußere Klasse gefahrlos auf die Eigenschaften ihrer Oberklasse zugreifen kann.
    Da habe ich mich auch schon nach dem Hintergrund gefragt. Die Oberklasse kennt ihre Unterklasse nicht. Sie kann sich also ohne Weiteres Initialisieren. Die Unterklasse weiß in einer x-beliebigen Methode nicht, ob die Oberklasse initialisiert ist. Sie könnte ja in einem Initialisierer aufgerufen worden sein. Ich sehe schon iAmInited-Flags durch die Gegend rauschen.

    Möglicherweise hängt dies mit einem anderen Problem zusammen. Ich glaube, ich habe es hier schon geschrieben, aber Stack-Allokation hat mir einen kleinen "Schrecken" eingejagt: Stack-Allokation und Initialisierung sind vermint. Sobald eine Allokation daneben gehen kann, kommt man aus der Nummer eigentlich nicht mehr sicher heraus. Entweder man baut irgendwelche Handler (try-Jedöns), was deutlich mehr Aufwand als Heap-Allokation ist oder man muss sich komplizierte Konzepte ausdenken. Der Vorteil? Vielleicht ein bisschen Tipparbeit.

    Dass die am Ende dann an den Initialisierern rumdoktorn mussten, belegt für mich nur wieder, dass die am Anfang nicht alles durchdacht haben. Wir laufen mal los und schauen, wo wir landen.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Ein Argument von Apple für Swift ist ja auch die höhere Geschwindigkeit bei der Ausführung. Ist die Objective-C Runtime denn wirklich schon komplett ausgereizt und geht es daher nicht schneller?

    Evtl. sollte Apple einfach mal etwas mehr Energie in die weitere Optimierung der Objective-C Runtime stecken. Dies würde dann ja auch die Ausführung von bestehendem Code beschleunigen.

    Ist die Objective-C Runtime eigentlich öffentlich oder liegt die verschlossen bei Apple?