Autor |
Beitrag |
ml-kuen
      
Beiträge: 17
Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
|
Verfasst: Mo 02.06.14 23:29
Hallo,
Hab nach längerer Suche nichts gefunden, darum möchte ich im Forum mal nachfragen.
Ich habe verschiedene Records mit 2, 3 oder 4 Feldern. Diese werden wahlweise durch TreeNode.Data referenziert. Die Zuweisung ist auch kein Problem.
Nur, wie bekomme ich später heraus, welcher Rekord-Typ in Data hinterlegt wurde um diesen zu Re-Referenzieren?
Hoffentlich brauche ich dazu kein Object, dann müsste ich den Quelltext komplett überarbeiten.
Gruß
Michael L.
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 02.06.14 23:50
Prinzipiell würde ich immer zu Objekten greifen, insbesondere in solch einem Fall, da hier die Vererbung wie die Faust aufs Auge passt. Dazu kommt, dass du dir die ganze Pointerspielerei sparen kannst...
Aber wenn du in die Records als erstes ein Flag z.B. in Form eines Integerwerts einbaust, das den Typ angibt, kannst du es als Notlösung auch so lösen, dass du den Pointer auf PInteger castest und so diesen Integerwert auswertest... Schön ist das nicht, funktioniert aber.
|
|
Xion
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Di 03.06.14 08:16
Würde ich anders machen (wobei auch ich vermutlich Objekte an dieser Stelle bevorzugen würde).
Du erzeugst dir pro Record-Typ ein Array, dort steckst du deine Records rein. So kannst du diese sehr effizient auch für andere Zwecke aufzählen. Und die fummelige Speicherverwaltung entfällt (new/dispose).
In das Data Feld hängst du dann ein TDataLink Record ein:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| type TDataLink=record recType: integer; recIdx : integer; end; type PDataLink=PDataLink;
var recType1Array: array of TRecType1; recType2Array: array of TRecType2; recType3Array: array of TRecType3; recDataLinks : array of TDataLink; |
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
ml-kuen 
      
Beiträge: 17
Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
|
Verfasst: Mi 04.06.14 21:31
Hallo jaenicke, hallo Xion,
Im Grunde habe ich das auch so gemacht wie jeanicke beschrieben hat. Ich zeig mal, was ich gemacht habe:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148:
| Type pScopeLst = ^aScopeLst; aScopeLst = RECORD Caption : String; IP : String; Mask : String; Name : String; Comment : String; END;
pRangeLst = ^aRangeLst; aRangeLst = RECORD Caption : String; IP_Begin : String; IP_End : String; END;
pExcludeLst = ^aExcludeLst; aExcludeLst = RECORD Caption : String; IP_Begin : String; IP_End : String; END;
pOptionLst = ^aOptionLst; aOptionLst = RECORD Caption : String; Value: String; END;
TFrmMain = class(TForm) ... public ScopeLst : TList; aScopeRec : pScopeLst; RangeLst : TList; aRangeRec : pRangeLst; ExcludeLst : TList; aExcludeRec: pExcludeLst; OptionLst : TList; aOptionRec : pOptionLst;
procedure TFrmMain.FormCreate(Sender: TObject); begin ScopeLst := TList.Create; RangeLst := TList.Create; ExcludeLst := TList.Create; OptionLst := TList.Create; end;
procedure TFrmMain.FormClose(Sender: TObject; var Action: TCloseAction); var Node : TTreeNode; begin ScopeLst.Free; RangeLst.Free; ExcludeLst.Free; OptionLst.Free; end;
procedure TFrmMain.CreateTree(Sender: TObject; SList : TStrings); var j: Integer; Node : TTreeNode; Begin For j:= 0 To SList.Count - 1 do Begin If c > 6 then If (SList.Strings[3] = 'add') and (SList.Strings[4] = 'scope') then Begin New(aScopeRec); aScopeRec^.Caption := 'Scope'; aScopeRec^.IP := SList.Strings[5]; aScopeRec^.Mask := SList.Strings[6]; aScopeRec^.Name := SList.Strings[7]; If c > 7 then Begin aScopeRec^.Comment :=SList.Strings[8]; Node := Sender.Items.AddChild(Node,SList.Strings[7]); end else Begin aScopeRec^.Comment :=SList.Strings[7]; Node := Sender.Items.AddChild(Node,SList.Strings[5]); end; ScopeLst.Add(aScopeRec); Node.Data := aScopeRec; Node.ImageIndex := 0; Node.SelectedIndex :=0; end; If c = 9 then If (SList.Strings[5] = 'Add') and (SList.Strings[6] = 'iprange') then Begin New(aRangeRec); aRangeRec^.Caption := 'Range'; aRangeRec^.IP_Begin := SList.Strings[7]; aRangeRec^.IP_End := SList.Strings[8]; Node := Sender.Items.AddChild(Node,SList.Strings[7] + ' - ' + SList.Strings[8]); RangeLst.Add(aRangeRec); Node.Data := aRangeRec; Node.ImageIndex := 116; Node.SelectedIndex := 116; end; If c = 9 then If (SList.Strings[5] = 'add') and (SList.Strings[6] = 'excluderange') then Begin New(aExcludeRec); aExcludeRec^.Caption := 'ExcludeRange'; aExcludeRec^.IP_Begin := SList.Strings[7]; aExcludeRec^.IP_End := SList.Strings[8]; Node := Sender.Items.AddChild(Node,SList.Strings[7] + ' - ' + SList.Strings[8]); ExcludeLst.Add(aExcludeRec); Node.Data := aExcludeRec; Node.ImageIndex := 13; Node.SelectedIndex := 13; end; If c > 9 then If (SList.Strings[6] = 'optionvalue') then Begin Ov := StrToInt(SList.Strings[7]); case Ov of 1: Begin New(aOptionRec); aOptionRec^.Caption := 'SubnetMask'; aOptionRec^.Value := SList.Strings[9]; Node := Sender.Items.AddChild(Node,'Subnetzmaske ' + '[' + SList.Strings[9] + ']'); Node.ImageIndex := 149; Node.SelectedIndex := 149; OptionLst.Add(aOptionRec); Node.Data := aOptionRec; end; 3: Begin New(aOptionRec); aOptionRec^.Caption := 'Router'; aOptionRec^.Value := SList.Strings[9]; Node := Sender.Items.AddChild(Node,'Router ' + '[' + SList.Strings[9] + ']'); Node.ImageIndex := 149; Node.SelectedIndex := 149; OptionLst.Add(aOptionRec); Node.Data := aOptionRec; end; 6: Begin New(aOptionRec); aOptionRec^.Caption := 'DNS'; aOptionRec^.Value := SList.Strings[9]; Node := Sender.Items.AddChild(Node,'DNS-Server ' + '[' + SList.Strings[9] + ']'); Node.ImageIndex := 149; Node.SelectedIndex := 149; OptionLst.Add(aOptionRec); Node.Data := aOptionRec; end; end; end; end; end; |
Zugegeben, ich habe den Quelltext etwas angepasst, aber nur um es etwas anschaulicher darzustellen.
Durch das Feld 'Caption' kann man den Typ des Records nun zwar identifizieren, aber wie mache ich das praktisch im Quelltext?
Wie kann man dies beispielsweise in der folgenden Ereignisroutine realisieren?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure TFrmMain.JvTVChange(Sender: TObject; Node: TTreeNode); var n : TTreeNode; NL: Integer; begin NL := Node.Level; case NL of 3: Begin N := Node.getFirstChild; While (N <> NIL) do Begin if Assigned(N) and Assigned(N.Data) then Begin
???
end; N := N.getNextSibling end; end; end; end; |
hat jemand eine Idee?
|
|
Xion
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Do 05.06.14 00:33
Na so gehts wohl nicht, weil das Caption ja im Record steht, dessen Typ du erst kennen musst, um in das Record reinzugucken. Das ginge nur mit Objekten. Deine Caption müsste Teil von TTreeNode sein. Wie jaenicke sagte ginge es, wenn Caption integer ist (hmm, könnte auch mit String gehen), aber ich persönlich finde den Ansatz sehr unsauber.
Vorsicht! Böser Code! 1: 2: 3: 4: 5: 6:
| if Assigned(N) and Assigned(N.Data) then Begin case PString(N) of 'Range': ShowMessage('I''m a range record'); end; end; |
Aus verschiedenen Gründen ist es besser, statt Caption: String lieber Enumerates zu benutzen (Performanz, weniger Fehleranfällig bzgl. vertippen etc.).
Delphi-Quelltext 1: 2: 3:
| type TCaptionEnum = (ceRange, ceScope, ce...); ... caption: TCaptionEnum; |
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
ml-kuen 
      
