C und patch

Josef 'Jupp' Schugt jupp at gmx.de
Fre Nov 22 17:20:56 CET 2002


* On 2002-11-22 13:19
* Christoph Kliemt <christoph.kliemt at entici.de> wrote:
>   ==      obj == anObject  -> true or false
> 
> Equality---At the Object level, == returns true only if obj and anObject
> are the same object. Typically, this method is overridden in descendent
> classes to provide class-specific meaning.
> 
> Un nu?
> 
> Jetzt kann es natürlich sein, daß ich das nicht ganz richtig verstanden
> habe (weil: noch nie mit Ruby programmiert), aber wenn zB die Überladung
> dieses Operators ähnlich wie in C++ verhält ( aka selbstdefinierte
> Gleicheit) dann bringt Ruby uns im Hinblick auf Lesbarkeit und / oder
> einleuchtende Syntax auch nicht weiter...

== ist kein Operator sondern eine Methode. Wenn du deutlich machen
willst, dass es sich um eine von dir geschriebene Methode handelt,
dann schreib' 'a.==(b)'.

Damit doktorst du aber nur an den Symptomen herum.

Zunächst sind Objekte nur dann gleich, wenn es sich ein und dasselbe
Objekt handelt. Getreu dem Prinzip der kleinsten Überraschung geht
Ruby in diesen Fällen zunächst davon aus, dass mit '==' diese
Bedeutung der Gleichheit gemeint ist.

Wenn es sich um Zeichenfolgen, Zahlen, etc. handelt, meint '==' eine
wertemäßige Übereinstimmung, was sich in diesen Fällen ebenfalls im
Verhalten von Ruby widerspiegelt.

Bei manchen selbst definierten Objekten ist unklar, was mit '=='
gemeint sein könnte. In diesen Fällen verbietet sich das Überladen
von '=='. Ein Beispiel, wie man es NICHT machen sollte:

class Bruch
  attr_accessor :zaehler
  attr_accessor :nenner

  def initialize(zaehler,nenner)
    @zaehler = zaehler.to_f
    @nenner = nenner.to_f
  end
  def ==(q)
    (self.zaehler == q.zaehler) and (self.nenner == q.nenner)
  end
end
a = Bruch.new( 1.0, 2.0)
b = Bruch.new( 2.0, 4.0)
c = Bruch.new( 1.0, 2.0)
d = a
puts a.==(b), a.equal?(b)
puts a.==(c), a.equal?(c)
puts a.==(d), a.equal?(d)

Das ergibt:

false
false
true
false
true
true

Warum handelt es sich um schlechten Programmierstil? Ganz einfach:
Die Definition

def ==(q)
    (self.zaehler / self.nenner) == (q.zaehler / q.nenner)
end

wäre ebenfalls denkbar - und liefert für a und b abweichende
Ergebnisse:

true
false
true
false
true
true

Anders sieht es im nachfolgenden Beispiel aus. Die Klassen-Methode
'gcd', die sich in meiner ExtMath-Library befindet, bestimmt den
größten gemeinsamen Teiler von zaehler und nenner. Der Bruch wird
gekürzt und damit gibt es nur eine einzige Möglichkeit, was mit '=='
gemeint sein kann.

require 'ExtMath'
class Bruch
  attr_accessor :zaehler
  attr_accessor :nenner

  def initialize(zaehler,nenner)
    @zaehler = zaehler / ExtMath.gcd(zaehler, nenner)
    @nenner = nenner / ExtMath.gcd(zaehler, nenner)
  end
  def ==(q)
    (self.zaehler == q.zaehler) and (self.nenner == q.nenner)
  end
end
a = Bruch.new( 1, 2)
b = Bruch.new( 2, 4)
c = Bruch.new( 1, 2)
d = a
puts a.==(b), a.equal?(b)
puts a.==(c), a.equal?(c)
puts a.==(d), a.equal?(d)

Hier werden folgende Werte ausgegeben:

true
false
true
false
true
true

Jetzt liefern die beiden vorher verwendeten Definitionen identische
Ergebnisse - Achtung: Um '/' richtig zu verwenden, müssen die Werte
natürlich in Fließkommazahlen umgewandelt werden. Wie das in Ruby
geht, kann ich ja mittlerweile als bekannt voraussetzen.

Einen Operator (bzw. eine Operatormethode) überlädt man nur, wenn die
Bedeutung offensichtlich und eindeutig ist. Andernfalls lässt man die
Finger davon, denn man handelt sich damit eine ergiebige und  völlig
unnötige Fehlerquelle ein.

Josef 'Jupp' Schugt <jupp at gmx.de>                 http://jupp.tux.nu/
-- 
Meckenheimer Str. 66a, 53179 Bonn, DE/EU             +49 228 34 24 85
I was deeply shocked by learning that a Windows XP Pro Recovery CD at
39,- EUR is a pirated copy. Does this mean that my Linux distribution
which did cost less and has more features is a pirated copy as well?