pcplayer99 11 Posted September 26, 2020 In unit Soap.SOAPLinked.pas there are:  1. TLinkedWebNode 2. TLogLinkedWebNode = class(TLinkedWebNode) 3. TLinkedRIO = class(TRIO)  in TLinkedRIO, it has two constructor: one is for: FLinkedWebNode := TLinkedWebNode.Create(nil); and another is for: FLinkedWebNode := TLogLinkedWebNode.Create(nil);  My question is: if I want to create a new TLinkedWebNode like TLogLinkedWebNode, Just named it TMyWebNode, I must let TLinkedRIO has a new constructor that lets it create FLinkedWebNode as my new TMyWebNode.  but, I can not modify Soap.SOAPLinked.pas because it is source code in Delphi. I will create a new pas file and inherit TLinkedRIO like TMyRIO = class(TLinkedRIO) and add a new constructor in it.  but, the new TMyRIO in a new pas unit, I can not access FLinkedWebNode like FLinkedWebNode := TMyWebNode.Create(nil);  So, is there any way to do that? or this is a design issue in Soap.SOAPLinked.pas and I must modify it?   Share this post Link to post
FPiette 380 Posted September 26, 2020 Not sure I correctly understand what need and what you've done. I understood that you copied Delphi source code in another unit and then modified that unit to fit you needs. Then why not modify it further to make visible what you need ? Â btw: Modifying a Delphi unit although technically correct, will make your application difficult to maintain on the long term as Delphi source code will change: you'll have to apply your changes, if possible, to the new source and this may be difficult or even impossible. To avoid this problem, you probably have to change your design. Â Â Share this post Link to post
dummzeuch 1496 Posted September 26, 2020 (edited) You cannot access private fields of a class declared in a different unit. [Period] Â That is, if you play by the rules. There are various ways to still achieve that, but each of them relies on either some compiler quirk (e.g. class helpers could access private fields in some Delphi versions, but that loophole has been closed) or directly use the knowledge about the memory layout of the original class. The latter is done either with pointer arithmetic or by declaring a new class with the same fields and hard typecasting an instance to that class, which then allows accessing the private fields. Of course that would mean this class or pointer arithmetic must be adapted to every change that Embarcadero makes to the original, so the memory layout matches. Edited September 26, 2020 by dummzeuch 1 Share this post Link to post
FredS 138 Posted September 26, 2020 11 hours ago, pcplayer99 said: So, is there any way to do that? How to call a private method of a class inside a Berlin+ class via Helper procedure TSomeClassHelper.CheckAccessToPrivate; begin With Self do begin // access via with works FInt :=1; SomeMethod; end; end; // Declared in another unit as: type TSomeClass = class private FInt : integer; procedure SomeMethod; end; Â 1 1 Share this post Link to post
pcplayer99 11 Posted September 27, 2020 20 hours ago, FPiette said: Not sure I correctly understand what need and what you've done. I understood that you copied Delphi source code in another unit and then modified that unit to fit you needs. Then why not modify it further to make visible what you need ? Â btw: Modifying a Delphi unit although technically correct, will make your application difficult to maintain on the long term as Delphi source code will change: you'll have to apply your changes, if possible, to the new source and this may be difficult or even impossible. To avoid this problem, you probably have to change your design. Â Â Â Yes, this is why I do not want to copy it and modify it, I just want to inherit a new class in a new unit, to avoid modify Delphi's source file. Share this post Link to post
pcplayer99 11 Posted September 27, 2020 10 hours ago, FredS said: How to call a private method of a class inside a Berlin+ class via Helper procedure TSomeClassHelper.CheckAccessToPrivate; begin With Self do begin // access via with works FInt :=1; SomeMethod; end; end; // Declared in another unit as: type TSomeClass = class private FInt : integer; procedure SomeMethod; end;   Thank you Fred. I will try helper class mode. Share this post Link to post
pcplayer99 11 Posted September 27, 2020 I have done a test if the class helper is in a different unit with the original class, it can not access  private field in original class. Share this post Link to post
dummzeuch 1496 Posted September 27, 2020 7 hours ago, pcplayer99 said: I have done a test if the class helper is in a different unit with the original class, it can not access  private field in original class. As I wrote above: On 9/26/2020 at 9:46 AM, dummzeuch said: There are various ways to still achieve that, but each of them relies on either some compiler quirk (e.g. class helpers could access private fields in some Delphi versions, but that loophole has been closed) So, depending on your Delphi version this may still work, but it won't in the later version(s). Share this post Link to post
Guest Posted September 27, 2020 19 hours ago, FredS said: How to call a private method of a class inside a Berlin+ class via Helper Then "berlin+" is not correct. I almost lost my chin here... (?)  I mean, if you must edit the unit then you could edit that unit, and instead move the member to the protected section. It will give a compile error when the unit is updated rather than creating havoc that could slip inte a production build. Share this post Link to post
FredS 138 Posted September 27, 2020 12 hours ago, pcplayer99 said: it can not access  private field in original clas  I have this test setup to let me know if this is ever changed in a new version of Delphi. Should be simple enough to replace TCustomTextFile with whatnot and run the test which I just ran in 10.4.1 and it passed:  //MMWIN:CLASSCOPY unit _MM_Copy_Buffer_; interface implementation type TTestAccessToPrivateFieldHelper = class helper for TCustomTextFile function SetPrivateOwnsStream(AValue: boolean): boolean; end; { TTestAccessToPrivateFieldHelper } function TTestAccessToPrivateFieldHelper.SetPrivateOwnsStream(AValue: boolean): boolean; begin with Self do begin FOwnsStream := AValue; Result := FOwnsStream; end; end; end. //MMWIN:MEMBERSCOPY unit _MM_Copy_Buffer_; interface type THelperTests = class(TObject) public [Test(True)] procedure TestAccessToPrivateField; end; implementation procedure THelperTests.TestAccessToPrivateField; var F : TTextFile; begin F := TTextFile.Create('testing.txt', TEncoding.UTF8); try Assert.IsFalse(F.SetPrivateOwnsStream(False)); Assert.IsTrue(F.SetPrivateOwnsStream(True)); finally F.Free; end; end; end.  1 Share this post Link to post
FredS 138 Posted September 27, 2020 4 hours ago, Dany Marmur said: Then "berlin+" is not correct.  Works here, must be Magic 🙂 Share this post Link to post
pcplayer99 11 Posted September 27, 2020 22 minutes ago, FredS said:  Works here, must be Magic 🙂  My test code as:  constructor TMyClassB3.Create(B: Boolean); begin  if B then FMyClassA := TMyClassA2.Create;  end;  The field "FMyClassA" is declared in TMyClassB2 in another unit, and this code can not compile. because field "FMyClassA" is a private field of TMyClassB2. Share this post Link to post
FredS 138 Posted September 27, 2020 28 minutes ago, pcplayer99 said: The field "FMyClassA" is declared  You have to use the Helper, only it and the use of WITH get you access, see my test code above.  Plus that's not enough code for anyone to help you..  // Your helper should have a method like SetPrivateVar which uses 'With Self do' SomeClass.SetPrivateVar(TMyClassA2.Create());  2 Share this post Link to post
pcplayer99 11 Posted September 29, 2020 Thanks FredS, after I add "With Self do" in my helper class, it can access provate field in another unit.   in unit1, here is TMyClassB:  TMyClassB = class  private   FMyClassA: TMyClassA;   function GetMyName: string;  public   constructor Create;   property MyName: string read GetMyName;  end;   in Unit2, here is my helper class: TMyClassB3 = class helper for TMyClassB  public   constructor Create(B: Boolean); overload;  end;  constructor TMyClassB3.Create(B: Boolean); begin  //if B then FMyClassA := TMyClassA2.Create;  //helper class can not access private field.   //use with self do, here can access private field  with Self do  begin   FMyClassA := TMyClassA2.Create;  end; end;   Share this post Link to post
dummzeuch 1496 Posted September 29, 2020 This is the last (known) remaining class helper loop hole that was overlooked when they closed the previous one that didn't require a 'with' statement. Don't expect this to keep working in future Delphi versions. Â (OK, I'll shut up with this warning now.) Share this post Link to post
Anders Melander 1773 Posted September 29, 2020 6 minutes ago, dummzeuch said: Don't expect this to keep working in future Delphi versions. I'm still hoping that with will be completely eliminated from the language. Here's a few lines from the code I'm currently working on: begin ...3-400 lines of code... with vPlan.DataController, dbSlaktePlan, BLPlan, Grupper ,Data[Id] do begin ...a few hundre lines more... with vPlan, BLPlan.SiteSum, Plans[Id] do begin ...and it goes on... Â 1 1 Share this post Link to post
dummzeuch 1496 Posted September 29, 2020 (edited) 6 minutes ago, Anders Melander said: I'm still hoping that with will be completely eliminated from the language. Here's a few lines from the code I'm currently working on: begin ...3-400 lines of code... with vPlan.DataController, dbSlaktePlan, BLPlan, Grupper ,Data[Id] do begin ...a few hundre lines more... with vPlan, BLPlan.SiteSum, Plans[Id] do begin ...and it goes on... Â Not likely, because there is lots of code like this which would break, keeping people from updating which would hurt the bottom line. The best we can hope for is a warning or maybe even a switch to turn 'with' off. And, actually, seeing how many 'with' statements there are even in the RTL / VCL (haven't checked FMX) and even in our own code (where I try to eliminate every 'with' I come across when I edit code), that's probably a good thing. Â But we digress... Edited September 29, 2020 by dummzeuch Share this post Link to post
pcplayer99 11 Posted September 29, 2020 with MyDataSet do begin  FieldByName('aaa').AsString := 'abcd';  FieldByName('bbb').AsInteger := 234;  etc... end;  This ca reduce typing. Share this post Link to post
Fr0sT.Brutal 899 Posted September 29, 2020 (edited) 1 hour ago, Anders Melander said: I'm still hoping that with will be completely eliminated from the language. Here's a few lines from the code I'm currently working on: F.ex., C-like langs are full of such constructions that allow such write-only clauses as "while (*p++=*r++)" or "i+++++j" but noone tries to throw them out. Shittycode could be written in any language even in Brainfuck (lol) Edited September 29, 2020 by Fr0sT.Brutal Share this post Link to post
Guest Posted September 29, 2020 1 hour ago, dummzeuch said: But we digress... Shurely, we do and let me go on! A compiler flag (with: off) and good refactoring support is on my wish-list! I understand that since the debugger cannot figure out the scope then refactoring would maybe be tricky to implement 😞 IMHO "hate" is a very strong word that i seldom use, if at all. I hate with. Share this post Link to post
Anders Melander 1773 Posted September 29, 2020 1 hour ago, pcplayer99 said: This ca reduce typing. I dnt knw bout u, bt I gt $ 4 the Q of my cde. Not for the amount of keystrokes I can save. 1 Share this post Link to post
Stefan Glienke 1996 Posted September 29, 2020 Hundreds of lines of code within one routine and you think that *with* is the problem? LOL 1 Share this post Link to post
HeZa 3 Posted September 29, 2020 1 hour ago, Stefan Glienke said: Hundreds of lines of code within one routine and you think that *with* is the problem? LOL Yes, because with this WITHs it's very hard to do secure refactorings to solve other problems. 1 Share this post Link to post
Anders Melander 1773 Posted September 29, 2020 1 hour ago, Stefan Glienke said: Hundreds of lines of code within one routine and you think that *with* is the problem? LOL That almost sounded like an insult but assuming that wasn't the intention; I didn't write the code but I've been tasked with maintaining, fixing and modernizing it. with isn't the only problem but it's the one that makes refactoring the code a much harder task than it should have been - and it makes the code undebuggable. Among the other beauties in this code base are the local procedures; The above was actually found in a local procedure, several levels down. The top level method is a few thousand lines of pure horror. 1 Share this post Link to post
Lars Fosdal 1789 Posted September 29, 2020 OMG, @Anders Melander - I feel for you! Refactoring is hard with mastodont routines like that. 1 Share this post Link to post