June 8, 2016
As many of you know, Embarcadero made a change to the Delphi compiler in 10.1 Berlin to close an existing bug that allowed access to private data of any class via a class helper. Developers who were leveraging this hack would need a migration strategy.
As many of you know, Embarcadero made a change to the Delphi compiler in 10.1 Berlin to close an existing bug that allowed access to private data of any class via a class helper. Developers who were leveraging this hack would need a migration strategy.
Private is... Private
For quite some time, there was a bug in the Delphi compiler that ended up allowing class helper methods to access private fields of the class they helped, regardless of the unit in which the class was declared. This “hack” basically broke OOP encapsulation rules. To enforce visibility semantics, class and record helpers in most recent versions of Object Pascal compilers (starting with 10.1 Berlin) cannot access private members of the classes or records that they extend. Notice that protected members, on the other hand, are accessible to class helpers, exactly like they are to derived classes.
(By the way, this issue was covered last month also by Craig at http://chapmanworld.com/2016/05/03/the-encapsulation-bug-that-was-a-feature/)
A number of developers found this hack quite handy for accessing private fields and methods of the class library or component they use and we got complaints during the beta and after the product release about this change. We spent a lot of time evaluating different options and solutions... but could not find any better option. The request of "leave this bug open, it is a feature we rely upon" does make sense, but ultimately allowing access to private fields in libraries implies going against the main pillar of object-oriented programming and the last 20 years of computer languages. Not only that, in practical terms it means having to maintain some sort of compatibility of the private portion of core library classes in the future, avoid changing any behavior. The reason these private features are private is exactly to allow developer freedom to change them in the future!
We also got requests to leave this as a temporarily switch, but that would have only delayed the decision (and the code update) to the next release, while leaving the bug open. Another point I heard a lot was about other programming languages allowing the same type of private access. C++ has a "friend class" construct, but the difference there is you grant friendship to another class, while that other class cannot just claim friendship and access private data. Imagine Facebook would allow any person to claim friendship (not be granted friendship) and access your information at will.
Other languages like Java and C# allow access to private fields via reflection... which is exactly what Delphi also allows, and has allowed for many years now since extended RTTI was introduced. Now the question becomes: if this is possible anyway, why don't let developers do it the easy way? The issue is developers should not be encouraged to access private data and they should clearly express their intention in code, clearly indicating what they are doing. To me, using RTTI satisfies these requirements better.
Again, this is not a decision that was taken lightly. We even invited a former R&D engineer, who originally added class helpers to the language, to share his opinion with us and in the beta forums. That resulted in some very interesting conversations.
But is Private Always Needed?
An important point that was highlighted by this change in the compiler, is that in some cases libraries keep access to some information private without a full evaluation of the scenarios in which developers might need access to those fields or methods. During the beta, developers pointed out fields or methods they really needed to access to, and the team either moved some fields to protected, added additional access properties (still keeping the data private), or introduced more flexibility in other ways. These are specific titles of QP issues that have been addressed during the beta (but there have been many more in this and the previous releases):
Private access issue: TCustomForm.FTextHeight
Private access issue: TBitmap.FAlphaFormat
Private access issue: VCL TBitmap.FImage / TBitmapImage.FDib
TListView: It should be possible to define own calls for TListColumn
Mark CreateRoot method in ShellCtrls virtual and elevate visibility Root fields
FMX TTreeViewItem needs protected ChildrenOffset
TRTTIParameter.Parent not pointing to correct TRttiMethod instance (affects Spring4D)
Change visibility specifiers in all style hook classes
Private access issue: TStyleManager.FSystemStyle
We are more than willing to keep evaluating more cases in which exposing a private member makes sense, and the same you should probably ask to other library vendors.
But What About my Code?
Most of Delphi developers have been able to move their code to 10.1 Berlin easily, as they were not leveraging this hack or did it only occasionally and were able to bypass the problem. There are others who are experiencing bigger problems. What are the options?
One option is to consider if changes already done to the RTL or VCL libraries have already made the private access redundant. At times this is the case (and more often that some people think). If this is not the case, you might also want to consider if that is really needed. If it does, apply one of the workarounds below and file a quality portal report asking Embarcadero to open access that specific information.
The cleaner solution for private access is generally the use of RTTI. Something like
RTTIContext.GetType('classname').GetField('fieldname').GetValue(anObject)
might do the trick. Beside the extra code (which can be simplified and embedded in a class helper!) the drawback is the significantly slower performance. However, you can also keep the RTTI context and the TRttiField object around for optimization. This is a small working VCL-based code snippet (even if not a terribly useful one):
var
rttiCtx: TRTTIContext;
begin
ShowMessage (rttiCtx.GetType(TForm).GetField('FClientWidth').GetValue (self).ToString);
If you need a fast, direct solution a real hack is to declare a data structure matching the class and doing a hard type cast among the two classes. Or just get the field position in the class structure and do a pointer-based access. These approaches are clearly not recommended, but (in corner cases) they offer top performance.
For some alternative coding styles and some discussions, you can see among other sources:
http://stackoverflow.com/questions/37351215/how-to-access-a-private-field-from-a-class-helper-in-delphi-10-1-berlin
http://stackoverflow.com/questions/36716363/how-to-access-private-methods-without-helpers
http://stackoverflow.com/questions/31972202/accessing-private-fields-from-a-class-helper
Compatibility versus Evolution
Even if this is a very specific scenario, having to do more with a bug than with a feature, the issue we faced while deciding for a direction to take in this case is one between maintaining perfect compatibility with all existing code and evolving the tool. In many cases the two can coexist (and Delphi has one of the best track records with 20 years of backwards compatibility), but in same scenarios you have to privilege one over the other. In this case the call was to fix a really critical bug. I know some of you would disagree...
posted by
marcocantu @ 2:16PM | 38 Comments
[0 Pending]
38 Comments
Closing the Class Helpers Private Access Loophole
Hi Marco,
Please don't fall back on your OOP purist mantra for
this breaking change. It is disingenuous to say that
you guys did this for OOP encapsulation reasons. If
you really cared about OOP purity then fix TFiler,
TReader and TWriter so they didn't share each others
private fields and were actually extensible. There are
tons of other examples of bad encapsulation in the
VCL, especially the older classes. As you noted, there
are lots of different ways of accessing a classes
private fields, and you just removed the most
convenient one. Of course it is not desirable, and is
only used in the cases when the original component
vendor (usually embarcadero) has flaws in the code
that cannot be fixed in any other way. Simply making
it it harder for your customers in order to promote
some purist mantra is just silly (especially when you
do not close the other ways of doing it). Of course,
having class helpers access private fields (and all
the other methods of accessing private fields) have
their risks for the person who does it, and they have
to evaluate what to do with every new release of the
components set they are patching. No one who does this
expects the component vendor to maintain compatibility
of the private variables so hacks will work.
The fact that you have devoted your time and energy to
this, in light of the tons of other things you could
be doing is very mysterious to me. I bet you had 100x
more requests to extend the class helpers by allowing
multiple helpers in different units, than requests to
eliminate this loophole, yet you chose to devote time
and effort to eliminating this loophole. How many
customers actually complained that having this
loophole there was harming their code?
Comment by David Novo on June 8, 15:09
Closing the Class Helpers Private Access Loophole
David,
suggest with withhold closing this bug because we have other
encapsulation issues (that need to be demonstrated, those you point
to are just implementation details) is like saying never start to fix
issues. It was a bug, and totally unintended.
You might not believe it, but this issue was reported by a customer
who asked us to fix it. Had we been aware, we would have close it
much sooner.
You say this is only used when needed, and this is also my point,
as it was, it was way too easy to access private fields, with or
without knowledge (could be a nice cut and past of code from
Internet). Making this more "intentional" was a key point.
Comment by Marco Cantu
[http://www.marcocantu.com]
on June 8, 15:56
Closing the Class Helpers Private Access Loophole
The truth is that the "private" part of the data, while seemingly a
good idea, is a poor design pattern.
The fact that we are this far from when Objects were introduced in
TP 5.5, and we are still having to hack into objects to get our jobs
done - we rely on the original code writers to have done their jobs
perfectly when data is hidden behind the "private" wall. Clearly,
this isn't a feasible goal and the hacks that have followed support
that.
Sealed classes are perhaps the ultimate dead end of this concept
that the original author got everything perfect. I can not count the
number of times I have wanted to extend a sealed class, but instead
had to write ugly hack arounds, or flat out replacements just
because of the sealed class.
Frankly, I think both private and sealed should be removed from
the language rather than strengthened - and the number of hacks
people have to write supports that view.
We don't write perfect code, it is probably time to stop pretending
we did.
Incidentally, there is another hack for private fields if they are
exposed by a property reader without a function -
@Object.Property can give you the address of the underlying
private data. And yes, I've had to use it because someone thought
they knew how to do my task better than me.
Comment by C Johnson on June 8, 16:56
Closing the Class Helpers Private Access Loophole
C Johnson,
while I disagree with you on the fact sealed classes or private data
are a bad idea, I'm not saying hacks should be disallowed. But
building that as a "feature" is not a good point. Large libraries
require private implementations, to me.
And this is exactly because we don't write perfect code in those
classes, and need to be able to change it with minimal effects on
customers code. Delphi ships with libraries source code for a
reason...
Comment by Marco Cantu
[http://www.marcocantu.com]
on June 8, 17:00
Closing the Class Helpers Private Access Loophole
I am also a bit miffed about this. I am totally with
what David says: "No one who does this expects the
component vendor to maintain compatibility of the
private variables so hacks will work.".
I mostly needed the private "bug" for helpers fixing
classes from the RTL. This will probably force us to
either keep redundant copies of classes from the RTL
or use Reflection. Which is exactly the same thing, just
way slower and less convenient.
Comment by Fronzel Neekburm on June 8, 17:07
Closing the Class Helpers Private Access Loophole
Fronzel,
understood -- I know this is not ideal. However, what about
evaluating your fixes and trying to fix the RTL itself, no that fewer
hacks are needed. We did a lot of effort in that direction, but clearly
much more is needed.
Comment by Marco Cantu
[http://www.marcocantu.com]
on June 8, 17:11
Closing the Class Helpers Private Access Loophole
If you treat breaking encapsulation like a feature
instead of a hack, then more and more code will be
written that relies on private implementations.
And that code will be brittle.
I understand that this will be inconvenient for anyone
using it now, but I think it's a long term improvement.
Comment by Bruce McGee on June 8, 17:41
Closing the Class Helpers Private Access Loophole
I completely agree with Embarcadero's decision to
close this bug.
Private fields are in most cases private for a reason.
For instance in my code I often declare fields private
because rest of my class's code expect data in that
field to be within specific rage. So I ensure this by
declaring field private and then using property setter
method to validate data before it is written into the
field. Failing to do so could lead to bunch of
unexpected scenarios.
And I bet there are bunch of other scenarios where
private fields are useful.
Now most of you that are against this decision claim
that you have to use such hacks in order to extend
that specific code.
Have you ever thought of that perhaps the original
author of that code does not want other people to
extend their code?
If the original author does not mind you extending
his code then he also won't mind changing his own
code to allow you do that by moving private field
into protected section or adding additional property
for accessing that filed.
In some parts of my code I also use private fields
with intention to prevent others from extending my
own code. Why I do this?
In most cases I have plans for further extending the
code myself.
And since I have worked hard so far on this code and
will work hard even more to further implement
planned features into it I think I have all the right to
control of how my code is used.
Now this is not in line with open source code trend
that is becoming more and more popular.
But I'm mostly writing closed sourced code.
And when I do write open sourced code I allow
anybody to change it so you would not have to use
any hacks but instead just make small change to my
existing code.
Comment by SilverWarior on June 8, 17:57
Closing the Class Helpers Private Access Loophole
a) 10 years old bug (introduced and wide recommended
as a solution from D2007), is not a bug, but feature
b) this was nice solution, every other is worse (asm
calls, RTTI, copying units)
c) first disable accessing private members from same
unit, this solve many cases
d) IMHO private keyword for component or library
vendor is prohibited
and so on
Comment by Radek
[http://delphi.cz]
on June 8, 20:17
Don't like it
I've already used this hack myself many times, to fix RTL/VCL
bugs. Without it you are only doing things worse. People will tend
to make everything protected (which is a bad thing!) and replace
whole classes just to fix a bug (which is even worse than class
helpers).
I understand that PRIVATE data is vital and I don't want the idea of
making everything protected in order to be accessible by
descendant classes. But removing the only hack available with
good performance is not the way to go. Reflection is part of C# and
Java universe since day one, but this is not true for Delphi. Many
Delphi applications are compiled without extended RTTI and this
won't change.
Anyway, from the thousand open bugs and important feature
requests, really amazes me the fact that you guys spent some time
fixing one of the few "good" bugs.... and you are actually aware of
how important this "bug" was for Delphi developers, because it
made you write one of the biggest blog posts of 2016, right?
Comment by Alexandre Machado on June 8, 21:32
Closing the Class Helpers Private Access Loophole
"Large libraries require private implementations, to me"
Yes, Marco, you are correct. Libraries require private stuff.
However, this is a convention. When I put data in a private section
I'm saying to all users of that class: "This is MY private stuff. I'll
change it without any further notice at my will. If you touch here,
you just CAN'T complain if/when I break it". Simple as that. If the
user decide to hack it and change the private details of that class
(e.g. because of a bug that he needs to fix urgently, like I have done
dozens of times), he is on his own. But, he is aware of that!!!
Comment by Alexandre Machado on June 9, 01:01
Closing the Class Helpers Private Access Loophole
When these helpers first appeared and access to
private variables were possible that made a change and
advancement to the language. Reverting this feature
and relying on supposed OOP principles as a rationale,
helpers now become no better than descendent objects.
If anything helpers are a weaker version of a
descendent object.
So you have gone from advancing the language to adding
a "feature" that already exists - not much in the way
of development.
Comment by James Shelton on June 9, 02:37
Closing the Class Helpers Private Access Loophole
Radek,
a) "Wide recommended as a solution"? Where? It was never
documented by Embarcadero and it is referenced on a couple of
independent blogs, as a passing reference.
It was never a wide recommended solution, and it is absolutely a bug.
b) if worse meaning developer might explicitly use other features,
this is actually the intention
c) Disable private access from same unit will break a large amount of
code and offer no advantage... how is that related
d) at that point why create components? let's share code snippets
online so you can change at will... Honestly, you guys complaining
about private being useless are just throwing out the baby with the
hot water...
Comment by Marco Cantu
[http://www.marcocantu.com]
on June 9, 07:54
Closing the Class Helpers Private Access Loophole
James,
helpers offers several features, private access is not one of them --
so hacking private is not an advancement in the language, and the
fact you cannot do it in any other language explains something.
"Supposed OOP rationale"? Encapsulation is just programming 101.
Comment by Marco Cantu
[http://www.marcocantu.com]
on June 9, 07:57
Closing the Class Helpers Private Access Loophole
Alexandre,
Private for libraries is not a convention. It is a fundamental feature.
With the class helpers private access, developers can use private
members WITHOUT EVEN NOTICING. This contrasts with what
you are saying... I agree if the user decides to hack is fine, but it
needs to be a conscious and specific decision, not something that just
happens because the language allows it.
It is exactly the developer awareness that was a key issue. Using
RTTI makes is a much more conscious decision, to me. And so using
other specific hacks.
Comment by Marco Cantu
[http://www.marcocantu.com]
on June 9, 08:02
Closing the Class Helpers Private Access Loophole
@Marco - "Not even noticing" - I was not aware of
that, good point. I am probably convinced now :-)
Comment by Fronzel Neekburm on June 9, 08:16
Closing the Class Helpers Private Access Loophole
I didn't say that private is a convention. The convention is: When I
put something in private section it should not be touched UNLESS
there is a very good reason and knowledge behind it, like:
Embarcadero released a buggy Delphi version, I bought it and I just
can't wait 6 months for a fix, so I use class helpers to fix it myself.
That's a very good and legitimate reason to mess with private stuff.
Or, do you guys at Embarcadero really think that writing class
helpers to change private fields is a common thing, something that
we do in our daily job???
Comment by Alexandre Machado on June 9, 11:22
Closing the Class Helpers Private Access Loophole
Thanks for a good move in the newest Delphi. To be sincere, if
there is a well-done OOP programming language, there could not
be ANY single way to access the private fields. "Hacks" indincates
the software language weakness.
Also that, what Radek said ("first disable accessing private
members from same unit, this solve many cases"), could be done
using the "strict" prefix. It could not be done easily for backward
compatibility.
But, the truth is, you can win more users, if you understand that the
future of class helpers is not just to fix problems. I see class helpers
as tool to extend basic classes - even my own ones - without
redeclaring existing types and derivation. I can use base type in
one place, but extend it in other - but my base class remain small
and tidy. Please concider this in the newer Tokio version. :)
Cheers!
Comment by Jacek Krawczyk
[http://www.oeggmbh.com]
on June 9, 13:27
Closing the Class Helpers Private Access Loophole
@SilverWarrior:
<blockquote>Now most of you that are against this
decision claim that you have to use such hacks in
order to extend that specific code.
Have you ever thought of that perhaps the original
author of that code does not want other people to
extend their code?</blockquote>
If the original author failed to consider an important
use case for his code, I don't really care whether he
wanted it to be extended or not. Encapsulation is
good, up to a point, but beyond that it's horrible.
I've seen many more problems result from
over-encapsulation than from insufficient encapsulation.
Comment by Mason Wheeler
[http://tech.turbu-rpg.com]
on June 9, 13:59
Closing the Class Helpers Private Access Loophole
Marco, i m personally very sad about this ! Very sad that you spend
time on this, when their is zillions other "real" bug to correct on
delphi. Right now we have no other choice and we must copy/past
the entire unit to have access to a private field (RTTI it's a joke,
because it's too much slow), and their is many (many) case where
it's necessary to have access to private field because nothing is
perfect in this world, ESPECIALLY in delphi fmx.
Do you really think this way (the way you force us to go,
copy/past) is a more better way than using class helper hack? your
decision (that was taken lightly?) is the worse decision you could
made :
1/ now we must copy/past the entire unit to correct it (and most of
the time it's not only one unit we must copy past)
2/ the compile time on android/ios is now TERRIBLE !!
3/ now everytime a new version of delphi will come we will very
very not want to BUY IT because the migration of the unit we
copy/past with the new unit will be very PAINFULL!
sad is not the good word, ANGRY is a better word !
Comment by Loki on June 9, 15:32
Closing the Class Helpers Private Access Loophole
I am totally with those who said you should disable private access
within a unit first. Why? Because that would force embarcadero
(and others but embarcadero are the biggest problem) to refactor
there classes so that only members which truly are internal are
private. Right now the rtl and vcl is full of classes which only work
because embarcadero rely on same unit access to private. When
other developers try to use these classes they find they are too
inflexible to use, hence our need for ways around private.
As for using rtti, we currently limit rtti generation to avoid blowing
out exe size. So enabling it on private members is not a great
solution for us. We will probably hack the Delphi files instead (and
have deal with making sure design time doesn't use/compile any
interface changes which is a pain in the butt) which makes a
mockery of the suggestion that this change will reduce developer
reliance on internal implementation!
Comment by David Brennan on June 9, 19:23
Closing the Class Helpers Private Access Loophole
Loki, you don't really to copy and paste an entire unit, you just add
the original unit to your project and modify it, like it was done many
times in the past.
But I don't think the issue is as common as you depict it, most
developers using FMX don't need to use these hacks. RTTI is not a
joke and there are other hacks to access members by pointer if you
need performance.
And the reason I'm spending time on this is a few people are very
upset of very angry because we are closing the private access
loophole -- otherwise I won't be spending much time on it.
===
To those asking for private working as private, that's been around
many years and called strict private. But it a class uses a private
implementation type for a good reason, this is often meant to stay
private.
Comment by Marco Cantu
[http://www.marcocantu.com]
on June 9, 20:09
Closing the Class Helpers Private Access Loophole
@Mason Wheeler
I agree with you that over-encapsulation is terrible.
I'm not denying that.
But using hacks to avoid encapsulation is also not
right approach. Especially if those hacks make your
code potentially buggy. For instance change of
original code could break your code.
Now like others you would probably say that you
were aware of that before you decided to use that
hack. That still doesn't make it right. In fact I think
that is completely wrong. Why? Because you are
consciously writing bad code.
You are also presenting a hypothetical scenario when
original author fails to consider all important use
cases for his code. Now what is better:
- that you go and egoistically extend his code using
hacks and potentially dangerous code that can
backfire in your face any time
- or that you contact the author of original code and
inform him of potential use case for his code that he
missed and that together you make required changes
to both his and your code so they can work perfectly
together. And by using this approach you could
achieve even more. How?
By presenting original author with a new way of
using his own code you are likely to change his point
of view on his code which could potentially lead to
the case where he could come up with even more use
case for his own code since he will be now looking
at it from a new perspective. And this is how a true
progress is made.
@Everyone
I guess that everyone of us here agree that improper
use of private fields can severely limit code
encapsulation. So the main question that we should
be asking is how do we fix that.
I don't think that removing private fields altogether
would fix that.
No the better solution would be to teach people so
they better know when private fields should be used
and when not.
To do this you need to teach people to use and work
with classes and interfaces properly. And here I'm
afraid Embarcadero is failing miserably.
I mean there isn't a single example that ships with
Delphi which would explain of how you can extend
an existing class or write a new one yourself. If there
is one please do correct me.
Also I'm having troubles finding any good Delphi
books that would cover in depth usage of classes or
interfaces in Delphi.
Comment by SilverWarior on June 10, 01:35
Closing the Class Helpers Private Access Loophole
Marco,
If encapsulation is just programming 101, then I
wonder when you will remove access to privates via
RTTI - surely by that comment this gross divergence
from the basics must be on the roadmap and will be
addressed!
More seriously though, even RTTI was never part of
original OOP. Historically, once we moved to third
generation languages any form of RTTI was thought to
be bad practice and potential malware, until 1982 and
the advent of 3-Lisp - now most languages offer it in
one guise or another - so when it was first
(re)introduced did the fact that no other language was
offering that feature sway the doctorate of Brian
Smith? Did its absence explain something to him, that
it was in fact not a good thing?
I would also ask (retorically), why would I now create
a Helper - why won't/shouldn't I just declare a
descendent class - and then refactor my code to
reference my new descendent class? I get no further
benefit from a Helper apart from not having to use the
refactor tool (or notepad++ over my entire library).
Obviously there are some very strong opinions on this
topic, I feel it is unfortunate the stance that has
been taken, judicious use of Helpers made some coding
nice, clean and simple - refactoring my codebase to
make RTTI calls from a dedicated library is just
disapointing - and the code looks more "hacky".
The earlier incarnation of a Helper allowed for work
arounds to mistakes or unfortunate designs in code.
Good OOP suggests that the visibility of a field be as
restricted as possible - but sometime we mere mortals
of programmers make mistakes or do not see the bigger
picture and set the visibility too low - I will even
admit to doing that myself (on the very odd occasion)
- the issue stands though with third party or inherent
VCL/FMX code when these mistakes occur we will no
longer have a neat work around whilst we wait for the
fix to be approved and implemented.
There is no need to respond to this comment. I
appreciate that you have addressed the comments by
myself and others before - it is now up to us as the
users of Delphi to either continue to use an earlier
version and remain pig-headed and dogmatic, or accept
that, on this rare occasion, backward compatibility
has now been broken and adjust our code accordingly.
Comment by James Shelton on June 10, 02:19
Closing the Class Helpers Private Access Loophole
Backward compatibility is important. Food for thought:
There is a "Ask HN: Oldest code you have written that is still in use?"
topic in the Hacker News community:
https://news.ycombinator.com/item?id=11718197
And under that topic there is a comment by byuu:
"There's an entire community of video game hackers (smwcentral.net)
using a cross-assembler I wrote in 2001 named xkas. I added a few minor
patches and by early 2004 I had released the final version, v06.
I never really intended for anyone to use it seriously. I made it for myself,
but went ahead and posted it online anyway. It is a 1500-line single-file,
nearly-commentless, nearly-spaceless abomination of code with no
documentation, and an endless list of critical bugs that every user keeps
encountering. They have elaborate workarounds for many of these bugs.
It became a negative feedback loop: "Why do we use xkas? Because
everything else is written in xkas", and so now even more code was
created and written in xkas. And so even though I've since written a
proper assembler that's dozens of times nicer, no one can/will use it.
Lately, people have been writing their own versions (in addition to
countless forks) that try to offer backward compatibility with all the crazy
parsing errors and (mis)features of xkas, like left-to-right evaluation of
math expressions, and the most convoluted macro evaluation system
you've ever seen (one user proved it was Turing complete and wrote a
Brainfuck parser in it.)
It's surreal. I feel terrible that so many people are stuck with this mess, but
even I can't stop it anymore :/".
Comment by Edwin Yip on June 11, 07:45
Closing the Class Helpers Private Access Loophole
That would be nice if one would be able to access all private data
via RTTI. I have, however, recently had a need accessing some
private methods inside TCustomForm and, for example, this
doesn't work:
TRttiContext.Create.GetType(TCustomForm).GetMethod('SetWin
dowState')
(it returns 'nil'). So basically I had to fall back to encoding hard
offsets into the source >:-(
Comment by Primoz Gabrijelcic
[http://thedelphigeek.com]
on June 13, 13:35
Closing the Class Helpers Private Access Loophole
Loophole? Maybe.
I use it to fix VCL bugs and/or extend some functionality.
RTTI does not allow me to do this (replace private
fields with my classes).
With Berlin I must include the whole modified
Vcl.DBCtrls.pas in the project - nasty thing to do.
Return the Feature back please. You can add a compiler
warning when accessing private members.
Comment by Pavel on June 13, 17:04
Closing the Class Helpers Private Access Loophole
This is probably the biggest regression in Delphi history?
Please don't explain me what is a good OOP programmer,
I'm too old for that now :-). I start to know
precisely what I'm doing.
I use helpers to solve performances issues in the VCL
and FMX libraries.
I choose this solution instead of making changes
directly in the source code itself and thrust me it's
much more OOP friendly than modify the VCL source code...
I just want to develop an efficient app, and now it
gone be more difficult.
I hope (pray..) you'll change you mind and reintroduce
this feature very soon.
senso+++
Comment by sensomusic
[http://www.sensomusic.com]
on June 13, 17:51
Closing the Class Helpers Private Access Loophole
few more comments :
Half of your text try to explain that a good OOP
programmer should not access to private fields, and
the other half about a hack to access to such private
fields.
Isn't it a contradiction?
Comment by sensomusic
[http://www.sensomusic.com]
on June 13, 18:04
Closing the Class Helpers Private Access Loophole
Ask self- for who is Delphi?
For develovers - your customers.
You call this bug - we call this feature.
You say it should not exists - we say we need it.
Do you see the difference on both side of the line?
If you need to remove unintended use of private then
you can add compiler directive like
{$ACCESS_PRIVATE}
Self.FLeft:= 5;
{$END}
or better something like this:
private Self.FLeft:= 5;
protected Self.XXX;
the last one remove already existing crap like
TSomeClassCracker = class(TSomeClass)
..
TSomeClassCracker
(objWithProtectedMember).protectedmember
regards,
Karol Bieniaszewski
Comment by Karol Bieniaszewski on June 14, 06:03
Closing the Class Helpers Private Access Loophole
Marco's reasoning is ALMOST perfect... pity it's not completely :)
So, what is the problem? Well, the problem is that - in Delphi - the
private keyword ALSO serves as a sort of "friend" for other classes
in the unit (at least, it did up to some time ago, but I never use this
because I am strict with my privates :D).
Now, the "helper" class is meant to integrate seamlessly with the
class it is helping, becoming essentially part of it. So we now have
a class that is meant to fully integrate with another and a section
that can be used (and I am not saying it is right, but it CAN BE
USED) to make a friend-sort-of-behaviour.
In light of this, the change is wrong in my view.
A
Comment by Andrea Raimondi on June 16, 10:56
Closing the Class Helpers Private Access Loophole
RTL/VCL/FMX have the RTTI method options off, which
means that access to protected/private methods with
RTTI is not possible.
http://stackoverflow.com/questions/37905306/rtti-access-to-private-methods-of-vcl-e-g-tcustomform-setwindowstate
I don't think closing this "bug" was a very smart move...
Comment by Dennis S on June 19, 16:46
Closing the Class Helpers Private Access Loophole
Just had a situation where the poor design of VCL.CaptionDockTree
forced me to create a derivative but because private methods are now
private, I had to copy code from that unit to a new one. A Class
Helper with private access would have solved the problem.
Comment by Mark on June 29, 17:09
Closing the Class Helpers Private Access Loophole
one more, look here:
http://stackoverflow.com/questions/36716363/how-to-access-
private-methods-without-helpers/36717896#36717896
do you really think that this go in better direction now?
That users run asm code to fix this? What is more dangerous for
your customers?
function THogeHelper.GetMethodAddr: Pointer;
asm
{$ifdef CPUX86}
LEA EAX, THoge.PrivateMethod
{$else}
LEA RAX, THoge.PrivateMethod
{$endif}
end;
Comment by Karol Bieniaszewski on June 30, 07:18
Closing the Class Helpers Private Access Loophole
Programming is really becoming funny.
People is now complaining when a bug is fixed.
Comment by Marcello Dias on July 10, 00:45
Closing the Class Helpers Private Access Loophole
@Marcello Dias: Depends what you call a bug. C# has
a comparable loophole in abstract classes which has
saved me days refactoring someone else's code.
Programming tools are there to solve problems. A tool
that prevents that is counter-productive.
Comment by Gordon Sandown on October 24, 08:03
Closing the Class Helpers Private Access Loophole
Hi Marco,
We have a number of issues with the VCL where we use
code hooks to fix the behavior. As part of these code
hooks we access private fields. We fix the VCL for a
number of reasons: Performance, WINE support and high
DPI support. In every case we have thought long and
hard before doing the code hooks and only used it as a
last resort short of updating the VCL source directly.
This change is almost a breaking change for us. We
still haven't upgraded to the latest version even
though we have a license for it.
In your blog you indicated that certain fields had
been moved to protected as part of the beta. Where can
we submit the list of fields that we need access to?
One example, for performance reasons we replace one of
the System.Classes.TWriter.Write overloads with our
own method. This method needs access to FStream and
FBufPos from TFiler. The alternative to this is to go
the route of building a class that matches the TFiler
definition so we can cast and gain access to the
fields or resign ourselves to updating the VCL source
for each upgrade.
A controlled, intentional, piece of code is a far
better approach. As has been suggested, it could
easily be locked behind a compiler define.
Comment by Dean Hill on January 12, 02:23
Closing the Class Helpers Private Access Loophole
I know it is too late to have anything done about this,
but I still can hardly believe the chutzpah of
Embarcadero making this breaking change. They say
they are fixing a "bug" but it is a *feature* when it is
used for a decade by coders to solve problems. And
until Emba uses strict private on *all* of their class
private fields to prevent friend classes from using
private fields, their claims about "OOP purity" are
totally bogus. Marco's complaint that people could
unknowingly access private fields is valid, but easily
solved with a compiler warning.... I could go on, but
apparently I have to spend my time finding new
ways to fix broken VCL and RTL code if I am to
stay current with Delphi releases.
Comment by Brandon Staggs
[http://brandonstaggs.com]
on January 13, 14:46
Post Your Comment
Click
here for posting
your feedback to this blog.
There are currently 0 pending (unapproved) messages.