Jump to content

Rollo62

Members
  • Content Count

    1674
  • Joined

  • Last visited

  • Days Won

    22

Everything posted by Rollo62

  1. Interesting, need more consideration where/how to use that ... 🤔
  2. Hi there, I have a general question regarding this topic. There is a lot information out there, even in the DocWiki. https://blogs.embarcadero.com/what-are-the-mistakes-we-made-in-creating-delphi-objects/ https://sergworks.wordpress.com/2015/01/21/think-twice-before-raising-exception-in-constructor/ https://stackoverflow.com/questions/39110021/delphi-raise-exception-in-constructor To summarize: It is perfectly fine to raise an exception in a class constructor ( and in some cases its even not avoidable, I assume ). My question is: Shall and raise an exception on purpose, and if so, what strategy is best ? In a normal situation, this is completely OK. LA := TRaiseOnMinus.Create( -2 ); //<== Raise try //some code finally LA.Free; //<== Never called end; But like that it causes issues: try LA := TRaiseOnMinus.Create( -2 ); //<== Raise //some code finally LA.Free; //<== Will be called on an unconstructed object end; But there is the pattern of encapsuling multiple try - finally's How shall I handle that ? LA := nil; LB := nil; try LA := TRaiseOnMinus.Create( AInputA ); //<== PossibleRaise try LB := TRaiseOnMinus.Create( AInputB ); //<== Possible Raise finally LB.Free; end; finally LA.Free; end; Either I can guarantee that NO Exception can be raised ( can I guarantee that really ) ? Or maybe guarding the Free might help, but I doubt that. LA := nil; LB := nil; try LA := TRaiseOnMinus.Create( AInputA ); //<== PossibleRaise try LB := TRaiseOnMinus.Create( AInputB ); //<== Possible Raise finally if Assigned( LB ) then LB.Free; end; finally if Assigned( LA ) then LA.Free; end; Are there any recommendations or best practices, about using Exceptions in class constructors ( Shall I use them, or not ) ? I see the problem that the caller never knows if Create might be able to throw an exeption, so he must be analysing the internals of the TRaisedOnMinus class first. Beside that, there could be the possibility to prevent any damage from inside the class, by guarding internals, to ensure that double-calling Free doesn't do any damage. Only I'm afraid that this guarding inside Destroy is bad practice too ( but I like double-safetly measures anyway ). constructor TRaiseOnMinus.Create( AParam : Integer ); begin inherited; FMyList := nil; if AParam < 0 then raise Exception.Create( 'Bum' ); FMyList := TStringList.Create; end; destructor TRaiseOnMinus.Destroy; begin if Assigned( FMyList ) then FMyList.Free; inherited; end; How do you design classes with exceptions ?
  3. ... and there we are again with Uwe's Initialize and my Conf_Setup_ scheme ... I like that approach too, because of the clear separation, but its hard to say where I should use that or better constructor parameters. Maybe the experienced developer has always the right answer, but not me, I usually try and rework my classes many many times, until I find a stable, acceptable final design. Would be great to have some rules in what situations such separation makes sense, you gave already a good hint to that. I like to use the Conf_Setup scheme in combination with the fluent interface, which makes class creation, or class builder, more nice and well readable. begin LMyObj := TMyObj.Create {} .Conf_Setup_Begin {} .Conf_Setup_Color( clBlue ) {} .Conf_Setup_Events( EvOnChange ) ... {} .Conf_Setup_End {} ; end; Most of the time I use class functions in those "Builders", which encapsulates class creation within the class itself. Another step of separation creation and initialization within the "Builder".
  4. That external parameter is not in the domain of the class, so I have to take care outside, to keep everything clean. Or do you mean issues with some kind of delayed access, in anonymous procs, events or threads ? When the object might be released, while the event proc might still try to touch it. I think this could has to be guarded by other means, its not related to the constructor exceptions. I would not need Guards on every internal operation, to ensure all parameters are OK. I would hardly see any strange sideeffects later on, when an invalid parameter causes issues only under rare conditions, the creation fails gracefully immediately before that happens.
  5. Right, I'm also wondering how such a "simple" question touches so many basic language concepts. But to clarify the original question again: It was not about if raising exception in Create is possible and how to do that and catch it, the question was: "Shall I raise exceptions on purpose, or better not". Yes, this is exactly what I am looking for, especially here I should raise exceptions if something is wrong with these parameters. Thanks to all, who brought so many different aspects into this discussion. I came already to the conclusion: Raising on purpose in Create() is fine, especially to guard against missing or faulty injected parameters. Everything else is just an intermediate state to the final, perfect design, but there is no real reason to keep such intermediates. ( only I'm not so sure if I am ready to "finalize" all my classes in time )
  6. Right, but why does it feel so bad Maybe I need to think a little out-of-the-box: 1. If I have a little complex classes with quite a few parameters that may rearranged in many ways, while the class is intendet to use direkt operations anyway, then the Conf_Setup pattern for initialization seems to be reasonable. Conf_Setup can throw exceptions when needed. If I remove all the guards on each operation, this is a little risky step. When "forgetting" such Setup, might result in failures usually that should be directly "visible" and easily spotable, but they also might occur in any unpleasant, unforseen situations. So I better use Conf_Setup ALWAYS with Guards on each operation. 2. If I have small, simple objects with < 5 parameters, which are mainly intended to be passed to other objects ( like TTtreeNode ), then the raise in Create might be the right choice. As advantage I can remove all Guards inside that class. 3. A third rule might be, if you have a class of 1.) it is maybe too complex. Try to re-arrange or decompose it, so that the class(es) can fall under 2.) But this is not so easy sometimes, as you might know. This would mean the Conf_Setup rule 1.) is something temporarily only, until I find some better design solution. So a set of rules for different use cases should be fine too, but I'm not sure if these considerations are complete yet. But looking at 1-3.), I would think that the final goal could be to move most classes to 2.), with raising exceptions at the point of their creation. So reaching design 2.) should be the most attractive, I would assume.
  7. Right, Destroy should have no exceptions. But is there any difference if the Exception happen in Destroy or in Conf_Teardown ? If Conf_Teardown is called only in Destroy, and raises an exception, the bad result might be the same. The only advantage to put things in Teardown might, that there a try - finally block could catch such Events, in a central manner. Which is maybe a better place for try-finally, than to put that in Destroy itself.
  8. You can also find a nice online tool
  9. Thanks for those descriptions, they are very enlightning too. I use the Assigned() check as another (bad) habit too, inspired by the DUnit-Tests, which is somewhat related to the separation idea from above ... destructor TRaiseOnMinus.Destroy; begin if Assigned(FMyList) then begin FMyList.Conf_Teardown; FMyList.Free; end; inherited; end; Related to the Conf_Setup_.... scheme, I like to implement Conf_Teardown as well, but this is maybe less reasonable. My goal with that approach was to get also all cleanup in one place, outside the Destroy, thats why I often use the Assigned() before .Free. But as explained above, I find Conf_Setup_... and Conf_Teardown not that attractive, and hope to get rid of this. One reason ist that the external call to Conf_Setup is maybe missing, and the internal fields stay maybe uninitialized. procedure TTest.Run; var LA : TRaiseOnMinus; begin LA := nil; try LA := TRaiseOnMinus.Create; //<= No more exception LA.Conf_Setup( -1 ); //<= It's possible here now LA.Conf_Setup( TStringList.Create ); //<= Another configuration, maybe this line is missing ?? finally if Assigned( LA ) than begin LA.Conf_Teardown; LA.Free; end; end; end; Either I guard any internal access to the internal StringList field variable, or I throw an exception at such accesses. This behaviour I dislike very much in the Conf_Setup approach, and I see no simple way how to intrinsically detect if Conf_setup was called, or not. Allowing uninitialized, unguarded fields would cause random AV, which is by far the worst case of all, IMHO.
  10. @Uwe Raabe Thanks Uwe, it turns out that I used a similar approach for a few classes. Only that I called them Conf_Setup_..., which allows me to have different Conf_Setup_.... for different purposes ( Conf_Setup_Initial, Conf_Setup_Module, Conf_Setup_Events, .... ). This way I have them all nicely bundled together under the same Prefix. LA := TRaiseOnMinus.Create; try LA.Conf_Setup_Initial( AInputA ); //<== PossibleRaise ... This works Ok, but it feels a little wrong, when I try to use clean DI via constructor injection a the same time. To separate this, from constructor to property injection, would bring DI to a less strict level, IMHO. I have hope to keep simple classes as clean as possible, that was the main reason of my initial question in the first place. Would clean separation of construction and initialization be able to resolve ALL the unwanted issues completely ? If that is the case, then I think the overhead is worth it. Only I am not so sure if I can achive the same, with lower overhead cost too. @Dalija Prasnikar Thanks, these rules are very helpful to sort out the right behaviour. @Dalija Prasnikar Doesn't that bite with your bullet point from above ? Once you have half-created instance, you also may have hals constructed internal fields, or is that guaranteed that this never happened ? Thats why I put the FMyList := nil; before the Raise, but it's more like an old habit of mine, to initialize before use. Ok, with your rule: "object instance fields are always zero initialized when constructor chain is being called", thats obsolete. But are all kind of field types secured, like Pointers, [ Weak ] field, and whatsnot, ... ? My habit shall prevent any unexpected glitch, but is of course double-safety in most cases. (Is this an AntiPattern maybe ? ) I also used the "flat" try - finally here and there, but this always left a bad taste to me. What happend if I use this for more than two variables, which often may happen in Bitmap related stuff ? var LA, LB, LC: TRaiseOnMinus; begin LC := nil; LB := nil; LA := nil; try LA := TRaiseOnMinus.Create( -2 );  LB := TRaiseOnMinus.Create( -3 ); LC := TRaiseOnMinus.Create( -3 ); //some code finally LC.Free; LB.Free; LA.Free; end; end; Wouldn't it be OK as well, when I use them "flat", but take special care on managing them in the right order ( ABC - CBA ), like above ? Why should I use one Create outside the try scope ? @Lars Fosdal Right, I also avoid to raise Exceptions, but currently I am working on a class where this could make sense. So I would like to find the best answer or rule-of-thumb for this case, could be like this: - never raise Exception on purpose, it's evil - never raise Exception on purpose, it's an antipattern ( because ... see GOF page xxx ) - you can raise Exceptions safely, if you do prepare this and that - if you always do it like this, you guaranteed to never ever run into any issues. I think we already have a lot of useful rules identified already, thanks to all. @Fr0sT.Brutal Yes, I only try to find the rules for raising my own Exceptions on purpose. But they may raise by system at any time, maybe not only memory, but also file system or other hardware related. Would be good to have the best set of rules for all cases, my exceptions and system exceptions, in the same way.
  11. Rollo62

    Move a Function or Procedure to a Unit??

    TLDR; I think you mixed too many stuff in one method. I would separate this into different domains, each in a unit, e.g. like UMailSend.pas, USysInfo.pas, and the caller I usually encapsule separate functions into classes, with static functions/methods. This behaves same like functions or methods, but keep them under a "namespace" of the class, which could be extended if needed. type TMail = class class function Send( AReceiver, AMessage : String, ...); static; end;
  12. Thats where you should set it, under "All" Android should be the best place, when Debug/Release is not yet set. Be aware that there could be several wrong, old settings under Debug 32/64 and Release 32/64. Maybe you could check with a fresh, new project, just to ensure the that the keysore works well.
  13. There were two passwords, for the keystore and the Alias. Are you sure both of them were correct ?
  14. How about this Project?
  15. There are other, simpler methods to copy a bitmap, but maybe this example is worth noting it, (or here) line-by-line using ScanLine. var srce, dest: TBitmapSurface; path: string; scan: integer; w, h1, h2: integer; begin path := 'C:\tmp\Imgs\res.bmp'; srce := TBitmapSurface.Create; try TBitmapCodecManager.LoadFromFile(path, srce); dest := TBitmapSurface.Create; try // first half w := srce.Width; h1 := srce.Height div 2; dest.SetSize(w, h1, TPixelFormat.RGBA); for scan := 0 to h1-1 do Move(srce.Scanline[scan]^, TBitmapSurface(dest).Scanline[scan]^, srce.Width * 4); Image1.Bitmap.Assign(dest); // second half h2 := srce.Height - h1; dest.SetSize(w, h2, TPixelFormat.RGBA); for scan := h1 to srce.Height-1 do Move(srce.Scanline[scan]^, TBitmapSurface(dest).Scanline[scan-h1]^, srce.Width * 4); Image2.Bitmap.Assign(dest); finally dest.Free; end; finally srce.Free; end; (the example explains how to handle very large images). Here also a simpler solution (just don't use the "with" ...)
  16. Rollo62

    TomTom maps on Android.

    TMS Maps claims that they support TomTom, not tested that.
  17. Rollo62

    I need FireMonkey demo projects

    https://en.delphipraxis.net/topic/5406-image32-2d-graphics-library-open-source-freeware/
  18. Rollo62

    I need FireMonkey demo projects

    What does that mean ? The page is here, its not requiring any ther packages, as far as I know. http://www.angusj.com/delphi/image32/Docs/_Body.htm
  19. Rollo62

    I need FireMonkey demo projects

    Samples like that ? https://github.com/FMXExpress/Cross-Platform-Samples
  20. Rollo62

    I need FireMonkey demo projects

    Just a few posts ago, with Image32.
  21. Rollo62

    New OpenSSL 3.0.1 and 1.1.1m releases

    Thanks, thas very interesting news, to solve the ugly SSL issues once and for all. I wonder what prevents them to make it FMX compatible right away, on all platforms, I expect not much VCL code inside ?
  22. Rollo62

    Wordpress to Firemonkey

    Have a look at this WP-Client from Embarcadero, maybe its helpful. Not tested it, would be great if you could give us some feedback about it, if you can use it. Looks not that current any more, but maybe a good start.
  23. Thats why I always feel cheatet, as a loyal, many year subscription customer. For the normal, official renewal they offered about 27% higher rate than in this offer, while they claim subscription renewal will get lower every year. I from my perspective think that they choose renewal price by a kind of monte-carlo method, every year new. Shall I contact my sales office ?
×