Wertübergabe
am 03.10.2006 09:49:33 von Curtis
Hallo NG!
Ich bin mich damit am beschäftigen, wie ich Werte aus einem Objekt an ein
aufrufendes Script zurückgeben soll. Beim "forschen" im Web oder den Groups
bin ich über die verschiedensten Konstrukte gestolpert aber ohne zu finden,
warum man wann welche Variante wählen sollte, resp. welches Vor- und
Nachteile von diesen sind.
Ich hoffe/denke/gehe davon aus, dass sich alle einig sind, dass ein direkter
Aufruf der Attributwerte ($objekt->{attribut}) tabu ist?!
Ich habe zwei Beispiele angehängt und wäre froh über Kommentare und
Gedanken, resp. auch Korrekturen oder Hinweise, wie es besser geht (und.
v.a. auch WARUM)...
DANKESCHÖN!
Grüssles, Curtis
PS: Ich weiss, dass ich weder in meinen Methoden, noch im aufrufenden Script
Fehler behandle, aber dies habe ich aufgrund der Übersichtlichkeit und der
Postinglänge absichtlich weggelassen.
----->>> VARIANTE 1 <<<-----
----->>> quadrat.pm <<<-----
package quadrat;
use strict;
1;
sub new {
my $class = shift;
my $self = {
seite => undef,
flaeche => undef,
diagonale => undef
};
bless $self, $class;
return $self;
}
sub berechne {
my $self = shift;
$self->{flaeche} = $self->{seite} ** 2;
$self->{diagonale} = sqrt ($self->{flaeche} * 2);
return()
}
sub getflaeche{
my $self = shift;
return $self->{flaeche};
}
sub getdiagonale{
my $self = shift;
return $self->{diagonale};
}
sub setseite{
my $self = shift;
$self->{seite} = shift;
return()
}
----->>> test.pl <<<-----
use strict;
use quadrat;
my $quadrat = new quadrat();
$quadrat->setseite(10);
$quadrat->berechne();
print "Flaeche :" . $quadrat->getflaeche() . "\n";
print "Diagonale :" . $quadrat->getdiagonale() . "\n";
----->>> VARIANTE 2 <<<-----
----->>> quadrat.pm <<<-----
package quadrat;
use strict;
1;
sub new {
my $class = shift;
my $self = {
seite => undef,
flaeche => undef,
diagonale => undef
};
bless $self, $class;
return $self;
}
sub berechne {
my $self = shift;
$self->{seite} = shift;
$self->{flaeche} = $self->{seite} ** 2;
$self->{diagonale} = sqrt ($self->{flaeche} * 2);
return($self->{flaeche}, $self->{diagonale})
}
----->>> test.pl <<<-----
use strict;
use quadrat;
my $quadrat = new quadrat();
my ($flaeche, $diagonale) = $quadrat->berechne(10);
print "Flaeche :" . $flaeche . "\n";
print "Diagonale :" . $diagonale . "\n";
Re: Wertübergabe
am 03.10.2006 14:23:16 von Ch Lamprecht
Curtis M. West schrieb:
> Hallo NG!
>
> Ich bin mich damit am beschäftigen, wie ich Werte aus einem Objekt an ein
> aufrufendes Script zurückgeben soll. Beim "forschen" im Web oder den Groups
> bin ich über die verschiedensten Konstrukte gestolpert aber ohne zu finden,
> warum man wann welche Variante wählen sollte, resp. welches Vor- und
> Nachteile von diesen sind.
>
> Ich hoffe/denke/gehe davon aus, dass sich alle einig sind, dass ein direkter
> Aufruf der Attributwerte ($objekt->{attribut}) tabu ist?!
>
> Ich habe zwei Beispiele angehängt und wäre froh über Kommentare und
> Gedanken, resp. auch Korrekturen oder Hinweise, wie es besser geht (und.
> v.a. auch WARUM)...
>
> DANKESCHÖN!
>
> Grüssles, Curtis
>
> PS: Ich weiss, dass ich weder in meinen Methoden, noch im aufrufenden Script
> Fehler behandle, aber dies habe ich aufgrund der Übersichtlichkeit und der
> Postinglänge absichtlich weggelassen.
>
>
> ----->>> VARIANTE 1 <<<-----
> ----->>> quadrat.pm <<<-----
> package quadrat;
>
> use strict;
>
> 1;
>
> sub new {
> my $class = shift;
> my $self = {
> seite => undef,
> flaeche => undef,
> diagonale => undef
> };
> bless $self, $class;
> return $self;
> }
>
> sub berechne {
> my $self = shift;
> $self->{flaeche} = $self->{seite} ** 2;
> $self->{diagonale} = sqrt ($self->{flaeche} * 2);
> return()
> }
>
> sub getflaeche{
> my $self = shift;
> return $self->{flaeche};
> }
flaeche und diagonale sind ja redundant als Attribute. Du könntest auch gleich
schreiben:
sub get_flaeche{
my ($self) = @_;
return $self->{seite}**2;
}
Wenn du die flaeche trotzdem vorhalten willst, könntest du einfacher schreiben:
sub getflaeche{
my $self = shift;
return $self->{flaeche};
}
(wie gehabt)
und:
sub set_seite{
my ($self,$value) = @_;
$self->{seite} = $value;
$self->berechne; # vermeide inkonsistenten Zustand von seite/flaeche
$return $self;
}
Und wenn es ein weniger triviales Projekt wird, bei dem zu erwarten steht, dass
die Objekte in Beziehung treten, gleich so (aber das ist jetzt wahrscheinlich OT):
sub set_seite{
my ($self,$value) = @_;
$self->{seite} = $value;
$self->changed;
$return $self;
}
sub changed{
my ($self)= @_;
$self->berechne;
# tu was notwendig ist, um die Objekte,
# die von mir abhaengig sind zu informieren.
return $self;
}
Christoph
--
perl -e "print scalar reverse q/ed.enilno@ergn.l.hc/"
Re: Wertübergabe
am 03.10.2006 18:30:46 von hjp-usenet2
On 2006-10-03 07:49, Curtis M. West wrote:
> Ich bin mich damit am beschäftigen, wie ich Werte aus einem Objekt an ein
> aufrufendes Script zurückgeben soll. Beim "forschen" im Web oder den Groups
> bin ich über die verschiedensten Konstrukte gestolpert aber ohne zu finden,
> warum man wann welche Variante wählen sollte, resp. welches Vor- und
> Nachteile von diesen sind.
>
> Ich hoffe/denke/gehe davon aus, dass sich alle einig sind, dass ein direkter
> Aufruf der Attributwerte ($objekt->{attribut}) tabu ist?!
Tabus gibt es in Perl nicht :-).
Dem OO-Puristen mag es da zwar die Zehennägel einrollen, aber ein Hash
ist eine der grundlegenden Perl-Datenstrukturen, und ich sehe wenig
Grund, warum man die nicht verwenden sollte, wenn sie dem Problem
angemessen ist. Mit tie kann man auch den Zugriff schön kapseln.
> ----->>> VARIANTE 1 <<<-----
> ----->>> quadrat.pm <<<-----
> package quadrat;
[...]
> sub berechne {
> my $self = shift;
> $self->{flaeche} = $self->{seite} ** 2;
> $self->{diagonale} = sqrt ($self->{flaeche} * 2);
> return()
> }
>
> sub getflaeche{
> my $self = shift;
> return $self->{flaeche};
> }
>
> sub getdiagonale{
> my $self = shift;
> return $self->{diagonale};
> }
>
> sub setseite{
> my $self = shift;
> $self->{seite} = shift;
> return()
> }
> ----->>> test.pl <<<-----
> use strict;
> use quadrat;
>
> my $quadrat = new quadrat();
>
> $quadrat->setseite(10);
> $quadrat->berechne();
Der explizite Aufruf von berechne() stört mich hier. Der ist leicht zu
vergessen und dann bekommt man veraltete Werte.
> print "Flaeche :" . $quadrat->getflaeche() . "\n";
> print "Diagonale :" . $quadrat->getdiagonale() . "\n";
>
Ich würde das so umschreiben:
sub berechne {
my $self = shift;
$self->{flaeche} = $self->{seite} ** 2;
$self->{diagonale} = sqrt ($self->{flaeche} * 2);
$self->{berechnet} = 1;
return()
}
sub getflaeche{
my $self = shift;
$self->berechne() unless ($self->{berechnet});
return $self->{flaeche};
}
sub getdiagonale{
my $self = shift;
$self->berechne() unless ($self->{berechnet});
return $self->{diagonale};
}
sub setseite{
my $self = shift;
$self->{seite} = shift;
$self->{berechnet} = 0;
return()
}
oder in diesem Fall (flaeche und diagonale sind voneinander unabhängig)
eher:
sub getflaeche{
my $self = shift;
$self->{flaeche} = $self->{seite} ** 2 unless defined $self->{flaeche};
return $self->{flaeche};
}
sub getdiagonale{
my $self = shift;
$self->{diagonale} = $self->{seite} * sqrt(2) unless defined $self->{diagonale};
return $self->{diagonale};
}
sub setseite{
my $self = shift;
$self->{seite} = shift;
$self->{flaeche} = undef;
$self->{diagonale} = undef;
return()
}
> ----->>> VARIANTE 2 <<<-----
> sub new {
> my $class = shift;
> my $self = {
> seite => undef,
> flaeche => undef,
> diagonale => undef
> };
> bless $self, $class;
> return $self;
> }
>
> sub berechne {
> my $self = shift;
> $self->{seite} = shift;
> $self->{flaeche} = $self->{seite} ** 2;
> $self->{diagonale} = sqrt ($self->{flaeche} * 2);
> return($self->{flaeche}, $self->{diagonale})
> }
Welchen Sinn hat hier das Objekt? Du speicherst hier zwar ein paar
Werte, hast aber keine Möglichkeit vorgesehen, die jemals wieder
abzufragen. Da bist Du mit einer Klassenmethode oder einer schlichten
einfachen Funktion besser bedient.
hp
--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp@hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
Re: Wertübergabe
am 03.10.2006 19:04:13 von Michael Perle
Hallo,
es gibt halt viele Wege, die zum Ziel führen.
Einige Tips:
- Lass den Package-Namen mit Groszbuchstaben anfangen.
- Soweit möglich würde ich die Seitenlaenge
bereits im Konstruktor setzen. Bei nur 1 oder 2 Parametern
reicht die Uebergabe/Annahme von Skalaren, z.B.
my $quadrat = Quadrat->new(10);
- Der explizite Aufruf von berechne() ist m.E. fehlerlastig,
weil man ihn vergessen koennte. Das kann man doch gleich
in die Methode setseite() packen: Die berechneten Werte
aendern sich ja mit der Seitenlaenge.
- Allerdings wuerde ich die berechneten Werte sowieso
nicht in separaten Eigenschaften (flaeche, diagonale)
beherbergen. Stattdessen eher Methoden zur Berechnung
bereitstellen, die dann immer die aktuelle Seitenlaenge
verwenden.
sub flaeche {
my $self = shift;
$self->{seite} ** 2;
}
sub diagonale {
my $self = shift;
sqrt( $self->{seite} ** 2 * 2 );
}
Richtig: flaeche und diagonale werden jetzt jedesmal
neu berechnet, und zwar mit der aktuellen Seitenlaenge
(die ja eventl. mit set_seite() geaendert wurde).
Wenn jemand Deine Klasse im zeitkritischen Rahmen verwendet
und den Wert des gleichen Quadrats sehr oft braucht, dann
ist es m.E. an ihm/ihr, den Wert einmal zu berechnen und
in ein Skalar zu schreiben. Beispiel:
print "Ich sage es jetzt 100000 Mal:\n";
$f = $quadrat->flaeche();
for (1..1_000_000) {
print "Die Flaeche ist $f.";
# Statt: print "Die Flaeche ist ", $quadrat->flaeche()
}
- In Perl schreibt man oft keine separaten Setter und Getter,
sondern kombiniert das ganze oft.
sub seite {
my $self = shift;
my $self->{seite} = shift || $self->{seite};
}
$quadrat->seite() gibt die aktuelle Seitenlaenge zurueck.
$quadrat->seite(63) setzt die Seitenlaenge auf 63
(und gibt als Nebeneffekt diesen Wert auch zurueck).
Wie schon geschrieben: Alles meine persoenliche Meinung.
Kritik und Diskussion erwuenscht.
MP
Re: Wertübergabe
am 03.10.2006 19:12:43 von Frank Seitz
Peter J. Holzer wrote:
> On 2006-10-03 07:49, Curtis M. West wrote:
>>
>>Ich hoffe/denke/gehe davon aus, dass sich alle einig sind, dass ein direkter
>>Aufruf der Attributwerte ($objekt->{attribut}) tabu ist?!
>
> Tabus gibt es in Perl nicht :-).
>
> Dem OO-Puristen mag es da zwar die Zehennägel einrollen, aber ein Hash
> ist eine der grundlegenden Perl-Datenstrukturen, und ich sehe wenig
> Grund, warum man die nicht verwenden sollte, wenn sie dem Problem
> angemessen ist. Mit tie kann man auch den Zugriff schön kapseln.
Der Hash ist hier Träger der Instanzvariablen. Den Zugriff auf
solche sollte man grundsätzlich kapseln. Tie ist dabei kein besonders
sinnvoller Weg, sondern Getter/Setter-Methoden.
> Der explizite Aufruf von berechne() stört mich hier. Der ist leicht zu
> vergessen und dann bekommt man veraltete Werte.
Sehe ich genauso. Ein Objekt sollte nach auÃen immer korrekt
seinen inneren Zustand reflektieren, nicht nur manchmal.
> Ich würde das so umschreiben:
>
> sub berechne {
> my $self = shift;
> $self->{flaeche} = $self->{seite} ** 2;
> $self->{diagonale} = sqrt ($self->{flaeche} * 2);
> $self->{berechnet} = 1;
> return()
> }
>
> sub getflaeche{
> my $self = shift;
> $self->berechne() unless ($self->{berechnet});
> return $self->{flaeche};
> }
>
> sub getdiagonale{
> my $self = shift;
> $self->berechne() unless ($self->{berechnet});
> return $self->{diagonale};
> }
>
> sub setseite{
> my $self = shift;
> $self->{seite} = shift;
> $self->{berechnet} = 0;
> return()
> }
>
> oder in diesem Fall (flaeche und diagonale sind voneinander unabhängig)
> eher:
>
> sub getflaeche{
> my $self = shift;
> $self->{flaeche} = $self->{seite} ** 2 unless defined $self->{flaeche};
> return $self->{flaeche};
> }
>
> sub getdiagonale{
> my $self = shift;
> $self->{diagonale} = $self->{seite} * sqrt(2) unless defined $self->{diagonale};
> return $self->{diagonale};
> }
>
> sub setseite{
> my $self = shift;
> $self->{seite} = shift;
> $self->{flaeche} = undef;
> $self->{diagonale} = undef;
> return()
> }
Brrrr. Finde ich nicht gut. Das Ganze ist unnötig kompliziert, da
das Objekt Berechnungsergebnisse speichert. Wozu?
Hier mein Vorschlag:
#!/usr/local/bin/perl -w
use strict;
package Quadrat;
sub new
{
my $class = shift;
my $seite = shift;
return bless \$seite,$class;
}
# Als Getter/Setter implementiert. Kann man
# nach Geschmack auch aufspalten in set_seite() und get_seite().
sub seite
{
my $self = shift;
$$self = shift if @_;
return $$self;
}
sub flaeche
{
my $self = shift;
return $$self**2;
}
sub diagonale
{
my $self = shift;
return sqrt($self->flaeche*2);
}
package main;
my $q = Quadrat->new(10);
print 'Seite: ',$q->seite,"\n";
print 'Fäche: ',$q->flaeche,"\n";
print 'Diagonale: ',$q->diagonale,"\n";
$q->seite(15);
print 'Seite: ',$q->seite,"\n";
print 'Fläche: ',$q->flaeche,"\n";
print 'Diagonale: ',$q->diagonale,"\n";
GrüÃe
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Wertübergabe
am 03.10.2006 21:17:58 von hjp-usenet2
On 2006-10-03 17:12, Frank Seitz wrote:
> Brrrr. Finde ich nicht gut. Das Ganze ist unnötig kompliziert, da
> das Objekt Berechnungsergebnisse speichert. Wozu?
Ich bin davon ausgegangen, dass er in Wirklichkeit etwas komplizierteres
berechnen will als die Fläche eine Quadrats. Dann ist es durchaus
sinnvoll, die Ergebnisse zu cachen und nicht jedesmal neu zu berechnen.
hp
--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp@hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
Re: Wertübergabe
am 03.10.2006 21:27:00 von Frank Seitz
Peter J. Holzer wrote:
> On 2006-10-03 17:12, Frank Seitz wrote:
>>
>>Brrrr. Finde ich nicht gut. Das Ganze ist unnötig kompliziert, da
>>das Objekt Berechnungsergebnisse speichert. Wozu?
>
> Ich bin davon ausgegangen, dass er in Wirklichkeit etwas komplizierteres
> berechnen will als die Fläche eine Quadrats. Dann ist es durchaus
> sinnvoll, die Ergebnisse zu cachen und nicht jedesmal neu zu berechnen.
Sowas baut man allenfalls nachträglich ein - wenn man es wirklich braucht.
GrüÃe
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Wertübergabe
am 03.10.2006 21:43:18 von Slaven Rezic
Frank Seitz writes:
> Peter J. Holzer wrote:
> > On 2006-10-03 07:49, Curtis M. West wrote:
> >>
> >>Ich hoffe/denke/gehe davon aus, dass sich alle einig sind, dass ein direkter
> >>Aufruf der Attributwerte ($objekt->{attribut}) tabu ist?!
> >
> > Tabus gibt es in Perl nicht :-).
> >
> > Dem OO-Puristen mag es da zwar die Zehennägel einrollen, aber ein Hash
> > ist eine der grundlegenden Perl-Datenstrukturen, und ich sehe wenig
> > Grund, warum man die nicht verwenden sollte, wenn sie dem Problem
> > angemessen ist. Mit tie kann man auch den Zugriff schön kapseln.
>
> Der Hash ist hier Träger der Instanzvariablen. Den Zugriff auf
> solche sollte man grundsätzlich kapseln. Tie ist dabei kein besonders
> sinnvoller Weg, sondern Getter/Setter-Methoden.
Wozu braucht man Getter/Setter? Mir fällt nur das nachträgliche
"Adeln" einer Instanzvariablen zu einer Methode ein, die etwas mehr
machen soll als nur Daten auszulesen oder zu setzen. Um zu verhindern,
dass man in diesem Fall viel Code umschreiben soll, verwendet man
gleich von Anfang an ausschließlich Getter/Setter. In Perl hat man
aber auch die Möglichkeit, einen normalen Hash in einen Tied-Hash zu
überführen und den zusätzlichen Code damit ausführen zu lassen.
[...]
>
> Brrrr. Finde ich nicht gut. Das Ganze ist unnötig kompliziert, da
> das Objekt Berechnungsergebnisse speichert. Wozu?
In diesem Fall tatsächlich unnötig, weil hier die Berechnungen sehr
einfach sind. Aber grundsätzlich sollte die Möglichkeit des Cachens
immer berücksichtigt werden.
Gruß,
Slaven
--
Slaven Rezic - slaven rezic de
tknotes - A knotes clone, written in Perl/Tk.
http://ptktools.sourceforge.net/#tknotes
Re: Wertübergabe
am 03.10.2006 22:44:40 von Frank Seitz
Slaven Rezic wrote:
> Frank Seitz writes:
>>
>>Der Hash ist hier Träger der Instanzvariablen. Den Zugriff auf
>>solche sollte man grundsätzlich kapseln. Tie ist dabei kein besonders
>>sinnvoller Weg, sondern Getter/Setter-Methoden.
>
> Wozu braucht man Getter/Setter?
Damit die Klasse jegliche Veränderungen an ihrem internen
Zustand kontrollieren kann.
Die Klassendefinition des OP in der Variante von Peter Holzer
liefert ein Beispiel dafür: Stell Dir vor, die Klasse würde die Attribute
seite, flaeche und diagonale via Hash-Zugriff $obj->{$attrib}
veröffentlichen - die automatische Neuberechnung würde
nicht mehr funktionieren und es wären beliebige
inkonsistente Zustände möglich.
Meine Klassendefinition ist dagegen immun - allerdings eher zufällig.
> Mir fällt nur das nachträgliche
> "Adeln" einer Instanzvariablen zu einer Methode ein, die etwas mehr
> machen soll als nur Daten auszulesen oder zu setzen. Um zu verhindern,
> dass man in diesem Fall viel Code umschreiben soll, verwendet man
> gleich von Anfang an ausschließlich Getter/Setter.
Ja, man wird auch in anderer Hinsicht flexibler. Das, was Du
ansprichst, ist übrigens ein Gegenargument gegen Bezeichnungen
wie set...() und get...().
> In Perl hat man
> aber auch die Möglichkeit, einen normalen Hash in einen Tied-Hash zu
> überführen und den zusätzlichen Code damit ausführen zu lassen.
Sicher, das ist aber untypisch, für den Anwender entsprechend unerwartet
und sieht in der Implementierung sicherlich alles andere als elegant aus.
Von vermutlich gravierenden Problemen bei der Vererbung ganz zu schweigen.
>>Brrrr. Finde ich nicht gut. Das Ganze ist unnötig kompliziert, da
>>das Objekt Berechnungsergebnisse speichert. Wozu?
>
> In diesem Fall tatsächlich unnötig, weil hier die Berechnungen sehr
> einfach sind. Aber grundsätzlich sollte die Möglichkeit des Cachens
> immer berücksichtigt werden.
Da bin ich völlig anderer Meinung. Solche Überlegungen sollten bei
der Konzeption einer Klasse erstmal keine Rolle spielen. Eine ordentlich
designte Klasse läßt sich nachträglich auch geeignet tunen,
wenn man das wirklich braucht. Umgekehrt läuft man Gefahr,
schwer wartbaren Code zu produzieren. Was das bereits in einem
einfachen Fall ausmacht, kannst Du in diesem Thread bewundern.
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Wertübergabe
am 03.10.2006 23:08:25 von Ch Lamprecht
Slaven Rezic schrieb:
> Frank Seitz writes:
>
>
>>Peter J. Holzer wrote:
>>
>>>On 2006-10-03 07:49, Curtis M. West wrote:
>>>
>>>>Ich hoffe/denke/gehe davon aus, dass sich alle einig sind, dass ein direkter
>>>>Aufruf der Attributwerte ($objekt->{attribut}) tabu ist?!
>>>
>>>Tabus gibt es in Perl nicht :-).
>>>
>>>Dem OO-Puristen mag es da zwar die Zehennägel einrollen, aber ein Hash
>>>ist eine der grundlegenden Perl-Datenstrukturen, und ich sehe wenig
>>>Grund, warum man die nicht verwenden sollte, wenn sie dem Problem
>>>angemessen ist. Mit tie kann man auch den Zugriff schön kapseln.
>>
>>Der Hash ist hier Träger der Instanzvariablen. Den Zugriff auf
>>solche sollte man grundsätzlich kapseln. Tie ist dabei kein besonders
>>sinnvoller Weg, sondern Getter/Setter-Methoden.
>
>
> Wozu braucht man Getter/Setter?
Ist das jetzt rethorisch gefragt?
Im Gegensatz zu einer falsch geschriebenen Methode erzeugt der Zugriff auf ein
nicht existentes Feld z.B. keinen Fehler.
Die Datenstruktur hinter den Accessors lässt sich leicht ändern.
Erbende Klassen können den Zugriff auf die Felder redefinieren.
> Mir fällt nur das nachträgliche
> "Adeln" einer Instanzvariablen zu einer Methode ein, die etwas mehr
> machen soll als nur Daten auszulesen oder zu setzen. Um zu verhindern,
> dass man in diesem Fall viel Code umschreiben soll, verwendet man
> gleich von Anfang an ausschließlich Getter/Setter. In Perl hat man
> aber auch die Möglichkeit, einen normalen Hash in einen Tied-Hash zu
> überführen und den zusätzlichen Code damit ausführen zu lassen
Das wird schon für eine Klasse komlizierter als mit Getters/Setters und wie das
mit Vererbung funktionieren soll ist mir nicht ganz klar.
Christoph
--
perl -e "print scalar reverse q/ed.enilno@ergn.l.hc/"
Re: Wertübergabe
am 04.10.2006 10:59:41 von Frank Seitz
Michael Perle wrote:
> - In Perl schreibt man oft keine separaten Setter und Getter,
> sondern kombiniert das ganze oft.
> sub seite {
> my $self = shift;
> my $self->{seite} = shift || $self->{seite};
> }
Aber besser nicht so. Das funktionuckelt nicht, wenn 0, ''
oder undef erlaubte Werte sind.
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Wertübergabe
am 04.10.2006 15:34:16 von Michael Perle
Frank Seitz wrote:
> Michael Perle wrote:
>>- In Perl schreibt man oft keine separaten Setter und Getter,
>> sondern kombiniert das ganze oft.
>> sub seite {
>> my $self = shift;
>> my $self->{seite} = shift || $self->{seite};
>> }
>
> Aber besser nicht so. Das funktionuckelt nicht, wenn 0, ''
> oder undef erlaubte Werte sind.
Richtig. Zu schnell geschossen.
Danke. Asche auf mein Haupt.
Die 0 ist bestimmt ein zulaessiger Wert.
Für den OP heißt das dann wohl (TIMTOW..)
z.B. erst schauen wieviel elemente @_ hat oder
ob nach dem shift noch was in @_ ist oder ...
Re: Wertübergabe
am 05.10.2006 00:34:45 von hjp-usenet2
On 2006-10-04 08:59, Frank Seitz wrote:
> Michael Perle wrote:
>> - In Perl schreibt man oft keine separaten Setter und Getter,
>> sondern kombiniert das ganze oft.
>> sub seite {
>> my $self = shift;
>> my $self->{seite} = shift || $self->{seite};
>> }
>
> Aber besser nicht so. Das funktionuckelt nicht, wenn 0, ''
> oder undef erlaubte Werte sind.
Yup. man sollte explizit abfragen, ob das Argument übergeben wurde, und
nicht, ob es "true" ist.
Ich mag ja an sich
my $parameter = shift;
überhaupt nicht und bevorzuge
my ($parameter1, $parameter2, ...) = @_;
aber in diesem Fall hat es eine gewisse Berechtigung:
my $self = shift;
if (@_) {
my $self->{seite} = shift
}
return $self->{seite};
ist etwas eleganter als
my ($self, $seite) = @_;
if (@_ > 1) {
my $self->{seite} = $seite;
}
return $self->{seite};
(die Zuweisung an $seite von einem u.U. gar nicht existierenden Element
ist da unschön)
meistens geht aber
my ($self, $seite) = @_;
if (defined $seite) {
my $self->{seite} = $seite;
}
return $self->{seite};
auÃer, wenn man $self->{seite} explizit auf undef setzen möchte ...
hp
--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp@hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
Re: Wertübergabe
am 05.10.2006 01:00:01 von Slaven Rezic
Frank Seitz writes:
> Slaven Rezic wrote:
> > Frank Seitz writes:
> >>
> >>Der Hash ist hier Träger der Instanzvariablen. Den Zugriff auf
> >>solche sollte man grundsätzlich kapseln. Tie ist dabei kein besonders
> >>sinnvoller Weg, sondern Getter/Setter-Methoden.
> >
> > Wozu braucht man Getter/Setter?
>
> Damit die Klasse jegliche Veränderungen an ihrem internen
> Zustand kontrollieren kann.
>
> Die Klassendefinition des OP in der Variante von Peter Holzer
> liefert ein Beispiel dafür: Stell Dir vor, die Klasse würde die Attribute
> seite, flaeche und diagonale via Hash-Zugriff $obj->{$attrib}
> veröffentlichen - die automatische Neuberechnung würde
> nicht mehr funktionieren und es wären beliebige
> inkonsistente Zustände möglich.
>
> Meine Klassendefinition ist dagegen immun - allerdings eher zufällig.
>
> > Mir fällt nur das nachträgliche
> > "Adeln" einer Instanzvariablen zu einer Methode ein, die etwas mehr
> > machen soll als nur Daten auszulesen oder zu setzen. Um zu verhindern,
> > dass man in diesem Fall viel Code umschreiben soll, verwendet man
> > gleich von Anfang an ausschließlich Getter/Setter.
>
> Ja, man wird auch in anderer Hinsicht flexibler. Das, was Du
> ansprichst, ist übrigens ein Gegenargument gegen Bezeichnungen
> wie set...() und get...().
Ja, aus ästhetischen Gründen bevorzuge ich meistens den Namen
statt get und set.
> > In Perl hat man
> > aber auch die Möglichkeit, einen normalen Hash in einen Tied-Hash zu
> > überführen und den zusätzlichen Code damit ausführen zu lassen.
>
> Sicher, das ist aber untypisch, für den Anwender entsprechend
> unerwartet
Was kann der User erwarten? Handgeschriebene Getter/Setter? Eine
Schleife, die für eine Liste von Membern Methoden per
Symbolmanipulation erzeugt? Oder die Verwendung von einer der vielen
Klassen wie accessors, Class::Accessors etc.
> und sieht in der Implementierung sicherlich alles andere als elegant
> aus.
Ohne es ausgetestet zu haben:
sub FETCH {
my($self, $key) = @_;
if ($self->can($key)) { # oder ->can("get".ucfirst($key))
$self->$key;
} else {
$self->{$key};
}
}
Dito für STORE. Alternativ könnte statt der ->can-Prüfung auch ein
Mapping von Member->Methode stehen.
> Von vermutlich gravierenden Problemen bei der Vererbung ganz zu
> schweigen.
Ein Tied-Hash ist doch auch eine normale objektorientierte Klasse?
Aber diesen Punkt habe ich nicht zu Ende gedacht, da könnte
tatsächlich noch ein Haken sein.
>
> >>Brrrr. Finde ich nicht gut. Das Ganze ist unnötig kompliziert, da
> >>das Objekt Berechnungsergebnisse speichert. Wozu?
> >
> > In diesem Fall tatsächlich unnötig, weil hier die Berechnungen sehr
> > einfach sind. Aber grundsätzlich sollte die Möglichkeit des Cachens
> > immer berücksichtigt werden.
>
> Da bin ich völlig anderer Meinung. Solche Überlegungen sollten bei
> der Konzeption einer Klasse erstmal keine Rolle spielen. Eine ordentlich
> designte Klasse läßt sich nachträglich auch geeignet tunen,
> wenn man das wirklich braucht. Umgekehrt läuft man Gefahr,
> schwer wartbaren Code zu produzieren. Was das bereits in einem
> einfachen Fall ausmacht, kannst Du in diesem Thread bewundern.
>
Vielleicht waren wir schon in der Tuning-Phase? :-)
Gruß,
Slaven
--
Slaven Rezic - slaven rezic de
tkruler - Perl/Tk program for measuring screen distances
http://ptktools.sourceforge.net/#tkruler
Re: Wertübergabe
am 05.10.2006 01:02:50 von Slaven Rezic
Ch Lamprecht writes:
> Slaven Rezic schrieb:
> > Frank Seitz writes:
> >
> >>Peter J. Holzer wrote:
> >>
> >>>On 2006-10-03 07:49, Curtis M. West wrote:
> >>>
> >>>> Ich hoffe/denke/gehe davon aus, dass sich alle einig sind, dass
> >>>> ein direkter Aufruf der Attributwerte ($objekt->{attribut}) tabu
> >>>> ist?!
> >>>
> >>>Tabus gibt es in Perl nicht :-).
> >>>
> >>>Dem OO-Puristen mag es da zwar die Zehennägel einrollen, aber ein Hash
> >>>ist eine der grundlegenden Perl-Datenstrukturen, und ich sehe wenig
> >>>Grund, warum man die nicht verwenden sollte, wenn sie dem Problem
> >>>angemessen ist. Mit tie kann man auch den Zugriff schön kapseln.
> >>
> >>Der Hash ist hier Träger der Instanzvariablen. Den Zugriff auf
> >>solche sollte man grundsätzlich kapseln. Tie ist dabei kein besonders
> >>sinnvoller Weg, sondern Getter/Setter-Methoden.
> > Wozu braucht man Getter/Setter?
> Ist das jetzt rethorisch gefragt?
>
> Im Gegensatz zu einer falsch geschriebenen Methode erzeugt der Zugriff
> auf ein nicht existentes Feld z.B. keinen Fehler.
Leider gibt es den Fehler bei der falsch geschriebenen Methode erst
zur Laufzeit. Bei Hashes konnte man mit fields.pm nicht existierende
Keys sogar zur Compile-Zeit erkennen. Aber leider sind Pseudo-Hashes
abgeschafft worden...
Gruß,
Slaven
--
Slaven Rezic - slaven rezic de
babybike - routeplanner for cyclists in Berlin
handheld (e.g. Compaq iPAQ with Linux) version of bbbike
http://bbbike.sourceforge.net
Re: Wertübergabe
am 05.10.2006 10:09:49 von Frank Seitz
Peter J. Holzer wrote:
> On 2006-10-04 08:59, Frank Seitz wrote:
>>Michael Perle wrote:
>>
>>>- In Perl schreibt man oft keine separaten Setter und Getter,
>>> sondern kombiniert das ganze oft.
>>> sub seite {
>>> my $self = shift;
>>> my $self->{seite} = shift || $self->{seite};
>>> }
>>
>>Aber besser nicht so. Das funktionuckelt nicht, wenn 0, ''
>>oder undef erlaubte Werte sind.
>
> Yup. man sollte explizit abfragen, ob das Argument übergeben wurde, und
> nicht, ob es "true" ist.
>
> Ich mag ja an sich
>
> my $parameter = shift;
>
> überhaupt nicht und bevorzuge
>
> my ($parameter1, $parameter2, ...) = @_;
Das ist aber ineffektiver als shift und nicht geeignet,
wenn auf @_ weitere Argumente stehen, die man
an anderer Stelle verarbeiten möchte.
> aber in diesem Fall hat es eine gewisse Berechtigung:
>
> my $self = shift;
> if (@_) {
> my $self->{seite} = shift
> }
> return $self->{seite};
>
> ist etwas eleganter als
>
> my ($self, $seite) = @_;
> if (@_ > 1) {
> my $self->{seite} = $seite;
> }
> return $self->{seite};
>
> (die Zuweisung an $seite von einem u.U. gar nicht existierenden Element
> ist da unschön)
>
> meistens geht aber
>
> my ($self, $seite) = @_;
> if (defined $seite) {
> my $self->{seite} = $seite;
> }
> return $self->{seite};
>
> auÃer, wenn man $self->{seite} explizit auf undef setzen möchte ...
Zum letzten Beispiel: Warum eine Lücke lassen?
Für mich ist das kein 100%ig sauberer Code.
Bei mir sähe der Code so aus:
sub seite
{
my $self = shift;
$self->{seite} = shift if @_;
return $self->{seite};
}
GrüÃe
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Wertübergabe
am 05.10.2006 12:39:03 von hjp-usenet2
On 2006-10-05 08:09, Frank Seitz wrote:
> Peter J. Holzer wrote:
>> Ich mag ja an sich
>>
>> my $parameter = shift;
>>
>> überhaupt nicht und bevorzuge
>>
>> my ($parameter1, $parameter2, ...) = @_;
>
> Das ist aber ineffektiver als shift
Ich stelle hiermit Holzers Beobachtung auf:
Wenn jemand im Usenet mit "das ist aber ineffektiver" argumentiert, dann
ist die Wahrscheinlichkeit recht groÃ, dass es in Wirklichkeit
effektiver ist:
#!/usr/bin/perl
use warnings;
use strict;
use Benchmark qw(:all);
sub mul_with_shift {
my $n = shift;
my $m = shift;
return $n * $m;
}
sub mul_with_assign {
my ($n, $m) = @_;
return $n * $m;
}
cmpthese (-3, {
mul_with_shift => sub { mul_with_shift(9, 6) },
mul_with_assign => sub { mul_with_assign(9, 6) },
});
__END__
Rate mul_with_shift mul_with_assign
mul_with_shift 785940/s -- -13%
mul_with_assign 899906/s 15% --
hp
--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp@hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
Re: Wertübergabe
am 05.10.2006 12:41:14 von hjp-usenet2
On 2006-10-05 10:39, Peter J. Holzer wrote:
> On 2006-10-05 08:09, Frank Seitz wrote:
>> Peter J. Holzer wrote:
>>> Ich mag ja an sich
>>>
>>> my $parameter = shift;
>>>
>>> überhaupt nicht und bevorzuge
>>>
>>> my ($parameter1, $parameter2, ...) = @_;
>>
>> Das ist aber ineffektiver als shift
>
> Ich stelle hiermit Holzers Beobachtung auf:
>
> Wenn jemand im Usenet mit "das ist aber ineffektiver" argumentiert, dann
> ist die Wahrscheinlichkeit recht groÃ, dass es in Wirklichkeit
> effektiver ist:
Und als Korrolar dazu: AuÃerdem hat er "effektiv" und "effizient"
verwechselt :-).
hp
--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp@hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
Re: Wertübergabe
am 05.10.2006 13:16:36 von Helmut Wollmersdorfer
Peter J. Holzer wrote:
> Rate mul_with_shift mul_with_assign
> mul_with_shift 785940/s -- -13%
> mul_with_assign 899906/s 15% --
Danke für die Analyse.
Abgesehen davon, dass ich das für einen vernachlässigbaren Unterschied
halte (und auch vermutet hätte), halte ich die assign-Variante für
übersichtlicher, vor allem in der Schreibvariante
sub mul_with_assign {
my (
$n,
$m
) = @_;
return $n * $m;
}
und damit wartungs-effizienter.
Helmut Wollmersdorfer
Re: Wertübergabe
am 06.10.2006 08:54:24 von Ferry Bolhar
Peter J. Holzer:
> Ich stelle hiermit Holzers Beobachtung auf:
>
> Wenn jemand im Usenet mit "das ist aber ineffektiver" argumentiert, dann
> ist die Wahrscheinlichkeit recht groß, dass es in Wirklichkeit
> effektiver ist:
Da muss ich, weil wir (mein Team und ich) erst kürzlich eine
ähnliche Diskussion hatten, auch meinen Senf dazu geben:
Es hängt davon ab, was man als "effektiv" bzw. "effizient"
(denn um das geht es ja eigentlich) definiert.
Das kann jetzt von den Laufeigenschaften des Codes (wie
"schnell" ist er) bis hin zur Wartbarkeit gehen. Schneller Code
muss nicht umbedingt gut wartbar sein, und umgekehrt. Fast
immer ist das eine Gradwanderung, die letztlich in einen
Kompromiss mündet.
In PBP wird im Vorwort sehr gut auf diese Problematik
eingegangen, und das Buch ist IMHO letztlich auch nur ein
"Wegweiser", der helfen soll (und auch tut!), hier "seinen"
eigenen Weg zu finden.
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: Wertübergabe
am 07.10.2006 10:10:26 von Frank Seitz
Slaven Rezic wrote:
> Frank Seitz writes:
>>Slaven Rezic wrote:
>>>
>>>In Perl hat man
>>>aber auch die Möglichkeit, einen normalen Hash in einen Tied-Hash zu
>>>überführen und den zusätzlichen Code damit ausführen zu lassen.
>>
>>Sicher, das ist aber untypisch, für den Anwender entsprechend
>>unerwartet
>
> Was kann der User erwarten?
Dass eine Klasse eine übliche OO-Schnittstelle hat, sprich: dass
die Schnittstelle ausschließlich Methoden umfasst.
> Handgeschriebene Getter/Setter?
Wie die Getter/Setter zustande kommen, ist dem Anwender sicher egal.
> Eine Schleife, die für eine Liste von Membern Methoden per
> Symbolmanipulation erzeugt? Oder die Verwendung von einer der vielen
> Klassen wie accessors, Class::Accessors etc.
AUTOLOAD ist noch eine interessante Variante, die ich manchmal benutzte,
also Getter/Setter beim ersten Gebrauch on-the-fly generieren.
>>und sieht in der Implementierung sicherlich alles andere als elegant
>>aus.
>
> Ohne es ausgetestet zu haben:
>
> sub FETCH {
> my($self, $key) = @_;
> if ($self->can($key)) { # oder ->can("get".ucfirst($key))
> $self->$key;
> } else {
> $self->{$key};
> }
> }
>
> Dito für STORE. Alternativ könnte statt der ->can-Prüfung auch ein
> Mapping von Member->Methode stehen.
Die Idee leuchtet ein. Nur dass das Tie-Objekt $self hier mit dem
eigentlichen Objekt als identisch angesehen wird, erschien mir
zunächst fragwürdig. Aber ich habe es ausprobiert: Man kann die
eigentliche Klasse und die Tie-Klasse tatsächlich zusammenlegen.
>>Von vermutlich gravierenden Problemen bei der Vererbung ganz zu
>>schweigen.
>
> Ein Tied-Hash ist doch auch eine normale objektorientierte Klasse?
> Aber diesen Punkt habe ich nicht zu Ende gedacht, da könnte
> tatsächlich noch ein Haken sein.
Auch das habe ich ausprobiert. Auch bei Vererbung hat so
funktioniert, wie ist es erwarte.
Aber wie gesagt: Ich würde es so nicht machen.
Auch wenn die Klasse dank tie() die Zugriffe voll kontrolliert,
hat die Sache letztlich den Beigeschmack, als würde man als Anwender
auf Interna herumoperieren.
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Wertübergabe
am 07.10.2006 10:17:00 von Frank Seitz
Peter J. Holzer wrote:
> On 2006-10-05 08:09, Frank Seitz wrote:
>>Peter J. Holzer wrote:
>>>
>>>überhaupt nicht und bevorzuge
>>>
>>> my ($parameter1, $parameter2, ...) = @_;
>>
>>Das ist aber ineffektiver als shift
>
> Ich stelle hiermit Holzers Beobachtung auf:
>
> Wenn jemand im Usenet mit "das ist aber ineffektiver" argumentiert, dann
> ist die Wahrscheinlichkeit recht groÃ, dass es in Wirklichkeit
> effektiver ist:
[Benchmark]
Naja, wenn ich an dem Benchmark ein wenig herumspiele,
kann ich auch umgekehrte Ergebnisse erzielen.
Meine Aussage stützte sich auf eine Messung, die ich selbst
vor einiger Zeit mal gemacht hatte, bei der das Gegenteil herauskam.
Offenbar lässt sich das so pauschal nicht beurteilen.
Insofern habe ich mich wohl ein bisschen weit aus dem
Fenster gelehnt und ziehe hiermit meine apodiktische Effektivitätsaussage
(die wohl tatsächlich mehr eine Effizienzaussage war, aber wer
kennt den Unterschied schon so genau?) wieder zurück :)
GrüÃe
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Wertübergabe
am 07.10.2006 10:23:23 von Frank Seitz
Helmut Wollmersdorfer wrote:
> Abgesehen davon, dass ich das für einen vernachlässigbaren Unterschied
> halte (und auch vermutet hätte), halte ich die assign-Variante für
> übersichtlicher, vor allem in der Schreibvariante
>
> sub mul_with_assign {
> my (
> $n,
> $m
> ) = @_;
> return $n * $m;
> }
Dazu kann ich nur sagen: WÃRG.
Die Geschmäcker sind offbar sehr, sehr, sehr verschieden :)
GrüÃe
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel