tag:blogger.com,1999:blog-8832291873344926372.post3650669219865078108..comments2024-03-24T14:03:17.111-04:00Comments on Cape Cod Gunny - Michael Riley: How to Replace Global Variables by Using a Static ClassMichael Rileyhttp://www.blogger.com/profile/15959746627356186242noreply@blogger.comBlogger23125tag:blogger.com,1999:blog-8832291873344926372.post-24719107975943448502014-07-21T13:35:47.674-04:002014-07-21T13:35:47.674-04:00correction:
now it's obviously a global variab...correction:<br />now it's obviously a global variable (or constant), not disguised, thanks to the forced declaration of it's namespaceAnonymoushttps://www.blogger.com/profile/17275624737037271243noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-15579387337840482852014-07-21T13:20:14.377-04:002014-07-21T13:20:14.377-04:00... yes, but now it's obviously a global varia...... yes, but now it's obviously a global variable (or constant), not disguised thanks to the forced declaration of it's namespace, and as expected one is forced to be careful enough to not let the global variable have an unpredictable state by protecting it with a getter.Anonymoushttps://www.blogger.com/profile/17275624737037271243noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-54814483494798743572014-07-18T07:20:42.279-04:002014-07-18T07:20:42.279-04:00.. yes, but this is just another way to disguise g..... yes, but this is just another way to disguise global variables...Arnaudhttps://www.blogger.com/profile/00421394020248758254noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-91097005158366217802014-07-14T19:36:34.782-04:002014-07-14T19:36:34.782-04:00@Soul - +1 for avoid redundency@Soul - +1 for avoid redundencyMichael Rileyhttps://www.blogger.com/profile/15959746627356186242noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-26219004027725346322014-07-14T05:24:28.348-04:002014-07-14T05:24:28.348-04:00I think what Arnaud and Stefan are trying to say i...I think what Arnaud and Stefan are trying to say is that making your class var PUBLIC is a big no no.<br />Your should rather scope the class var as STRICT PRIVATE then declare a PUBLIC PROPERTY with a getter function.<br />You then have the option to initialize the class var in the property getter or the class constructor.<br /><br />Also, personally I would have called the class 'AppInfo' instead of 'TAppInfo', and dispensed with the AppInfo prefix for class constants, class methods and class properties. <br />The net result usage is:<br /> str := AppInfo.WebSite; <br /><br />Another neat trick is to make a 'super' static class to gather all the global library functions and constants into one place, I call it RTL which looks like this:<br /><br />unit MyRTL;<br />...<br />uses MyAppInfo;<br />...<br />RTL = class<br />public<br /> class function AppInfo: AppInfoClass;<br />end;<br /><br />class function RTL.AppInfo: AppInfoClass;<br />begin<br /> Result := AppInfo;<br />end;<br /><br />in a separate unit:<br /><br />unit MyAppInfo;<br />...<br /> AppInfoClass = class of AppInfo;<br /> AppInfo = class<br /> ...<br /> end;<br /><br />Cool things about this pattern:<br /><br />1. Usage and origin is clear, eg: str := RTL.Appinfo.WebSite;<br /><br />2. You can have hundreds of static classes in separate units but you only ever have to delcare MyRTL (.pas) in your uses clauses.<br /><br />3. Having your library functions grouped into many separate units makes them easier to test and manage.<br /><br />4. If you ever need to go cross platform it's so much easier by using compiler directives on the uses clause of MyRTL.pas<br />Anonymoushttps://www.blogger.com/profile/17275624737037271243noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-298077668962375982014-07-14T02:15:24.110-04:002014-07-14T02:15:24.110-04:00Thanks for sharing Michael:)
I just wanted to add...Thanks for sharing Michael:)<br /><br />I just wanted to add that what you did is bascially adding another scope to your already scoped code. You could write as well:<br /><br />Global.AppInfoCopyright;<br />Global.AppInfoWebsiteName;<br /><br />Also, try avoid redundancy like this:<br /><br />TAppInfo.Copyright;<br />TAppInfo.WebsiteName;<br /><br />Good luck with your application :)Soul Intruderhttps://www.blogger.com/profile/16873694208138872553noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-62244808195298741982014-07-14T01:56:45.126-04:002014-07-14T01:56:45.126-04:00"No one is born as a master."
@Uwe True...."No one is born as a master."<br />@Uwe True. And that is why I think that more knowledgeable people should share their knowledge so others can learn. If everyone would say "yay cool" nobody would think about why certain things might not be good. I hardly consider constructive criticism (even if strongly worded sometimes) bashing. Bashing is just talking down something without offering alternatives.<br /><br />I am not saying you should use this or that pattern or principle no matter what. Rather the opposite. Sometimes you just have to be pragmatic but over time your way of thinking and coding will change into a direction that will result in better code overall.Stefan Glienkehttps://www.blogger.com/profile/05509404049325709406noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-26809267378391254752014-07-12T13:02:47.221-04:002014-07-12T13:02:47.221-04:00Like the use of the goto statement, to use or not ...Like the use of the goto statement, to use or not to use global variables should *not* be a dogmatic decision as is implied in some of these replies. The decision should be made on a case by case basis. The writer appears to be the sole author, he has full control over the code, he may not be interested in reuse and most importantly he has to ship! His approach seems perfectly reasonable. Of course some will come back and comment that he may want to reuse the in the future. Trying to make software future proof and to anticipate future usage can be a bad thing, it results in over engineered and in the long term more complex code to maintain code. The way he handles global variables I think is elegant, essentially putting them into their own namespace. Penrodynhttps://www.blogger.com/profile/17990520067503449981noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-86220704001933062372014-07-12T13:00:04.596-04:002014-07-12T13:00:04.596-04:00Eamonn, nice idea. Thanks for your comment. I purc...Eamonn, nice idea. Thanks for your comment. I purchased Raize components (finally) and I will be using the TRzRegIniFile, TRzFormState and TRzPropertyStore for all my ini stuff.Michael Rileyhttps://www.blogger.com/profile/15959746627356186242noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-5217352656691697932014-07-12T10:34:59.174-04:002014-07-12T10:34:59.174-04:00Gunny, my next step was to make this self-persisti...Gunny, my next step was to make this self-persisting, so the class handles loading and saving it's properties to an ini / registry / file. If you base that on RTTI, you are then able to add new properties and they will be loaded/saved automatically.<br /><br />I used to hate creating the ini code for each app, now it's one of the first building blocks in all my apps.Eamonnhttps://www.blogger.com/profile/10952747254785020030noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-3908023121093466142014-07-12T09:04:23.875-04:002014-07-12T09:04:23.875-04:00@Uwe - Done thanks for your help and encouragement...@Uwe - Done thanks for your help and encouragement.Michael Rileyhttps://www.blogger.com/profile/15959746627356186242noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-87530002938159195692014-07-12T08:29:45.668-04:002014-07-12T08:29:45.668-04:00@Uwe - Thanks +∞@Uwe - Thanks +∞Michael Rileyhttps://www.blogger.com/profile/15959746627356186242noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-34737416592493152942014-07-12T08:25:52.555-04:002014-07-12T08:25:52.555-04:00@Arnaud - I appreciate your comments. I'm curr...@Arnaud - I appreciate your comments. I'm currently trying to upgrade a simple, single-user application that has not been through a major re-write for eight years. I'm a self-taught part-time guy trying to elevate my game.<br /><br />I am struggling with the answer to this question... "Will it help me ship my product?"<br /><br />I do not have time to fully learn everything and get a product built. I bought Nicks book and I'm stuck between pages 12-18. I purchased the had printed version of his book. I need to go purchase the PDF version so I can cut and past stuff I don't understand and ask about it in his google= community.<br />https://plus.google.com/u/0/communities/110978417023349293804Michael Rileyhttps://www.blogger.com/profile/15959746627356186242noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-44373876129456647492014-07-12T08:08:02.909-04:002014-07-12T08:08:02.909-04:00@Stefan - Thank you for the link to the clean code...@Stefan - Thank you for the link to the clean code video. I understand "the why" much better. I was hoping to move forward and make progress on my application this weekend. I was no not intending to go back to the drawing board and work on fundamentals. Oh well. Michael Rileyhttps://www.blogger.com/profile/15959746627356186242noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-43144992171834154732014-07-12T05:52:10.332-04:002014-07-12T05:52:10.332-04:00Why the bashing? Given the code shown there is not...Why the bashing? Given the code shown there is nothing wrong with it using a static class. That doesn't mean that static classes are the solution to every problem. Most of the time a pragmatic approach is better than a dogmatic one which might require a full redesign of all applications. Even the use of IOC and DI has to be learned before it can be used properly (and not overused). One cannot expect everyone to program at the sharp end. In addition, there is always room for improvement. No one is born as a master.Uwe Raabehttps://www.blogger.com/profile/08727704609084298159noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-36215941287091583372014-07-12T05:50:51.403-04:002014-07-12T05:50:51.403-04:00Every programmer who had to maintain some huge cod...Every programmer who had to maintain some huge code base with globals or statics knows what we are talking about.<br />You are perfectly right: it is not a matter of dogmatism or coding-by-the-book. It is about being pragmatic and efficient.<br /><br />IoC/DI are great tools for the lazy programmer!<br />:)Arnaudhttps://www.blogger.com/profile/00421394020248758254noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-24691221514815153072014-07-12T04:51:48.559-04:002014-07-12T04:51:48.559-04:00Could not have said this any better, Arnaud. Thank...Could not have said this any better, Arnaud. Thanks for your intervention.<br />It doesn't matter how its called or technically done. The point is that global state is bad, be it a global variable, as static class or a function that returns a singleton. I suggest watching this video to fully understand why: https://www.youtube.com/watch?v=-FRm3VPhseIStefan Glienkehttps://www.blogger.com/profile/05509404049325709406noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-68115782828995815722014-07-12T04:39:49.414-04:002014-07-12T04:39:49.414-04:00Do not use this trick, please.
Static vars are IM...Do not use this trick, please.<br /><br />Static vars are IMHO just as bad as global variables.<br />See http://blog.synopse.info/post/2014/07/12/staticsareglobalsArnaudhttps://www.blogger.com/profile/00421394020248758254noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-40000902588116028982014-07-12T04:20:33.733-04:002014-07-12T04:20:33.733-04:00Using such static declaration is just another way ...Using such static declaration is just another way of creating a global variable.<br />This is just a global variable in disguise.<br />In fact, the generated asm will be just like a global variable!<br /><br />It encapsulates the global declaration within a class name space, but it is still IMHO a very wrong design.<br />I've seen so many C# or Java code which used such a pattern (there is no global variable in those languages), and it has the same disadvantages as global variables.<br />Code is just not re-entrant nor thread-safe.<br />Nightmare to debug and let evolve.<br /><br />Imagine one day you would like to re-use the code of your app, then run your business logic code on a server.<br />You would like to re-use your existing code.<br />But since all your client instances would have to share the same global data, stored in static variables, you would be stuck to make the running instances un-coupled.<br /><br />This just breaks the SOLID principles.<br />What should be done instead of such deprecated globals is to use true classes (or even better interfaces), then use Inversion Of Control / Dependency Injection.<br />See http://blog.synopse.info/post/2012/10/14/Interfaces-in-practice%3A-dependency-injection,-stubs-and-mocks or Nick Hodges' book - https://leanpub.com/codingindelphiArnaudhttps://www.blogger.com/profile/00421394020248758254noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-80274796417563229882014-07-12T04:15:50.251-04:002014-07-12T04:15:50.251-04:00Well done! And now replace the initialization sect...Well done! And now replace the initialization section with a class constructor.Uwe Raabehttps://www.blogger.com/profile/08727704609084298159noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-36697349309798680572014-07-12T03:59:54.403-04:002014-07-12T03:59:54.403-04:00Thank you you can declare (as I found out) the set...Thank you you can declare (as I found out) the set function as private nd the init code still will execute<br /><br /> TAppInfo = class<br />private <br /> class function SetAppInfoPath(CSIDL:integer): string; static; <br /> public<br /> const<br /> AppInfoWebsiteName : string = 'www.creditcardmath.com';<br /> AppInfoWebsiteURL : string = 'http://www.zilchworks.com/buynow.asp';<br /> AppInfoCopyright : string = 'Copyright 1994-2014 © by Michael J. Riley. All rights reserved.';<br /> AppInfoName : string = 'Credit Card Math';<br /> class var<br /> AppInfoPathData : string;<br /> AppInfoPathLocal : string;<br /> <br /> class procedure GoToAppInfoWebsiteURL; static;<br /> end;<br />Anonymoushttps://www.blogger.com/profile/08896080676079852034noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-91049109076934579682014-07-12T03:01:56.470-04:002014-07-12T03:01:56.470-04:00You don't need a static class for this althoug...You don't need a static class for this although it is nice. Delphi 7 pulls this off by simply extantiating something like TGlobal from initialization and freeing it finalization of your Globals unit. Not as slick as a static class but for a few lines essentially the same thing.<br /><br />I haven't tried this but you could also do a helper class object on TApplication.Cameronhttps://www.blogger.com/profile/12643798206251661265noreply@blogger.comtag:blogger.com,1999:blog-8832291873344926372.post-48005298202002868052014-07-12T01:14:51.477-04:002014-07-12T01:14:51.477-04:00Wow!!! this is a real useful technique.
Now I wil...Wow!!! this is a real useful technique.<br /><br />Now I will be able to exchange data between my different modules easily!<br /><br />Thanks for this!<br />Yogi Yanghttps://www.blogger.com/profile/17700024840897265976noreply@blogger.com