Beiträge: 17
Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
|
Verfasst: Do 05.06.14 09:04
Guten Morgen,
ihr habt natürlich beide Recht. Nach dem ich die Sache überschlafen habe, verstehe ich es auch. Der Record muss selbstverständlich eindeutig identifiziert werden. Im Grunde bin ich natürlich auch für Erneuerung und dafür veraltete Dinge über Bord zu werfen. Die vorgehensweise mit den Pointern hatte ich allerdings schon einige Male praktiziert und die haben auch funktioniert. Die Strings wollte ich natürlich später durch Integer oder Aufzählung ersetzen.
Abschließend nur noch eine Frage. Reicht es für mein Vorhaben ein einfaches Objekt zu erstellen, oder sollte ich von Persistent erben?
Danke schon mal an euch beide für die Anregungen und Hilfestellung.
|
|
Blup
      
Beiträge: 174
Erhaltene Danke: 43
|
Verfasst: Do 05.06.14 14:08
Wenn es nur darum geht die Records zu ersetzen, genügt eine Ableitung von TObject.
Ich würde eine eigene Basisklasse von TObject ableiten, um später die Möglichkeit zu haben, zentral die Basisklasse zu ersetzen.
z.B.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| type TMyCustomDataObject = class(TObject) end;
TMyDataObject1 = class(TMyCustomDataObject) end;
TMyDataObject2 = class(TMyCustomDataObject) end; |
Der wesentliche Unterschied zum Record ist die Notwendigkeit die Objekte zu Erzeugen und zum Schluss wieder freizugeben.
In der Regel verwaltet man Objekte auch deshalb in eine TObjectList (statt Array).
|
|
ml-kuen 
      
