dummzeuch 1505 Posted April 18, 2020 (edited) TJSONObject.Size was deprecated and replaced by .Count in Delphi XE6, so up to Delphi XE5 you have to use .Size (because .Count doesn't exist) and from Delphi XE6 on you either live with the deprecated warnings (.Size is still available in Delphi 10.3) or replace the calls with .Count. But even if you accept those warnings, sooner or later you will have to address them because Embarcadero decided to finally remove the deprecated code. So, what if you want your code to compile on all versions that support JSON without warnings? E.g. in my u_dzGoogleTranslate unit there is the following code: if o.Size <> 3 then raise Exception.CreateFmt(_('Parsing error on JSON answer: Root object size is %d not 3.'), [o.Size]); where o is a TJSONObject. This compiles fine in all Delphi versions that have JSON support but starts throwing deprecated warnings from Delphi XE6 on. So, what are my options? I could IFDEF all those calls: {$IFDEF JSONOBJ_HAS_COUNT} if o.Count <> 3 then raise Exception.CreateFmt(_('Parsing error on JSON answer: Root object size is %d not 3.'), [o.Count]); {$ELSE} if o.Size <> 3 then raise Exception.CreateFmt(_('Parsing error on JSON answer: Root object size is %d not 3.'), [o.Size]); {$ENDIF} Which would be fine for one single line, but there are dozens of similar lines which renders the code unreadable. I could IFDEF complete functions instead but that would mean to fix any bug in all these functions. I could add a class helper for TJSONObject that adds the missing Count function for earlier versions (I think they all support class helpers, so that would be doable.) I could derive TdzJSONObject from TJSONObject and add the missing Count function but that would not work for RTL code that returns a TJSONObject. I could write an inlined wrapper function JSONObject_size that encapsulates that IFDEF. That would improve readability but but would still be ugly. I could drop support for Delphi XE5 or earlier, but I'd rather not. You never know when you're going to need that. Can you think of any other options? Edited April 18, 2020 by dummzeuch record helper -> class helper Share this post Link to post
Vandrovnik 214 Posted April 18, 2020 Do you have an idea, how many users really need new functions for old versions of Delphi? If there are not many of them, I would suggest to drop support for old versions - you can probably spend your time better than keeping code compatible with old Delphi... Share this post Link to post
dummzeuch 1505 Posted April 18, 2020 (edited) 17 hours ago, Vandrovnik said: Do you have an idea, how many users really need new functions for old versions of Delphi? If there are not many of them, I would suggest to drop support for old versions - you can probably spend your time better than keeping code compatible with old Delphi... OK, I should have provided some background: This library is a hobby project of mine, there are only a very limited number of people that use it: I myself at work my two coworkers (but only in Delphi 2007, XE2 and lately 10.2) I myself (again) in many of my open source projects that support various versions of Delphi (for GExperts that means Delphi 6 and later), but not all units from that library are important for this Even though this library has been open source (MPL) for at least 15 years, I have never heard of anybody else using it (Which I think is a shame, but hey, they just don't know what they are missing out. 😉 ) So, I don't want to drop compatibility if it can be kept without too much hassle, I'm asking for alternatives. Believe it or not: Maintaining backwards compatibility can be fun if it involves creative (mis-)uses of language features. I am programming in Delphi for fun, not just for the paycheck, otherwise I would have dropped Delphi for Visual Studio more than 10 years ago. Edited April 19, 2020 by dummzeuch Share this post Link to post
Remy Lebeau 1396 Posted April 18, 2020 9 hours ago, dummzeuch said: So, what are my options? I could IFDEF all those calls: {$IFDEF JSONOBJ_HAS_COUNT} if o.Count <> 3 then raise Exception.CreateFmt(_('Parsing error on JSON answer: Root object size is %d not 3.'), [o.Count]); {$ELSE} if o.Size <> 3 then raise Exception.CreateFmt(_('Parsing error on JSON answer: Root object size is %d not 3.'), [o.Size]); {$ENDIF} I would rewrite that to something more like this instead. Don't duplicate code that doesn't need to be duplicated: var LCount: Integer; LCount := o.{$IFDEF JSONOBJ_HAS_COUNT}Count{$ELSE}Size{$ENDIF}; if LCount <> 3 then raise Exception.CreateFmt(_('Parsing error on JSON answer: Root object size is %d not 3.'), [LCount]); 9 hours ago, dummzeuch said: Which would be fine for one single line, but there are dozens of similar lines which renders the code unreadable. I could IFDEF complete functions instead but that would mean to fix any bug in all these functions. I could add a class helper for TJSONObject that adds the missing Count function for earlier versions (I think they all support class helpers, so that would be doable.) I could derive TdzJSONObject from TJSONObject and add the missing Count function but that would not work for RTL code that returns a TJSONObject. I could write an inlined wrapper function JSONObject_size that encapsulates that IFDEF. That would improve readability but but would still be ugly. I could drop support for Delphi XE5 or earlier, but I'd rather not. You never know when you're going to need that. I would just write a class helper or separate function, and IFDEF the code inside of it. Class helpers were first introduced in Delphi 2005, but were buggy and not officially supported until Delphi 2006. JSON was first introduced in Delphi 2010. 2 1 Share this post Link to post
Uwe Raabe 2057 Posted April 19, 2020 I usually write class helper for this. They can easily be removed when older versions are dropped. 2 Share this post Link to post
A.M. Hoornweg 144 Posted April 19, 2020 I also usually use class helpers, that implement the new methods for the old Delphi versions. Not the other way around! 1 Share this post Link to post
Fr0sT.Brutal 900 Posted April 19, 2020 AFAIK there could be only one class helper until some of 10s so adding this you're blocking a user from creating his own ones. In this very case, you can define a descendant class where Count property would be declared for older compilers (GetSize is protected so there's no problem). Then you can typecast or just use type name as a pseudonym for your derived class: {$IFDEF Old_Compiler} TCompatJSONObject = class(Json.TJSONObject); property Count: Integer read GetSize; end; TJSONObject = TCompatJSONObject; {$ENDIF} If I get it right, non-published properties are "virtual" (just a syntax sugar) so these classes will even be binary-identical. In general, there's no convenient universal solution, every case should be considered individually. Share this post Link to post
Uwe Raabe 2057 Posted April 19, 2020 (edited) 1 hour ago, Fr0sT.Brutal said: AFAIK there could be only one class helper until some of 10s so adding this you're blocking a user from creating his own ones. You can inherit from a class helper, so it is still possible to extend that one. Alas, that doesn't work for record helpers. Edited April 19, 2020 by Uwe Raabe Share this post Link to post
Fr0sT.Brutal 900 Posted April 20, 2020 15 hours ago, Uwe Raabe said: You can inherit from a class helper, so it is still possible to extend that one. Alas, that doesn't work for record helpers. Oh, you're right, thanks! Then helpers seem the most convenient way to go. Share this post Link to post