About a code. Code Style Frage.



  • @TyRoXx
    Es ist nicht immer alles was "more verbose" ist auch automatisch "more good".

    Um zu entscheiden was besser ist - verbose oder concise - kommt es mMn. sehr darauf an wie oft man ein bestimmtes Konstrukt in einem Programm findet.
    Wenn man es 3x in einem Programm findet, dann definitiv verbose.
    Wenn man es 3000x findet, dann definitiv concise. Dann muss sich "der neue" halt eine Sache mehr merken bevor er richtig produktiv mittun kann, dafür müssen "die alten" nicht an 3000 Stellen den "noise" mitlesen den sie eh schon kennen.

    Wobei ich mich selbst grundsätzlich eher auf der Seite der "more verbose" Befürworter sehe, aber was du hier predigst geht mir irgendwie zu weit.

    Deine Argumentation, also immer verbose, es sei denn jeder Affe weiss sofort was gemeint ist, muss man nur mehr ein Stückchen weiter treiben, und dann darf man schon überhaupt keine Funktionen mehr verwenden. Die sind böse, die verstecken wertvolle Informationen hintern einem wenigsagenden Namen. Pfui. Weg weg weg.

    TyRoXx schrieb:

    Den Grund hatte ich tatsächlich vergessen: Man kann vergessen den zweiten Parameter zu übergeben. Ein explizites boost::none sagt dem Compiler und meinen Kollegen, dass ich da wirklich nichts übergeben wollte.

    Das ist mMn. kein gutes Argument. Man kann auch mit dem expliziten boost::none vergessen etwas anzugeben. Wenn du 100x sinnfrei boost::none getippt hast, weil deine Events so gut wie nie Daten haben, dann tippst du beim 101-ten Event, der dann doch Daten gehapt hätte, auch boost::none. Bzw. copy-pastest es von einer der anderen 100 Stellen.

    Wenn ich aus irgend einem Grund hier keinen Default-Parameter verwenden dürfte, dann würde ich eher noch zwei Funktionen machen, z.B. LogSimpleEvent(string) und LogDataEvent(string, string) .

    BTW: Was machst du bei Funktionen die z.B. 10+ Parameter nehmen? Guter Stil ist da ja statt dessen ne struct zu übergeben.
    Bei der kannst du dann aber erst nicht erzwingen dass alle Member initialisiert werden - kann man genau so leicht vergessen. Die einzige (mMn. überhaupt nicht gute) Alternative (die mir gerade einfällt), wäre, im Default-Ctor der struct lauter Blödsinnswerte einzutragen und zu beten dass es beim Testen auffällt wenn ein Wert wo nicht explizit gesetzt wurde.



  • TyRoXx schrieb:

    Für mich ist das ungefähr so als würde C++ das so spezifizieren:

    float fabs(float = -3.5f);
    

    Nur das dies ein absolut unsinniges Beispiel ist. Wenn man wie ich oben im Beispiel gennannt den Fall hat das man beim Runden im überwiegenden Fall 2 Nachkommastellen braucht, ist dies keine willkürliche Zahl.

    TyRoXx schrieb:

    Drittens wird jeder vernünftige Entwickler...

    Wie schön hier manche mit Absoluta arbeiten. Merkwürdig nur das ich solchen Entwicklern in meiner gesamten Laufbahn noch nicht in der Praxis begegnet bin. Die Wahrheit liegt wohl wesentlich mehr in einem sinnvollen Mittelweg. Dir ist hoffentlich auch das Paretoprinzip bekannt, das sich auf nahezu alle Bereiche anwenden lässt. In diesem Fall: Wenn in ~80% der Fälle ein Standardwert wirklich Sinn ergibt, ist die Argumentation mit der expliziten Angabe für mich schlicht Unsinn.

    Wenn ich eine Funktion habe die z.B. Werte eines Vectors in eine CSV-getrennte Stringliste umwandelt, und im Programm das Trennzeichen nun einmal üblicherweise "," ist, würde ich eine seperate Funktion für die Sonderfälle, oder eine explizite Angabe in jeden Aufruf ebenso als Unsinn deklarieren.

    Und es gibt sogar Sonderfälle wo das Ändern des Standardwertes auch einen Sinn ergeben kann (das ist aber wirklich eine Ausnahme).



  • hustbaer schrieb:

    Das ist mMn. kein gutes Argument. Man kann auch mit dem expliziten boost::none vergessen etwas anzugeben. Wenn du 100x sinnfrei boost::none getippt hast, weil deine Events so gut wie nie Daten haben, dann tippst du beim 101-ten Event, der dann doch Daten gehapt hätte, auch boost::none. Bzw. copy-pastest es von einer der anderen 100 Stellen.

    Du argumentierst jetzt aber mit einem Fehler, der bei beiden Varianten passieren kann. Der Standardwert ist eine davon unabhängige, weitere Fehlerquelle.

    hustbaer schrieb:

    Wenn ich aus irgend einem Grund hier keinen Default-Parameter verwenden dürfte, dann würde ich eher noch zwei Funktionen machen, z.B. LogSimpleEvent(string) und LogDataEvent(string, string) .

    Das ist noch besser als mit optional zu arbeiten. Mit dem optional<string> const& müsste jeder lvalue- string kopiert werden. optional ist hier also die falsche Wahl, unabhängig von Standardparameterwerten.
    Explizit unterschiedlich benannte Funktionen halte ich im Zweifel für die bessere Wahl, weil das die Intention deutlicher macht. Ich sehe, dass die zwei Log-Funktionen wohl unterschiedliche Dinge tun. Das muss ich dann nicht an der Anzahl der Argumente erraten.

    hustbaer schrieb:

    BTW: Was machst du bei Funktionen die z.B. 10+ Parameter nehmen? Guter Stil ist da ja statt dessen ne struct zu übergeben.
    Bei der kannst du dann aber erst nicht erzwingen dass alle Member initialisiert werden - kann man genau so leicht vergessen. Die einzige (mMn. überhaupt nicht gute) Alternative (die mir gerade einfällt), wäre, im Default-Ctor der struct lauter Blödsinnswerte einzutragen und zu beten dass es beim Testen auffällt wenn ein Wert wo nicht explizit gesetzt wurde.

    Man kann prinzipiell nicht verhindern, dass jemand Unsinnswerte übergibt. Man kann nur mit einem Konstruktur dabei helfen alle Member zu setzen. Ich sehe nicht, was das mit Standardparametern zu tun hat.



  • TyRoXx schrieb:

    hustbaer schrieb:

    Das ist mMn. kein gutes Argument. Man kann auch mit dem expliziten boost::none vergessen etwas anzugeben. Wenn du 100x sinnfrei boost::none getippt hast, weil deine Events so gut wie nie Daten haben, dann tippst du beim 101-ten Event, der dann doch Daten gehapt hätte, auch boost::none. Bzw. copy-pastest es von einer der anderen 100 Stellen.

    Du argumentierst jetzt aber mit einem Fehler, der bei beiden Varianten passieren kann. Der Standardwert ist eine davon unabhängige, weitere Fehlerquelle.

    Wo? Wie?
    Entweder ich gebe den Wert an, oder ich gebe ihn nicht an. boost::none ist ein vernünftiger Default-Wert in dem skizzierten Fall, an dem sich wohl so schnell nix ändern wird (genauer: niemals was ändern wird*). Wo soll da eine weitere, zusätzliche Fehlerquelle sein? WTF?

    TyRoXx schrieb:

    hustbaer schrieb:

    Wenn ich aus irgend einem Grund hier keinen Default-Parameter verwenden dürfte, dann würde ich eher noch zwei Funktionen machen, z.B. LogSimpleEvent(string) und LogDataEvent(string, string) .

    Das ist noch besser als mit optional zu arbeiten. Mit dem optional<string> const& müsste jeder lvalue- string kopiert werden. optional ist hier also die falsche Wahl, unabhängig von Standardparameterwerten.

    Herr TyRoXx. Das Wort Verhältnismässigkeit ist dir vermutlich fremd. Schlag es nach, ist ne interessante Sache. Ansonsten denk dir halt einfach nen optional<int> damit der Ineffizienzalarm in deinem Kopf nicht so schlimm losbrüllt.

    TyRoXx schrieb:

    hustbaer schrieb:

    BTW: Was machst du bei Funktionen die z.B. 10+ Parameter nehmen? Guter Stil ist da ja statt dessen ne struct zu übergeben.
    Bei der kannst du dann aber erst nicht erzwingen dass alle Member initialisiert werden - kann man genau so leicht vergessen. Die einzige (mMn. überhaupt nicht gute) Alternative (die mir gerade einfällt), wäre, im Default-Ctor der struct lauter Blödsinnswerte einzutragen und zu beten dass es beim Testen auffällt wenn ein Wert wo nicht explizit gesetzt wurde.

    Man kann prinzipiell nicht verhindern, dass jemand Unsinnswerte übergibt. Man kann nur mit einem Konstruktur dabei helfen alle Member zu setzen. Ich sehe nicht, was das mit Standardparametern zu tun hat.

    Boah, stell dich mal nicht so blöd!

    LogEvent("foo");
    //...
    LogEvent("foo", "foo-data");
    
    // vs.
    
    EventEntry ee;
    ee.name = "foo";
    // Weitere 9 Werte setzen die man immer setzen muss
    LogEvent(ee);
    // ...
    EventEntry ee;
    ee.name = "foo";
    // Weitere 9 Werte setzen die man immer setzen muss
    ee.data = "foo-data";
    LogEvent(ee);
    

    Du erkennst hier kein Muster? Echt nicht?

    *: Natürlich könnte man auf die Idee kommen boost::none durch boost::optional<T>() zu ersetzen, was ne Dependency auf none.hpp einspart. Ändert aber an der Semantik nixe.



  • Mal ein Beispiel:

    Ich habe eine Funktion, die liefert alle Knoten eines xml Baums mit einem bestimmten tag. Fast alle Programme lesen und schreiben ihre xml Dateien selbst und kümmern sich nicht um namespaces und prefixe. Ein paar aber doch. Diese dürfen den Namen eines namespaces mit angeben, der per default leer ist. Ohne default Parameter müsste ich von einigen funktionen zwei Versionen erstellen, die sich nur darin unterscheiden, den zweiten Parameter weiter zu geben. Irgendwo wird halt dann aus dem namespacenamen ein prefix ermittelt und mit dem xml prefix verglichen.

    Mfg Martin



  • hustbaer schrieb:

    ...

    Versuch doch mal nachzuvollziehen was ich schreibe und warum. Ich mache das nicht, um jemanden zu ärgern. Dass dir etwas nicht passt, heißt nicht automatisch, dass es falsch ist.

    Dein Ton passt nicht zur bisher sachlichen Diskussion. Es wäre schön, wenn du dich mäßigen und auf eine professionelle Ebene zurückkommen würdest.



  • Ich muss zZ java machen und hab oft:

    String s;
    ...
    s.toLowerCase(Locale.getDefault());
    

    Ich finde es bescheuert, da immer getDefault() aufrufen zu müssen, um einen Default-Parameter zu setzen.
    Hier zählt auch das Argument 'jemand könnte den Default Wert mit schlimmen Konsquenzen ändern' nicht, da getDefault() auch geändert werden könnte.



  • Wenn du das wirklich oft schreiben musst, machst du etwas falsch. Du solltest eine Methode definieren, die diese Umwandlung durchführt und semantisch sinnvoll benannt ist.

    String normalizeExampleString(String denormalized)
    {
        //we use the default locale here because [...]
        return String.toLowerCase(Locale.getDefault());
    }
    


  • Schreibst du für jede Funktion, die oft mit den gleichen Parametern aufgerufen wird, eine Wrapper-Funktion?

    Da hätte ich jedenfalls keine Lust zu und muss ich auch nicht, weil die meisten Funktionen überladen sind.

    Gibt es bei dir auch immer nur einen Konstruktor, der alle vorhandenen Werte durch den Client setzen lässt?

    Stelle ich mir schlimm vor, wenn ich für jeden Parameter immer erst rumsuchen müsste, wie ich da den Default herkriege.



  • TyRoXx schrieb:

    hustbaer schrieb:

    ...

    Versuch doch mal nachzuvollziehen was ich schreibe und warum. Ich mache das nicht, um jemanden zu ärgern. Dass dir etwas nicht passt, heißt nicht automatisch, dass es falsch ist.

    Das kann ich dir 1:1 zurückgeben.



  • Jockelx schrieb:

    Schreibst du für jede Funktion, die oft mit den gleichen Parametern aufgerufen wird, eine Wrapper-Funktion?

    Ja, das nennt man "strukturierte Programmierung".

    Jockelx schrieb:

    Gibt es bei dir auch immer nur einen Konstruktor, der alle vorhandenen Werte durch den Client setzen lässt?

    Immer würde ich nicht sagen. Aber meine Klassen haben neben Standard-, Kopier- und Move-Konstruktur meist nur einen weiteren Konstruktor. Ich habe schon lange genug erklärt, warum der Konstruktor dann fast nie Standardparameterwerte bekommt.

    Jockelx schrieb:

    Stelle ich mir schlimm vor, wenn ich für jeden Parameter immer erst rumsuchen müsste, wie ich da den Default herkriege.

    Und ich stelle es mir schlimm vor, wenn ich bei jedem Aufruf rumsuchen muss, um alle übergebenen Werte herauszufinden.

    hustbaer schrieb:

    Um zu entscheiden was besser ist - verbose oder concise - kommt es mMn. sehr darauf an wie oft man ein bestimmtes Konstrukt in einem Programm findet.
    Wenn man es 3x in einem Programm findet, dann definitiv verbose.
    Wenn man es 3000x findet, dann definitiv concise.

    Ich finde nicht, dass die Häufigkeit der Aufrufe relevant sein sollte. Wenn ich die Funktion deklariere, weiß ich doch gar nicht, wie oft die am Ende tatsächlich benutzt wird. Die Ersparnis an Tipperei ist also rein spekulativ und an sich IMO schon fraglich. Weniger Tipperei und weniger Code machen nicht automatisch produktiv. Wenn das so wäre, müssten die schnellsten Entwickler LZMA-kodierte Maschinensprache binär eingeben. Viel wichtiger ist die Lesbarkeit von Code. Deswegen benutzen wir Hochsprachen und deswegen sollten alle Funktionsargumente ersichtlich sein, ohne die Deklaration nachzuschlagen.

    hustbaer schrieb:

    Dann muss sich "der neue" halt eine Sache mehr merken bevor er richtig produktiv mittun kann, dafür müssen "die alten" nicht an 3000 Stellen den "noise" mitlesen den sie eh schon kennen.

    Wenn ich 1000 Funktionen habe, die jeweils 1000 mal im Code aufgerufen werden, habe ich gar nichts von Standardparameterwerten. Dann müsste ich nämlich sowieso jedes Mal die Werte nachschlagen.



  • TyRoXx schrieb:

    Jockelx schrieb:

    Stelle ich mir schlimm vor, wenn ich für jeden Parameter immer erst rumsuchen müsste, wie ich da den Default herkriege.

    Und ich stelle es mir schlimm vor, wenn ich bei jedem Aufruf rumsuchen muss, um alle übergebenen Werte herauszufinden.

    Also ich mach gerade etwas SFML. Will da ein Grundgerüst bauen und mach erstmal ein Fenster auf:

    sf::Window window(sf::VideoMode(800, 600), "SFML window");
    

    Super! So will ich das haben.
    Hättest du das designed, dann sähe der Ctor nicht so

    sf::Window::Window(VideoMode mode, const String& title, Uint32 style = Style::Default,	const ContextSettings& 	settings = ContextSettings())
    

    aus, sondern ich muss mich durch Sachen durchwurschteln, die mich erstmal überhaupt nicht interessieren.
    Wenn mein Fenster nicht das macht was es soll, dann kann ich immer noch nachschauen wo Styles definert werden und woher man einen Context kriegt und wozu der gut ist.
    Aber ich glaube unsere Positionen werden sich durch die Diskussion eh nicht ändern.



  • Das geht wieder in Richtung Konvention. Man weiß, wie auf seinem Betriebssystem ein typisches Fenster aussieht. Bei dem Aufruf kann man also davon ausgehen, dass das entstehende Fenster so aussehen wird.

    Ich hätte aber auch nichts dagegen das Kind beim Namen zu nennen:

    sf::Window CreateDefaultWindow(VideoMode mode, const String& title);
    sf::Window CreateCustomWindow(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings);
    

    Standardparameterwerte des Konstruktors zu nutzen ist eben die "clevere" Variante, wobei "clever" nicht immer gut ist in der Programmierung. Kann ich als Anfänger erkennen, dass es weitere Parameter gibt, ohne die Deklaration nachzuschlagen? Bequemlichkeit hat eben auch Nachteile.
    Am Namen CreateDefaultWindow kann ich hingegen erkennen, dass es höchstwahrscheinlich andere Funktionen zum Erstellen von Fenstern gibt.



  • Ist eigentlich keine wirklich relevante Diskussion, aber ich muss da doch mal meinen Senf abgeben.

    Es gibt in C++ die Möglichkeit, default-Werte für Parameter anzugeben. Man kann sicher dieses Feature missbrauchen, wie jedes andere Feature auch. Dennoch ist es sehr nützlich, wenn man es geeignet einsetzt.

    Ich finde das Beispiel der Rundungsfunktion auf 2 Nachkommastellen eher unglücklich. 2 Nachkommastellen erscheinen mir nicht überall eine natürliche Wahl zu sein.

    Aber der Kollege TyRoXx hat bereits die LZMA-Komprimierung erwähnt. Die ist parametrisierbar. Ich kann alles mögliche einstellen. In der Regel reicht es aber, mit geeigneten Standardwerten zu arbeiten. Daher würde ich eine Klasse, die LZMA-Komprimierung macht, eben mit diesen Standardwerten ausstatten (ich habe übrigens tatächlich mal genau das gemacht, also eine LZMA-Komprimierklasse).

    Oder ich denke da an Netzwerkklassen. Wenn ich einen gepufferten Stream habe, dann ist in aller Regel eine Puffergröße von 8k für Netzwerkkommunikation ein geeigneter Wert. Sehr selten macht es Sinn, davon abzuweichen. Daher würde ich (und habe ich wieder mal 😃 ) einen Standardwert für die Puffergrösse von 8k angegeben.

    Das ganze macht den Code lesbarer, da ich nicht bei jedem Methodenaufruf jedes Detail angeben muss, sondern nur die relevanten Parameter.

    Sicher kann man das auch ohne Default-Parameter lösen. Aber dafür haben wir eine Hochsprache, die abstrahiert. Ich kann ja auch in C objektorientiert programmieren, nur ist das in C++ doch deutlich einfacher, da mir hier deutlich mehr Ausdrucksmittel zur Verfügung stehen.



  • Du meinst wohl

    sf::Window CreateDefaultWindow(VideoMode mode, const String& title);
    sf::Window CreateCustomWindow(VideoMode mode, const String& title, Uint32 style);
    sf::Window CreateCustomWindowWithContext(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings);
    

    Gut, dass es nicht noch einen Parameter mehr hat.
    Spätestens, dann wirds unleserlich

    sf::Window CreateCustomWindowWithContextAndOther(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings, OtherT& other);
    

    Wobei ich zugeben muss, dass mir nach der Diskussion heute, bei einer Java ArrayList insertAt(index, bla) auch besser gefallen würde, als das tatsächliche
    add(bla) und add(index, bla).



  • tntnet schrieb:

    Oder ich denke da an Netzwerkklassen. Wenn ich einen gepufferten Stream habe, dann ist in aller Regel eine Puffergröße von 8k für Netzwerkkommunikation ein geeigneter Wert. Sehr selten macht es Sinn, davon abzuweichen. Daher würde ich (und habe ich wieder mal 😃 ) einen Standardwert für die Puffergrösse von 8k angegeben.

    Auch hier halte ich es nicht für sinnvoll mehrere Ebenen zu vermischen. Die "Netzwerkklasse" weiß doch gar nichts über meinen tatsächlichen Anwendungsfall. Warum soll die sich irgendeinen Standardpuffer aus den Fingern saugen? Ich weiß doch erst bei der Benutzung der Klasse, was ich damit machen will. Dann kann ich immer noch als "Standardwert" eine Konstante von 8k definieren, dokumentieren und da übergeben. Die Klasse kann auch eine Konstante namens RecommendedBufferSize oder so beinhalten. Wenn ich die verwende, dokumentiert das für jeden Leser, dass ich mich bewusst für einen aus den Fingern gesaugten Wert entschieden habe.

    tntnet schrieb:

    Das ganze macht den Code lesbarer, da ich nicht bei jedem Methodenaufruf jedes Detail angeben muss, sondern nur die relevanten Parameter.

    Eigentlich macht es den Code weniger lesbar, weil ich nach den Werten herumsuchen muss, die mich interessieren. Was du meinst, ist leichter schreibbar ohne nachzudenken.

    tntnet schrieb:

    Sicher kann man das auch ohne Default-Parameter lösen. Aber dafür haben wir eine Hochsprache, die abstrahiert.

    Default-Parameter sind keine Abstraktion. Eine explizite Konstante auf einer höheren Ebene, wie ich sie vorgeschlagen habe, wäre vielleicht Abstraktion.

    Jockelx schrieb:

    sf::Window CreateDefaultWindow(VideoMode mode, const String& title);
    sf::Window CreateCustomWindow(VideoMode mode, const String& title, Uint32 style);
    sf::Window CreateCustomWindowWithContext(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings);
    

    So etwas befürworte ich natürlich nicht. Dass es überhaupt eine Default-Variante gibt, kommt nicht einmal von mir, sondern du wolltest so etwas haben. Eine Anfänger- und eine Expertenfunktion sind doch gar nicht so schlecht. Wenn dann mal ein Parameter zur Expertenfunktion dazukommen soll, kann man in Gottes Namen einen Standardparameterwert benutzen, um das Interface kompatibel zu halten. Das ist ein Grund, den ich verstehen kann. Reine Bequemlichkeit auf Kosten der Nachvollziehbarkeit kann ich aber nicht als Grund verstehen.

    Wäre das hier so schlimm? Es wäre zumindest leichter verständlich und lesbarer als so ein Bitset.

    sf::Window CreateWindow(
    	VideoMode mode,
    	const String& title,
    	TitleBarStyle titleBar,
    	CloseStyle closing,
    	ResizeStyle resizing,
    	ScreenSection section,
    	const ContextSettings &settings
    );
    
    sf::Window window = sf::CreateWindow(
    	sf::VideoMode(800, 600),
    	"SFML window",
    	sf::TitleBarStyle::Visible, //oder sf::TitleBarStyle::Invisible
    	sf::CloseStyle::Closable, //oder sf::CloseStyle::NotClosable
    	sf::ResizeStyle::Resizable, //oder sf::ResizeStyle::FixedSize
    	sf::ScreenSection::Frame, //oder sf::ScreenSection::Fullscreen
    	sf::ContextSettings()
    );
    

    Ob man das obige oder das folgende aus dem Tutorial kopiert und einfügt, ist doch egal. Das obere hat noch den Vorteil, dass es selbsterklärend ist. Mit ContextSettings habe ich mich jetzt nicht auseinandergesetzt.

    sf::Window window(sf::VideoMode(800, 600), "SFML window");
    


  • TyRoXx schrieb:

    Ob man das obige oder das folgende aus dem Tutorial kopiert und einfügt, ist doch egal. Das obere hat noch den Vorteil, dass es selbsterklärend ist. Mit ContextSettings habe ich mich jetzt nicht auseinandergesetzt.

    Aber der Konstruktor von ContextSettings hat auch wieder default Werte (sogar 5). Von daher seh ich jetzt nicht den Vorteil dafür gleich direkt einen default Wert zu verwenden. Ansonsten musst du ja schreiben

    sf::Window window = sf::CreateWindow(
        sf::VideoMode(800, 600),
        "SFML window",
        sf::TitleBarStyle::Visible, //oder sf::TitleBarStyle::Invisible
        sf::CloseStyle::Closable, //oder sf::CloseStyle::NotClosable
        sf::ResizeStyle::Resizable, //oder sf::ResizeStyle::FixedSize
        sf::ScreenSection::Frame, //oder sf::ScreenSection::Fullscreen
        sf::ContextSettings(0, 0, 0, 2, 0)
    );
    

    wobei das dann ja wieder gar nichts erklärt, also noch zusätzliche konstanten Deklarationen braucht. Jeden Parameter in eine neue Zeile schreiben wäre hier auch eher unübersichtlich. Ganz schön viel Arbeit (und Code) für was eigentlich ganz einfaches, finde ich...



  • So vielleicht?

    sf::Window window = sf::CreateWindow(
        sf::VideoMode(800, 600),
        "SFML window",
        sf::TitleBarStyle::Visible,
        sf::CloseStyle::Closable,
        sf::ResizeStyle::Resizable,
        sf::ScreenSection::Frame,
        sf::ContextSettings::OpenGL_2_0_WithoutExtras
    );
    


  • Könnte man machen, aber ich finde

    Window w(VideoMode(800, 600), "SFML window");
    

    hat halt auch was.

    Ich hab mir deine Argumente durchgelesen und kann diese nachvollziehen (ist ja letztendlich eh alles Geschmacksache).

    Aber mMn muss man sich ja eh immer die Deklaration anschauen bevor man (irgend)eine Funktion benutzt. Allein schon damit man weiß ob gewisse Parameter (const) Referenzen sind oder nicht (kann man ja am Aufruf nicht erkennen). Nur weil es jemand falsch machen könnte der keine Ahnung hat und sich nichtmal die Deklaration der Funktionen anschaut die er benutzt finde ich ein bisschen übervorsichtig 😃

    Deswegen seh ich das mit default Parametern nicht so dramatisch, mir ist übersichtlicher Code wichtiger als alles super explizit hinzuschreiben. Das lenkt dann nur vom wesentlichen ab.



  • happystudent schrieb:

    Aber mMn muss man sich ja eh immer die Deklaration anschauen bevor man (irgend)eine Funktion benutzt. Allein schon damit man weiß ob gewisse Parameter (const) Referenzen sind oder nicht (kann man ja am Aufruf nicht erkennen).

    Beim Benutzen ja. Bei existierendem Code (wie dem SFML-Tutorial) nicht. Aus dem Aufruf kann man fast alles ableiten, was zum Verständnis notwendig ist. Nicht-const-Referenzen können das in meinem Beispiel nicht sein, weil das gar nicht übersetzbar wäre - unter der berechtigten Annahme, dass da keine globalen Variablen übergeben werden.

    happystudent schrieb:

    Deswegen seh ich das mit default Parametern nicht so dramatisch, mir ist übersichtlicher Code wichtiger als alles super explizit hinzuschreiben. Das lenkt dann nur vom wesentlichen ab.

    Alle Argumente sind für mich wesentlich, unabhängig von subjektiven Defaults, die andere gewählt haben. Wenn ein Argument unwesentlich ist, kann man auch einfach den Parameter löschen.

    happystudent schrieb:

    Nur weil es jemand falsch machen könnte der keine Ahnung hat und sich nichtmal die Deklaration der Funktionen anschaut die er benutzt finde ich ein bisschen übervorsichtig 😃

    Code, für dessen Verständnis man weniger nachschlagen muss, ist tendentiell besser, oder nicht?


Anmelden zum Antworten