Beiträge: 17
Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
|
Verfasst: Fr 06.06.14 15:57
Dank auch an Blup für seinen Kommentar. Ich habe mich nun doch entschlossen mit Objekten zu arbeiten und werde in Kürze noch einen Status dazu abgeben. Warum soll man sich den Stress mit den Pointern auch noch machen. Schließlich ist Delphi effizient genug und was sind schon ein paar zusätzliche Byte im Arbeitsspeicher bei heutigen Rechnern. Da überwiegt doch klar die Übersichtlichkeit und Sicherheit des objektorientierten Ansatzes.
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: Sa 07.06.14 16:07
An der Stelle habe ich auch einmal eine Frage zur objektorientierten Variante:
Welche der beiden Möglichkeiten ist besser/bevorzugt ihr:
Variante A: Das Objekt wird durch seine RTTI identifiziert.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| type TClassA=class(TObject) end;
type TClassB=class(TObject) end;
var obj : TClassA; begin obj := TClassA.Create; if obj is TClassA then showmessage('ClassA object') else showmessage('ClassB object'); obj.Free; end; |
oder
Variante B: Der Objekttyp wird als Feld einer gemeinsamen Basisklasse geführt und zuerst ausgeweret. Dann kann entspechend weiter gecastet werden.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| type TClassTypeID = (ctTypeA,ctTypeB);
type TBaseClass=class(TObject) FType : TClassTypeID; end;
type TClassA=class(TBaseClass) constructor Create; end;
type TClassB=class(TBaseClass) constructor Create; end;
constructor TClassA.Create; begin FType := ctTypeA; end;
constructor TClassB.Create; begin FType := ctTypeB; end;
var obj : TClassA; begin obj := TClassA.Create; if TBAseClass(obj).FType = ctTypeA then showmessage('ClassA object') else showmessage('ClassB object'); obj.Free; end; |
Ich entscheide mich immer für Variante B weil mal wo gelesen habe das der RTTI Zugriff (generell die IS und AS Operatoren) sehr langsam ist.
Aber vielleicht ist das ja auch falsch?!
Mich würde eure MEinung dazu mal interessieren.
Cheers,
Catweasel
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 08.06.14 12:50
Variante A ist die deutlich bessere, da Variante B nicht viel mit OOP zu tun hat...
Von der Geschwindigkeit wird es kaum einen spürbaren Unterschied machen.
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: So 08.06.14 13:11
Ich fände Varaiante A auch eleganter und manchmal mache ich es so.
Nur lese ich immer wider Dinge wie die hier : etutorials.org/Progr...e-Safe+Down-Casting/
Zitat: | The two RTTI operators, is and as, are extremely powerful, and you might be tempted to consider them as standard programming constructs. Although they are indeed powerful, you should probably limit their use to special cases. [...] RTTI has a negative impact on performance, because it must walk the hierarchy of classes to see whether the typecast is correct. |
Und da dachte ich eben bisher immer das mitgeführte Feld der Basisklasse ist schneller da nichts mehr "gesucht" werden muss..
Und da gibts noch mehr Quellen die uni sono sagen "RTTI ist schön, aber bitte vermeiden". DAs verunsichert dann schon etwas...
Cheers,
Catweasel
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
|
|
jfheins
      
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: So 08.06.14 13:18
Tja, das Problem ist jetzt, dass "sehr langsam" relativ zu sehen ist. Es mag sein, dass is und as hunderte von CPU-Zyklen brauchen. Aber letztlich sind 600 Zyklen auf heutigen CPU's in 200 Nanosekunden abgearbeitet.
Solange du das also nicht in einer Schleife sehr oft aufruft (so circa 1 Mio mal) ist das absolut kein Problem. Bedenke, selbst bei 1 Mio Aufrufen bist du bei 200 Millisekunden Laufzeit.
Also einfach benutzen. Und falls du irgendwann wirklich Performance-Probleme haben solltest, kannst du meistens etwas lokal an der Stelle ändern um das zu beheben.
Ich persönlich würde die is und as Operatoren aber auch nicht zu RTTI zählen.
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: So 08.06.14 13:52
Stimmt auch wieder. Aber man will ja als guter Programmierer immer so effizient wie möglich sein
Im Bezug auf die Orginalfrage wäre das hier dann wohl eine mögliche Vorgehensweise:
docwiki.embarcadero...._strukturierte_Typen
Da kann man dann sehen ob es drei vier oder mehr Felder sind. GetFields sollte es verraten...
Toll das das auch direkt mit den Feldnamen geht
(Hatte um RTTI immeer einen Bogen gemacht, ist aber sich sinnvoll wenn man seinen eigenen Objektinspektor schreiben will
docwiki.embarcadero....perationen_mit_Typen
Aber schonmal Danke für die Anregung mal ein bischen zu schmökern
Cheers,
Catweasel
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
|
|
jfheins
      
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: So 08.06.14 14:20
Lass es mich aber mal so formulieren: Mit dem Einsatz von RTTI (mit Ausnahme von is und as) solltest du auch vorsichtig sein, weil der Code tendenziell schwerer zu durchschauen wird.
Das ist insbesondere dann von Bedeutung wenn du Sachen, die das Typensystem schon hergibt, selber nochmal "in schlecht" neu implementierst
Was sich (wie hier) problemlos mit Objekten und Klassen abbilden lässt, rechtfertigt also keine Emulation der Klassenhierarchie durch records mit RTTI. Interessant wird es übrigens auch, wenn du sowas machen kannst:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| type
TBase = class(TObject) procedure DoStuff(a: Integer); virtual; abstract; end;
TClassA = class(TBase) procedure DoStuff(a: Integer); override; end;
TClassB = class(TBase) procedure DoStuff(a: Integer); override; end;
var obj : TBase; begin obj := TClassA.Create(); obj.DoStuff(4); obj.Free; end; |
Du sparst damit die Stellen, an denen du ein fettes case-Statements mit ähnlichem Code für jeden Möglichen Typen hast. Ganz interessant ist es dann, wenn ein Objekt neu dazu kommt, ob du daran denkst in jedem case die neue Klasse zu behandeln.
P.S.: Du wirst feststellen, dass auch in der offiziellen Dokumentation der as-Operator nicht mit RTTI in Verbindung gebracht wird.
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: So 08.06.14 14:54
Zitat: | P.S.: Du wirst feststellen, dass auch in der offiziellen Dokumentation der as-Operator nicht mit RTTI in Verbindung gebracht wird. |
Wirds doch  (*klugscheissennichtverkneifenkann*)
Zitat: | Mit der Eigenschaft TRttiType.TypeKind können Sie feststellen, ob der ermittelte TRttiType einem gegebenen Typ entspricht. Der Wert der Eigenschaft gibt den tatsächlichen Typ an. Eine weitere Methode zum Feststellen des tatsächlichen Klassentyps einer TRttiType-Instanz stellt der Operator is dar: |
Und wenn man mit RTTI arbeitet kommt man um is und as nicht herum
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| for LType in LContext.GetTypes() do if LType is TRttiInt64Type then begin Writeln('Type name:', LType.Name); Writeln('Min allowed value:', TRttiInt64Type(LType).MinValue); Writeln('Max allowed value:', TRttiInt64Type(LType).MaxValue); Writeln; end; |
Aber ich weis worauf du hinauswillst. Man sollte sich jedesmal fragen, wenn man meint RTTI zu brauchen, ob da nicht irgendwo eine Designschwäche in der Objekthierachie ist.
Doch muss ich zugeben das meine Skepsis is und as gegenüber doch ein wenig schwindet
Cheers,
Catweasel
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: So 08.06.14 19:13
Kurz gesagt: is und as haben nichts mit RTTI in dem Sinne wie es überall benutzt wird zu tun.
Beide arbeiten auf der Class/ClassParent-Kette, welche integraler Bestandteil des Objektkonzepts von Delphi(-artigen Sprachen) ist. Zusätzlich zu den "sichtbaren" Feldern welche von TObject geerbt werden, hat jede Klasseninstanz (nicht also objects) diverse andere Attribute, welche mit im Speicher liegen. Dazu gehört die virtuelle Methodentabelle VMT, ein Zeiger auf die Klasse als TClass, der Self-Pointer, der System-Exception-Record (für Exception und abgeleitete), in neueren Delphis die TMonitor-Instanz (warum auch immer die da drin ist und nicht TObject hinzugefügt wurde) und noch einiges anderes was ich grade nicht aus'm Kopf weiß. System.pas, Suchwort 'vmtSelf' oder so ähnlich. Einer dieser Zeiger geht auch auf den RTTI-Block, sofern denn beim Compilieren eingestellt war, dass die generiert werden sollen.
is tut jetzt nichts anderes als der dadurch entstandenen verketteten Liste zu folgen:
Pseudocode 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| function Is(Instance: TObject; Class: TClass): boolean; var classptr: TClass; begin Result:= false; classptr:= Instance.vmt[vmtParent]; while assigned(classptr) do begin if Class = classptr then Exit(true); classptr:= classptr.vmt[vmtParent]; end; end; |
as ist einfach nur eine Zuweisung mit Exception falls is nicht true ist.
Bei mäßig komplizierten Klassenbäumen sind das einige 10 CMP,MOV,LEA-Instruktionen. Kann man vernachlässigen
"RTTI" im Sinne von "Such mir mal die Eigenschaft mit dem Namen 'abc' und weise der den Integerwert 42 zu" ist eine ganz andere Geschichte. AFAIR auch sehr schön im Doberstein erklärt, aber hier Irr-Elefant.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Für diesen Beitrag haben gedankt: jfheins, Xion
|
|
|