Stilfrage: Zuweisungen in if-Klammern



  • net schrieb:

    allein wegen der gültigkeit von 'i' ist es besser in der for-anweisung aufgehoben

    Bei Deklaration in einer if-Anweisung ist es nicht anders:

    if (int a = foo())
        //...
    

    Hier möchte ich, dass der Gültigkeitsbereich von a von der Deklarationsstelle bis zum Ende der Bedingung reicht. Anhand deiner Argumentation nehme ich an, dass du in einem solchen Fall lieber sowas schreiben würdest:

    {
        int a = foo();
    
        if (a)
            //...
    }
    

    was ich natürlich für Blödsinn halte.



  • net schrieb:

    man solte es sich und anderen nicht unnötig schwer machen und zu 'obfuscated' coden.

    Zuweisungen in Bedingungen sind aber nicht 'obfuscated', sondern gängige Praxis.



  • Shlo schrieb:

    {
        int a = foo();
    
        if (a)
            //...
    }
    

    was ich natürlich für Blödsinn halte.

    ja, es sieht doof aus aber wär eine alternative wenn man die gültigkeit von 'a' einschränken will. würde ich fast dem 'if (int a=foo())' vorziehen.
    (jetzt bin ich bestimmt unten durch bei dir) 😉



  • OMG, das machst du hoffentlich nicht konsequent...

    {
      int i;
      for(i=0; i!=100; ++i)
        foo(i);
    }
    

    Grauenhaft!



  • Jetzt vergleicht ihr Äpfel mit Birnen. :p



  • MaSTaH schrieb:

    OMG, das machst du hoffentlich nicht konsequent...

    {
      int i;
      for(i=0; i!=100; ++i)
        foo(i);
    }
    

    nein, nicht in for-schleifen weil da kann's bei oberflächlicher betrachtung nicht so leicht zu verwechslungen führen (== statt zuweisung). aber das schrieb ich schon irgendwo hier



  • Dass dieser Stil in der Vergangenheit wohl oft zu schwer auffindbaren Fehlern geführt hat, sieht man doch am Design neuer Sprachen. Genau _das_ ist der Grund, warum z.B. in Java oder C# sowas _nicht_ mehr erlaubt ist:
    if(i = foo())



  • Grauenhaft!

    Es hat ja auch niemand von der for-Schleife geredet, sondern von if und der verwechslung mit ==.



  • Hi!

    interpreter schrieb:

    Dass dieser Stil in der Vergangenheit wohl oft zu schwer auffindbaren Fehlern geführt hat, sieht man doch am Design neuer Sprachen. Genau _das_ ist der Grund, warum z.B. in Java oder C# sowas _nicht_ mehr erlaubt ist:
    if(i = foo())

    In C# ist das sehr wohl noch erlaubt. Allerdings benötigst du anschließend noch einen expliziten Vergleich:

    int i;
    if((i = foo())!=0) Console.WriteLine("Hello World!");
    

    Code-Hacker



  • interpreter schrieb:

    Dass dieser Stil in der Vergangenheit wohl oft zu schwer auffindbaren Fehlern geführt hat, sieht man doch am Design neuer Sprachen. Genau _das_ ist der Grund, warum z.B. in Java oder C# sowas _nicht_ mehr erlaubt ist:
    if(i = foo())

    Ich kann mich jetzt täuschen, aber ich glaube, es ist immer noch erlaubt, wenn man ein bool zuweist. Es wird nur kein Pointer oder ein int implizit in ein bool konvertiert, zum Glück.



  • ethereal schrieb:

    if((second=m_Room->RoomItems.Find(in))!=-1)        //search in RoomItems 
    { 
    	m_QuestManager.Evaluate(&m_Inventory,first,&m_Room->RoomItems,second); 
    	return m_ID; 
    } 
    else if((second=m_Room->Exits.Find(in))!=-1)    //search in Exits 
    { 
    	m_QuestManager.Evaluate(&m_Inventory,first,&m_Room->Exits,second); 
    	return m_ID; 
    } 
    else        //not found 
    { 
    	cout<<"There is no "<<in<<"!\n";                    
    	return m_ID;    
    }
    

    wohingegen bei der ersten Möglichkeit alle ifs/elses schön auf eine Ebene liegen.
    Was zieht man da vor?

    was für ne frage?
    da kannste genausogut anhand von zerbies code nachweisen, daß oo nix taugt oder anhand
    von camarcks code nachweisen, daß goto gut ist.
    also erstmal überlege ich, welchen sinn es macht, daß return m_ID dreimal da steht.

    if((second=m_Room->RoomItems.Find(in))!=-1)        //search in RoomItems 
    { 
    	m_QuestManager.Evaluate(&m_Inventory,first,&m_Room->RoomItems,second); 
    } 
    else if((second=m_Room->Exits.Find(in))!=-1)    //search in Exits 
    { 
    	m_QuestManager.Evaluate(&m_Inventory,first,&m_Room->Exits,second); 
    } 
    else        //not found 
    { 
    	cout<<"There is no "<<in<<"!\n";                    
    }
    return m_ID;
    

    dann versuche ich zaghaft für die beiden fast identischen dinge eine inlinefunktion
    zu bauen:

    bool findAndEvaluate(Container* cont,Item const& item)
    {
    	int second=Container->Find(item);
    	if(second==-1)
    		return false;
    	m_QuestManager.Evaluate(&m_Inventory,first,&m_Room->RoomItems,second);
    	return true;
    }
    ...
    if(findAndEvaluate(&Room->RoomItems,in))
    	return m_ID;
    if(findAndEvaluate(&Room->Exits,in))
    	return m_ID;
    cout<<"There is no "<<in<<"!\n";                    
    return m_ID;
    

    oder je nach gusto auch

    if(findAndEvaluate(&Room->RoomItems,in) || findAndEvaluate(&Room->RoomItems,in))
    	return m_ID;
    cout<<"There is no "<<in<<"!\n";                    
    return m_ID;
    

    aber die short-cirquit-auswertung in so seiteneffektigen aufrufen zu verwenden,
    finde ich nicht fein.
    oder

    if(!findAndEvaluate(&Room->RoomItems,in))
    	if(!findAndEvaluate(&Room->Exits,in))
    		cout<<"There is no "<<in<<"!\n";                    
    return m_ID;
    

    da hat man ja furchtbar viele möglichkeiten. man sollte sich überlegen, ob die -1 eine
    gute wahl war, um anzuzeigen, daß da nix gefunden wurde. warum wurden keine zeiger
    verwandt?

    merke: gute spieleprogrammierer haben keinen stil.



  • interpreter schrieb:

    Dass dieser Stil in der Vergangenheit wohl oft zu schwer auffindbaren Fehlern geführt hat, sieht man doch am Design neuer Sprachen. Genau _das_ ist der Grund, warum z.B. in Java oder C# sowas _nicht_ mehr erlaubt ist:
    if(i = foo())

    Ist das per se nicht erlaubt, oder ist es nicht erlaubt weil es keine implizite int-nach-boolean-Konvertierung gibt?

    Ansonsten würde ich Java/C# nicht unbedingt als Maßstab nehmen ... die Designentscheidungen in diesen Sprachen wurden maßgeblich von Überlegungen, wie man möglichst viele Anfänger und Manager von sich überzeugt, geprägt.



  • Hi!

    Bashar schrieb:

    Ist das per se nicht erlaubt, oder ist es nicht erlaubt weil es keine implizite int-nach-boolean-Konvertierung gibt?

    So wie er es geschrieben hat ist es nicht erlaubt, da hier eine <Typ> nach boolean-Konvertierung stattfand. In C# muss immer explizit mit einem Wert verglichen werden, sofern es sich nicht um den Typ bool handelt, da geht dann sehr wohl dies:

    bool richtig = true;
    if(richtig) Console.WriteLine("Richtig");
    else Console.WriteLine("Falsch");
    

    Code-Hacker



  • Also dann: Wer unbedingt will, dass die Zuweisung eine Anweisung und kein Ausdruck ist, kann sich ja mal im Pascal-Lager(+Ada, +Eiffel) umsehen.



  • Bei

    if(!(x = foo()) ...

    lese ich, "Wenn foo() nicht funktioniert, mach dies und das". Gut.
    Wenn dort aber steht

    x = foo();

    if(!x) ...

    muss ich viel mehr denken. Erstmal wird x der Rückgabewert von foo() zugewiesen. Dann erst sehe ich, dass x evtl. ungültig sein kann und darauf reagiert wird.

    IMHO will man aber meistens nicht auf ein ungültiges x prüfen, sondern darauf ob foo() funktioniert hat oder nicht. Das finde ich viel natürlicher und flüssiger zu lesen.



  • Bei

    if(!(x = foo()) ...

    lese ich, "Wenn foo() nicht funktioniert, mach dies und das". Gut.

    Vielleicht lesen andere daraus: Wenn die zuweisung an x nicht funktioniert.



  • volkard schrieb:

    dann versuche ich zaghaft für die beiden fast identischen dinge eine inlinefunktion
    zu bauen:

    bool findAndEvaluate(Container* cont,Item const& item)
    {
    	int second=Container->Find(item);
    	if(second==-1)
    		return false;
    	m_QuestManager.Evaluate(&m_Inventory,first,&m_Room->RoomItems,second);
    	return true;
    }
    ...
    if(findAndEvaluate(&Room->RoomItems,in))
    	return m_ID;
    if(findAndEvaluate(&Room->Exits,in))
    	return m_ID;
    cout<<"There is no "<<in<<"!\n";                    
    return m_ID;
    

    oder je nach gusto auch

    if(findAndEvaluate(&Room->RoomItems,in) || findAndEvaluate(&Room->RoomItems,in))
    	return m_ID;
    cout<<"There is no "<<in<<"!\n";                    
    return m_ID;
    

    hmm, ich finde ehrlich gesagt folgendes lesbarer als deine Idee mit der neuen Inline-Fkt....

    if((second=m_Room->RoomItems.Find(in))!=-1)		//search in RoomItems
    		m_QuestManager.Evaluate(&m_Inventory,first,&m_Room->RoomItems,second);
    else if((second=m_Room->Exits.Find(in))!=-1)	//search in Exits
    	m_QuestManager.Evaluate(&m_Inventory,first,&m_Room->Exits,second);
    else											//not found
    	cout<<"There is no "<<in<<" in this room!\n";							
    
    	return m_ID;
    

    Die drei returns waren in der Tat redundant und resultierten aus Cpy&Paste 😉
    Und hier finde ich auch die Zuweisung innerhalb der if-Klammern durchaus sinnvoll. Aber die Idee mit den Zeigern war auch gut. Mal sehen, was sich da machen lässt...
    edit: cpp-Code formatiert



  • IMHO will man aber meistens nicht auf ein ungültiges x prüfen, sondern darauf ob foo() funktioniert hat oder nicht. Das finde ich viel natürlicher und flüssiger zu lesen.

    Wie ich bereits gesagt habe soll foo eine Ausnahme werfen oder einen gültigen Wert zurück geben und somit stellen sich solche Probleme erst gar nicht.



  • Wenn es sich nicht um eine außergewöhnliche Situation handelt, sollte man auch keine Ausnahme einsetzen.



  • ethereal schrieb:

    Aber die Idee mit den Zeigern war auch gut. Mal sehen, was sich da machen lässt...

    naja, vorteil ist, daß der ungültige zeiger nach false auswertet, was erlaubt:

    if(Bla* bla=find(...))
       tuwas(bla);
    

    vortiel von integern ist aber die leichte relokierbarkeit der daten. also wenn dein array mal wachsen muss und deswegen woanders platz nimmt, sind alle langlebigen zeiger ins array rein kaputt. die indizes aber sind alle noch ok.
    da könnte man sich noch überlegen, ne klasse Index zu basteln. und der op[] nimmt nicht mehr size_t oder int, sondern Index. Index hat natürliche nen umwandlungkonstruktor von int und size_t, damit normale schleifen auch nch gehen und man keinen unterschied merkt. aber Index könnte nen operator bol haben, der nur bei -1 false ausgibt. also nur im falle von "dieser index ist ungültig".


Anmelden zum Antworten