|
# Lines |
Joanna Carter
wrote
on 12-Feb-2010:
Having followed the 91 post thread that Rudy started by quoting Allen
Bauer's blog posting, I can only assume that nobody actually read the
blog in question.
We have had all sorts of arguments for and against globals, but nobody
seemed to realise that Allen's article was about calling FreeAndNil *in
|
42 |
Dalija Prasnikar
replied
on 12-Feb-2010:
(snip)
Don't know about the others, but I have read the blog and I fully agree with
you, Allen and Rudy about calling FreeAndNil in the destructor.
I have never used it in that context.
Dalija Prasnikar
|
50 |
Tom Brunberg
replied
on 12-Feb-2010:
"Joanna Carter" wrote:
(snip)
Dear Joanna,
Although you did not address me (because I'm not a FreeAndNil
fanatic),
may I participate in stiring the soup. I read the blog and noticed
|
132 |
Paul Blommaerts
replied
on 12-Feb-2010:
(snip)
It can be justable , fi I work a lot with async communication and have to
create a memorystream to send the data.
It can have multiple events when the communication ends and I use FreeAndNil
in any of these events.
Since I'm never sure which events will occur after freeing the stream, I use
|
26 |
Jens Gruschel
replied
on 12-Feb-2010:
(snip)
I've just searched my code, too, and I found less than 10 occurrences of
FreeAndNil within about 2000 files. Looks like I'm using FreeAndNil for some
factory methods. Since Delphi has class reference types I'm not using a lot of
factory methods at all. And if I do I usually reraise the exception in case of a
problem (after freeing the object) like this:
|
52 |
Roy Lambert
replied
on 12-Feb-2010:
Joanna
One question and a comment.
The question: you, and others, keep referring to design. I fail to see how design favours the use of one programming construct over another. Can you elucidate?
The comment: I decided to scan my apps and see how often I'd used FreeAndNil. I found two occurrences, and, since I don't care, I've altered those to Free. I also found 3 occurrences in code from a TeamB member. I then went on to scan all my third party and Borland/CodeGear code. It makes an interesting list:
Tim Young of ElevateSoft - DBISAM & ElevateDB
|
34 |
Joanna Carter
replied
on 12-Feb-2010:
Paul Blommaerts a __crit :
(snip)
You see, you've missed the point again.
The question is about using FreeAndNil in destructors, and only in
destructors, nowhere else.
Joanna
|
27 |
Joanna Carter
replied
on 12-Feb-2010:
Jens Gruschel a __crit :
But what about in destructors?
Joanna
--
Joanna Carter [TeamB|http://www.teamb.com]
|
6 |
Jens Gruschel
replied
on 12-Feb-2010:
(snip) Of course not. I thought that was clear before.
--
Jens Gruschel
http://www.pegtop.net
|
5 |
Joanna Carter
replied
on 12-Feb-2010:
Roy Lambert a __crit :
(snip)
The only question here is about using FreeAndNil in destructors, nowhere
else.
Joanna
--
|
16 |
Tom Brunberg
replied
on 12-Feb-2010:
"Paul Blommaerts" wrote:
(snip)
Hi Paul,
Thanks for you response. But just to clarify, do you recreate the
stream for the next data to send? If so, would it be possible to just
clear the stream and fill it with new data for the next transmission?
|
35 |
Tom Brunberg
replied
on 12-Feb-2010:
"Joanna Carter" wrote:
(snip)
Dear Joanna,
Sorry I highjacked your thread! I specifically asked in my post, that
Paul was answering, In what situations FreeAndNil would be
justifiable.
|
14 |
Bruce McGee
replied
on 12-Feb-2010:
(snip)
I tend to think that at least some FreeAndNil fanatics (of which, I am one) simply got overenthusiastic and used it everywhere we used to use free, including in destructors. I'll take my lumps for applying the rule too broadly and am happy for the broader perspective.
Another point I found interesting in Allan's post was the idea of filling in freed memory to produce a specific error and differentiate between accessing an object that hasn't been allocated yet and accessing one that has already been freed.
--
Regards
Bruce McGee
|
30 |
Christian Kaufmann
replied
on 12-Feb-2010:
(snip)
I never use FreeAndNil for a simple reason:
For objects, that are passed arround in an application we use
interfaces.
If you have a regular "TObject - class" and change that to be used
with interfaces with a "TInterfacedObject - class" behind it later,
|
30 |
Tom Brunberg
replied
on 12-Feb-2010:
"Jens Gruschel" wrote:
(snip)
Thank you Jens,
Interesting thoughts, but I have one question (hope it's not silly)
what is a null object?
Regards
|
49 |
Roy Lambert
replied
on 12-Feb-2010:
Joanna
I sit here suitably__ chastened.
I am not a FreeAndNil fanatic so perhaps I am not allowed to enter the discussion since your questions was
"So, can all you FreeAndNil fanatics please tell me if you can really
justify using your favourite construct *in the destructor* of a class?"
|
22 |
Wayne Niddery
replied
on 12-Feb-2010:
"Tom Brunberg" <✉to.me> wrote in message
news:✉forums.codegear.com...
(snip)
In some cases it is because they are holdovers from before *better* language
features and design practices were introduced.
In the case of FreeAndNil, it seems (to me at least) to have been introduced
|
126 |
Jens Gruschel
replied
on 12-Feb-2010:
(snip)
Instead of assigning nil to an object reference, one can also assign a special
object, which basically does nothing, but still supports the given interface.
An example for a null object:
{code}
type
|
58 |
Tom Brunberg
replied
on 12-Feb-2010:
"Wayne Niddery" wrote:
(snip)
Wayne,
Yeah, I guess we will allways have to carry with us the burden of
history in the name of backwards compatibility and easy upgrade.
To my pleasure IIRC the D2010 help says at some places something like
|
147 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Joanna Carter wrote:
(snip)
I did!
(snip)
Yes. I don't remember who started the talk about globals, or why anyway.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
23 |
Pieter Zijlstra
replied
on 12-Feb-2010:
Bruce McGee wrote:
(snip)
Probably pointing out something you already know ... but that is what
(stand-alone) FastMM4 does in FullDebugMode.
--
Pieter
|
26 |
Jens Gruschel
replied
on 12-Feb-2010:
(snip)
Such a form basically is a singleton with lazy initialization. And using nil
references for lazy initialization is quite common (if no proxy is used). After
freeing such an object the variable indicating that the object is not existing
has to be reset. FreeAndNil can be used, although it has no real benefit over
calling Free and setting the variable to nil afterwards. Well, FreeAndNil has a
|
59 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Tom Brunberg wrote:
(snip)
Sure.
Being the one who said that FreeAndNil (to me) indicates bad design (to
me), I think I'll have to modify it a bit: if I see someone use
FreeAndNil, it makes me suspect there may be bad design. There ARE uses
|
97 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Paul Blommaerts wrote:
(snip)
There we have it again. Design that allows the stream to be freed when
it is still accessible, or reversely, that enables access to such data
after the stream has ended, has to be questioned.
--
|
27 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Jens Gruschel wrote:
(snip)
I found one, in an old component, where I use the way Allen mentioned,
i.e. to save the state/data of a component in a private field while
re-creating the handle of the Windows control. FData is nil when there
is no such data (e.g. when the component is new), and not nil when the
|
40 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Wayne Niddery wrote:
(snip)
Allen mentions a valid use of FreeAndNil: when you must destroy and
re-create a Windows control, because setting a property requires it to
be re-created, you must sometimes save the internal data of that
control (say, a memo or a treeview) in some internal field, so after
|
47 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Roy Lambert wrote:
(snip)
Note that there are valid uses of FreeAndNil. One can't say that using
it is bad design, IMO. But if I see it, I do get very suspicious that
the design MIGHT be bad.
This suspicion comes from experience with all kinds of code that uses
|
48 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Joanna Carter wrote:
(snip)
That was what it was in your original message, but the thread has gone
beyond that.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
26 |
Loren Pechtel
replied
on 12-Feb-2010:
On Fri, 12 Feb 2010 01:32:41 -0800, Joanna Carter
<✉no.spam.for.me> wrote:
(snip)
The big discussion was about it's use in general.
I do agree that there's no reason for it in a destructor.
|
13 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Roy Lambert wrote:
(snip)
There is no reason why it should be used.
This is not about saving clock cycles, it is about the false sense of
"defensiveness" displayed by those who use it, which, IMO, may indicate
that, perhaps, they do not fully understand what they are actually
|
27 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Bruce McGee wrote:
(snip)
But, IMO, simply using it everywhere either shows that those who use it
either don't think about what they are actually doing, or they don't
fully understand it. Both are not good, IMO.
--
|
35 |
Rudy Velthuis (TeamB)
replied
on 12-Feb-2010:
Pieter Zijlstra wrote:
(snip)
And, since it probably takes time, should only be used in such
circumstances.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
27 |
Bruce McGee
replied
on 13-Feb-2010:
(snip)
I did know that, but I hadn't really thought about how I would take advantage of it. I've mostly been using FastMM's debug features to look for memory leaks.
--
Regards
Bruce McGee
Glooscap Software
|
15 |
Pieter Zijlstra
replied
on 13-Feb-2010:
Rudy Velthuis (TeamB) wrote:
(snip)
I dunno, ask Q ;-)
(snip) Yep :)
--
Pieter
|
18 |
Pieter Zijlstra
replied
on 13-Feb-2010:
Bruce McGee wrote:
(snip)
IMO it wouldn't hurt to do long runs (*) using FullDebugMode to detect
possible problems or just as an exercise to see how you code operates
under less than ideal circumstances.
(snip)
There is so much more you can do with the stand-alone version.
|
33 |
Tom Brunberg
replied
on 13-Feb-2010:
"Jens Gruschel" wrote:
(snip)
Jens,
OK, thanks, but I think I need to chew on this for a while.
Regards
Tom
|
61 |
Tom Brunberg
replied
on 13-Feb-2010:
"Jens Gruschel" wrote:
(snip)
Thank you Jens for confirming my thoughts
Regards
Tom
|
64 |
Hans-Peter Diettrich
replied
on 13-Feb-2010:
Joanna Carter schrieb:
(snip)
What's the problem with FreeAndNil, when using it does *not* affect an
"unproblematic" design?
What's the problem with a design that relies on FreeAndNil?
(other than *not* using FreeAndNil is against the design rules?)
|
48 |
Hans-Peter Diettrich
replied
on 13-Feb-2010:
Paul Blommaerts schrieb:
(snip)
ACK :-)
(snip)
Paranoia :-(
DoDi
|
10 |
Hans-Peter Diettrich
replied
on 13-Feb-2010:
Jens Gruschel schrieb:
(snip) [...]
How do you manage the creation an destruction of such objects?
There exists another design model, not based on abstract or immediately
virtual methods. The static method in the base class checks for
|
43 |
Hans-Peter Diettrich
replied
on 13-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
IMO it's the same matter - of *design rules* - that e.g. ban immediate
calls to Destroy, in favor of using Free instead.
IMO both Free and FreeAndNil have the same justification, and if you ban
one, you also have to ban the other one.
|
66 |
Hans-Peter Diettrich
replied
on 13-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
[no comment :-]
(snip)
This applies to the code you wrote yourself, and which you will have to
understand whenever you put your hands on it, at any later time. But as
soon as multiple coders are involved, an attempt to understand
|
42 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
The problem with it is that it is often used for the wrong reasons, and
this indicates that who uses it doesn't really know what he or she is
doing. If it is required to stop an error from happening, then there
must be something fundamentally wrong with the design. If it is not
|
36 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Hans-Peter Diettrich wrote:
(snip) In and of itself, nothing. But the use of FreeAndNil is often an
INDICATION that there is something wrong with it.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
14 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
There is no need to understand everything.
But there is a need to understand your OWN code. Now, if YOUR code is
thus that the code of OTHERS can access objects after YOU freed them in
your destructor, then there is a really big problem with your design,
|
50 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
WRONG. If access to the stream is still possible, then I wonder where
the extra references to it are. They should either not exist at that
moment, or the stream should not be freed yet.
--
|
20 |
Roy Lambert
replied
on 13-Feb-2010:
Wayne
(snip)
I hate to be a pedant but how does one call FreeAndNil on an integer, string or boolean? Or are you talking global objects?
Roy Lambert
|
22 |
Roy Lambert
replied
on 13-Feb-2010:
Hans-Peter
(snip)
As I tried to ask in another thread. Is design rule the right phrase. To me these are programming or implementation rules and nothing to do with design.
Roy Lambert
|
12 |
Roy Lambert
replied
on 13-Feb-2010:
Rudy
(snip)
I'd say there is little to argue in favour or against either approach.
(snip)
If it makes someone feel happy and has no nasty consequences does it really matter?
Roy Lambert
|
27 |
Roy Lambert
replied
on 13-Feb-2010:
Pieter
(snip)
Yeah. I found that out when running one bit of my app in the IDE and memory usage grew to the full extent of my 3GB or RAM
Roy Lambert
|
21 |
Roy Lambert
replied
on 13-Feb-2010:
Rudy
(snip)
Here I will probably agree with you, but offer in mitigation that there is so much in even my antiquated D2006 that I often have no idea what is there (until I have a need and ask for help here) or how it works.
Roy Lambert
|
17 |
Roy Lambert
replied
on 13-Feb-2010:
Jens
I've used something similar. A base form has a virtual procedure which may be overridden in all its descendents. I can then do a simple test in the main form for class and call it. If an override hasn't been set in a form down the inheritance trail nothing happens.
Roy Lambert
|
11 |
Roy Lambert
replied
on 13-Feb-2010:
Rudy
(snip)
Isn't part of the problem Windows events. Back in the good old days I knew exactly what was happening when in a program - after all I told it what it could do and when - but with Windows whilst I am sure its possible to figure out just what's going on if you have Marvin handy my brain often won't cope with it. Even trying to trace your way through events firing can be a nightmare.
Roy Lambert
|
24 |
Roy Lambert
replied
on 13-Feb-2010:
Rudy
(snip)
Please pass this request to Microsoft.
Roy Lambert
|
4 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Roy Lambert wrote:
(snip)
No. In a destructor, they should not matter.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"Life would be so much easier if we could just see the source
|
19 |
Dalija Prasnikar
replied
on 13-Feb-2010:
(snip)
Depends how you look at it. If FreeAndNil is needed in destructor that is
design flaw, on the other hand if it is not needed then it serves no purpose.
And code that has no purpose should be eliminated (at least I try to do so).
Dalija Prasnikar
|
24 |
Dalija Prasnikar
replied
on 13-Feb-2010:
(snip)
LOL
Dalija Prasnikar
|
7 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Roy Lambert wrote:
(snip)
Unnecessary code is not good design, IMO. Using FreeAndNil because you
don't know what other code might access the fields of a class is not
good design either. Once you reach the destructor of a class, no other
code should have access anymore to the fields you are freeing, even in
|
38 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Roy Lambert wrote:
(snip)
I am talking about the code you yourself wrote. You should know that.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"Subtlety is the art of saying what you think and getting out of
|
28 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Roy Lambert wrote:
(snip)
Object references are also variables, e.g. in
var
Form1: TForm1;
Form1 is a global variable.
|
33 |
Wayne Niddery
replied
on 13-Feb-2010:
"Tom Brunberg" <✉to.me> wrote in message
news:✉forums.codegear.com...
(snip)
In the case of forms, Screen.Forms contains any existing forms, so one can
scan that to see if a particular form type exists yet. I've used this many
times for exactly this purpose.
|
35 |
Bruce McGee
replied
on 13-Feb-2010:
(snip)
I know. I just haven't taken the time to explore them all, yet. It's on my perpetual todo list.
--
Regards
Bruce McGee
Glooscap Software
|
14 |
Roy Lambert
replied
on 13-Feb-2010:
Rudy
(snip) The way I read it you were referring to FreeAndNil. Sorry
Roy Lambert
|
6 |
Roy Lambert
replied
on 13-Feb-2010:
Rudy
(snip)
A Destructor is not stand alone. It exists in a wider app and it is the wider app I referred to.
Roy Lambert
|
8 |
Dalija Prasnikar
replied
on 13-Feb-2010:
(snip)
And what if you can have multiple forms of the same class in application?
Dalija Prasnikar
|
41 |
Rudy Velthuis (TeamB)
replied
on 13-Feb-2010:
Roy Lambert wrote:
(snip)
Using FreeAndNil in your own code, yes.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"I have made this letter longer than usual because I lack
|
15 |
Tom Brunberg
replied
on 13-Feb-2010:
"Wayne Niddery" wrote:
(snip)
Ahhh, thanks for the info. I wasn't aware of this.
I had a feeling that there could be other ways, specifically with
forms.
Cheers
|
14 |
Tom Brunberg
replied
on 13-Feb-2010:
wrote:
(snip)
Dalija,
I just played around with this and I guess you could check the name
instead of class.
You are giving meaningful names also to those components you create at
|
22 |
Pieter Zijlstra
replied
on 13-Feb-2010:
Roy Lambert wrote:
(snip)
Well, did the application die gracefully under these circumstances? :p
--
Pieter
"Never forget that everything Hitler did in Germany was legal."
|
18 |
Joanna Carter
replied
on 13-Feb-2010:
Roy Lambert a __crit :
(snip) If you are touching anything outside of the class in a destructor then
you need taking outside and having your brain removed cleaned and
replaced :-)
The only, I repeat, *the only* memory a destructor should ever touch is
|
19 |
Tom Brunberg
replied
on 13-Feb-2010:
"Joanna Carter" wrote:
(snip)
Joanna, you are getting softer. On Monday you wrote (in another
thread):
(snip)
Cheers
Tom
|
16 |
Dalija Prasnikar
replied
on 13-Feb-2010:
(snip)
LOL
Dalija Prasnikar
|
19 |
Dalija Prasnikar
replied
on 13-Feb-2010:
(snip)
Sorry for the confusion, I didn't ask this because I need the answer, I was just
wandering what would you do in such case.
All forms in my applications (sometimes even the main form) are encapsulated
in custom component class that I can drop on a form, or data module.
Form itself is not instantiated until is needed, and is automaticaly destroyed
|
55 |
Jens Gruschel
replied
on 13-Feb-2010:
(snip) If I understand it correctly your base class acts as interface and null object.
I think that's just a simplified null object approach.
--
Jens Gruschel
http://www.pegtop.net
|
10 |
Jens Gruschel
replied
on 13-Feb-2010:
(snip)
I've used that, too, but usually I try to avoid it, because it's a bit
dangerous. Someone might make a method checking for Assigned(Self) virtual by
accident. Or someone might introduce another method and forget checking for Self
= nil and access a field (or call a virtual method). On the other hand, the
called might forget that, too (probably even more likely), so I guess it's alright.
|
26 |
Tom Brunberg
replied
on 13-Feb-2010:
wrote:
(snip)
No, no Dalija, I think I should be sorry for the confusion. I
understood you were just speculating but the english way of speaking
in 2nd person when *one* actually means to speak in passive, is
sometimes confusing for the reader.
|
60 |
Loren Pechtel
replied
on 13-Feb-2010:
On Fri, 12 Feb 2010 14:48:59 -0800, Jens Gruschel
<✉pegtopwantsnospam.net> wrote:
(snip)
Yes. This is a valid case for free-and-nil. I think most all valid
cases for where it's needed (as opposed to simply defensive
programming) stem from this sort of situation.
|
69 |
Loren Pechtel
replied
on 13-Feb-2010:
On Fri, 12 Feb 2010 15:31:13 -0800, Rudy Velthuis (TeamB)
<✉rvelthuis.de> wrote:
(snip)
We recognize that we are human beings and thus fallible.
|
27 |
Wayne Niddery
replied
on 13-Feb-2010:
"Dalija Prasnikar" wrote in message news:✉forums.codegear.com...
(snip)
Then most likely you should not need to care about reusing variables - there
is nothing to call FreeAndNil on. You simply create and show an instance of
that form, and when the user closes it, it should be freed - which can be
don via the forms OnClose event.
|
26 |
Dalija Prasnikar
replied
on 13-Feb-2010:
(snip)
Wrappers usually exist throughout the lifetime of the application, but they
can also be instantiated and released dynamically.
(snip)
Basically, yes. OnClose event sends a message to the wrapper class,
and hides the form. After that wrapper class is responsible for cleanup
operation.
|
71 |
Hans-Peter Diettrich
replied
on 14-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
There are none. When the one and only reference is nilled, no accidental
access to the destroyed stream can occur any more.
(snip)
Right, that makes your "WRONG" WRONG ;-)
DoDi
|
21 |
Hans-Peter Diettrich
replied
on 14-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
How should your "fully understand" be interpreted, then?
(snip)
A derived class can be implemented by somebody else, in which case you
cannot know anything about that code.
DoDi
|
41 |
Hans-Peter Diettrich
replied
on 14-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
You're refraining old statements.
(snip)
What's an error? When the design relies on properly nilled references,
after an object is destroyed, it were an error if the reference were
*not* nilled.
|
42 |
Hans-Peter Diettrich
replied
on 14-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
Nothing new, so far, i.e. there remains no real problem to mention :-)
DoDi
|
12 |
Bruce McGee
replied
on 14-Feb-2010:
(snip)
Until someone writes a blog entry to make these poor misguided souls rethink their life choices.
--
Regards
Bruce McGee
Glooscap Software
|
15 |
Roy Lambert
replied
on 14-Feb-2010:
Pieter
(snip)
Nah. Just bombed with an out of memory error. Its real fun when I start that bit of the app (it imports the whole of the live database for testing purposes) in the IDE having forgotten "again" that I can't and a hour or so later come back to a crashed machine
Roy Lambert
|
25 |
Roy Lambert
replied
on 14-Feb-2010:
Joanna
(snip)
If you check what was written I made no mention of accessing anything in a Destructor that it didn't own.
Roy Lambert
|
20 |
Dalija Prasnikar
replied
on 14-Feb-2010:
(snip)
That is true for modal forms, and my base class wrapper started as modal
dialog wrapper and didn't have to use FreeAndNil. But then I used the same
principle for non-modal forms and the whole design has to be changed.
If you have forms that can be invoked while they are already showing you need
to test if they are created or not. Also if you have two independent forms
|
76 |
Hans-Peter Diettrich
replied
on 14-Feb-2010:
Jens Gruschel schrieb:
(snip)
AFAIK assigned() is a compiler magic. It can be replaced by Self<>Nil,
so that nothing can get into the way.
DoDi
|
22 |
Joanna Carter
replied
on 14-Feb-2010:
Dalija Prasnikar a __crit :
(snip) No, it isn't. The technique Wayne demonstrates is used for automatically
freeing non-modal forms.
(snip)
Only if you use global form variables. If you write the form class with
a static factory method, then you don't need to change your calling
|
87 |
Wayne Niddery
replied
on 14-Feb-2010:
"Dalija Prasnikar" wrote in message news:✉forums.codegear.com...
(snip)
I know nothing about your form wrapper class or its actual purpose, so it's
difficult for me to comment on it directly; but in the case you mention of
allowing multiple instances of a single form type, having wrapper instances
that may or may not currently have a reference to an actual form is the same
|
37 |
Mike Reublin
replied
on 14-Feb-2010:
If this can go on this long, it's obvious that the things that are obvious to the
proponents of every argument aren't particularly obvious, otherwise it obviously
wouldn't take this long to resolve.
Mike
|
8 |
Rudy Velthuis (TeamB)
replied
on 14-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
Then there is no need for FreeAndNil, in a destructor.
(snip)
No accidental access should occur anyway. That is what the design
should ensure. Using FreeAndNil is pure nonsense, in a destructor.
--
|
28 |
Rudy Velthuis (TeamB)
replied
on 14-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
Here is your answer:
(snip)
Although I am not responsible for the quality of derived classes
written by others, a derived class should not be able to access such
fields. That is why they should be private. That is also part of
|
60 |
Hans-Peter Diettrich
replied
on 14-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
It depends on the purpose a class serves.
DoDi
|
18 |
Rudy Velthuis (TeamB)
replied
on 14-Feb-2010:
Bruce McGee wrote:
(snip)
"Life choices" is a bit overdone, but even if someone like Allen Bauer
does that, people will still defend their own ways as better, probably
because of:
http://en.wikipedia.org/wiki/Illusory_superiority
|
29 |
Rudy Velthuis (TeamB)
replied
on 14-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
I'll refrain from answering that.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"I refuse to be labeled immoral merely because I am godless."
|
22 |
Rudy Velthuis (TeamB)
replied
on 14-Feb-2010:
Roy Lambert wrote:
(snip)
Doesn't matter either. A destructor is called at the end of life of an
object. That has nothing to do with the aserial way we program in
Windows.
--
|
24 |
Rudy Velthuis (TeamB)
replied
on 14-Feb-2010:
Joanna Carter wrote:
(snip)
Exactly.
--
Rudy Velthuis (TeamB) http://www.teamb.com
AMAZING BUT TRUE ...
|
26 |
Rudy Velthuis (TeamB)
replied
on 14-Feb-2010:
Roy Lambert wrote:
(snip)
Well, then the aserial nature of Windows programming doesn't play a
role.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
35 |
Rudy Velthuis (TeamB)
replied
on 14-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
No, it doesn't.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"Most people would sooner die than think; in fact, they do so."
|
27 |
Dalija Prasnikar
replied
on 14-Feb-2010:
(snip)
I was reffering to modal forms created with my wrapper.
(snip)
I have used the Observer pattern but I used wrapper classes to listen to
the data, not the forms directly.
(snip)
I don't use "out of the box" solutions, and I seldom use global form variables.
I'm not expert in design patterns so there is a chance that my design has flaws.
|
234 |
Dalija Prasnikar
replied
on 14-Feb-2010:
(snip)
One wrapper instance is responsible for one form instance, however form instance
is not created until it needs to be shown, and wrapper class contains data form
has to show or change. That way I can access the data at any time without the
need to create the form.
Dalija Prasnikar
|
50 |
Pieter Zijlstra
replied
on 14-Feb-2010:
Roy Lambert wrote:
(snip)
See, all you need is a 64 bit compiler and more RAM ;-)
--
Pieter
"The Bible was a consolation to a fellow alone in the old cell.
|
39 |
Bruce McGee
replied
on 15-Feb-2010:
(snip)
Self deprecating choice of words. :)
(snip)
Egos can get in the way of good collaboration. This Allan Bauer fellow might just know a thing or two about how to use Delphi.
--
Regards
Bruce McGee
|
20 |
Hans-Peter Diettrich
replied
on 15-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
Bet you can't
DoDi
|
6 |
Joanna Carter
replied
on 15-Feb-2010:
Hans-Peter Diettrich a __crit :
(snip)
As Rudy says, if you are expecting someone else to extend your class,
then you must program defensively, so that they can't abuse it in any way.
To do otherwise is poor design.
Joanna
|
31 |
Paul Scott
replied
on 15-Feb-2010:
On Sun, 14 Feb 2010 18:57:03 -0000, Rudy Velthuis
<✉rvelthuis.de> wrote:
(snip)
Sheesh! I can't believe that so many people have so little to do that
each and every time they come to free an object they can afford to spend
their time - and their employer's time - asking themselves:
|
135 |
Rudy Velthuis (TeamB)
replied
on 15-Feb-2010:
Paul Scott wrote:
(snip)
Yes, that can be expected of a programmer. The design should make such
considerations pretty easy. It should actually be so normal that you
hardly have to think about it anymore.
And knowing what he or she is actually doing and when an object can be
|
111 |
Rudy Velthuis (TeamB)
replied
on 15-Feb-2010:
Joanna Carter wrote:
(snip)
I'll go a step further. IMO, deriving from a class is just one way to
use it.
The internal state of a class should be protected against people
unknowingly or inadvertently bringing it into an invalid state (e.g.
|
57 |
An Pham
replied
on 15-Feb-2010:
(snip)
1. Something wrong is not an answer
2. Wrong design is a relative point in time (now but not tomorrow) and not an answer
3. There is no tool to validate the design, that's why software is always deliver AS-IS and
will crash
To my shop, software that is Work and work reliable is Most priority. If it fails, it must fail
|
41 |
Wayne Niddery
replied
on 15-Feb-2010:
"Paul Scott" <✉inf-rem-ove-these-bits-mansys.com> wrote in message
news:✉forums.codegear.com...
(snip)
Umm, if you are writing a line of code and don't even know whether you are
writing it in a destructor or not, you have far more serious problems as a
programmer.
|
147 |
Tom Brunberg
replied
on 15-Feb-2010:
"Wayne Niddery" wrote:
(snip)
Wayne,
I found in my code something like this (simplified):
{code:delphi}
type
|
41 |
Quentin Correll
replied
on 15-Feb-2010:
Wayne,
| Umm, if you are writing a line of code and don't even know whether
| you are writing it in a destructor or not, you have far more serious
| problems as a programmer.
LOL!
|
11 |
Joanna Carter
replied
on 15-Feb-2010:
Tom Brunberg a __crit :
(snip)
Providing you realise that by freeing the object in the arry, you may
invalidate any external reference to it, then there is no problem with
setting the item to nil after freeing it.
However, if you are likely to have any external references to the item
|
57 |
Wayne Niddery
replied
on 16-Feb-2010:
"Tom Brunberg" <✉to.me> wrote in message
news:✉forums.codegear.com...
(snip)
Because the class is actually managing that array and controlling access to
it, it is perfectly reasonable to me. The key is that access is isolated to
this class and other code uses the class rather than directly having to
|
46 |
Rudy Velthuis (TeamB)
replied
on 16-Feb-2010:
An Pham wrote:
(snip)
Not an answer to what?
(snip)
Again: not an answer to what?
3. There is no tool to validate the design, that's
(snip) How on earth is that relevant for the fact that using FreeAndNil in a
|
35 |
Rudy Velthuis (TeamB)
replied
on 16-Feb-2010:
An Pham wrote:
(snip)
If FreeAndNil helps you in finding errors, you didn't understand what
has been said, IMO.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
19 |
Rudy Velthuis (TeamB)
replied
on 16-Feb-2010:
Joanna Carter wrote:
(snip)
IMO, there should not be any external references to it.
--
Rudy Velthuis (TeamB) http://www.teamb.com
AMAZING BUT TRUE ...
|
23 |
Rudy Velthuis (TeamB)
replied
on 16-Feb-2010:
Wayne Niddery wrote:
(snip)
Since he uses the ID as index, that might not work as expected.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"Your Highness, I have no need of this hypothesis."
|
16 |
Tom Brunberg
replied
on 16-Feb-2010:
Joanna,
You are a master in pointing out paths of thinking that one has never
seen. Maybe that's why you are a consultant ;-)
"Joanna Carter" wrote:
(snip)
No, there are no external references, but if there were, wouldn't that
|
61 |
Tom Brunberg
replied
on 16-Feb-2010:
"Wayne Niddery" wrote:
(snip)
Thanks Wayne for your thoughts,
I recall that I considered TObjectList at the time, but discovered it
to become more complicated, without any benefits, compared with the
current solution.
|
32 |
Paul Scott
replied
on 16-Feb-2010:
Wayne, Rudy,
On Mon, 15 Feb 2010 17:30:19 -0000, Wayne Niddery
<✉chaffrogers.com> wrote:
(snip)
Fair enough - if you can +guarantee+ that line of code won't ever need to
be refactored out of the destructor to somewhere where the pointer /will/
|
168 |
andrew galatyn
replied
on 16-Feb-2010:
Absolutely agree with you, Paul.
There is no perfect things in the real world.
I am working on project started ~7-10 yers ago. It is long enough to change
term "design" itself. And this huge collection of code written by different
people. It would be stupid to wait that all of them designed every piece of
|
201 |
Wayne Niddery
replied
on 16-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
Right, hence my comment that it would change the semantics of how the class
is used.
--
|
17 |
Wayne Niddery
replied
on 16-Feb-2010:
"Paul Scott" <✉inf-rem-ove-these-bits-mansys.com> wrote in message
news:✉forums.codegear.com...
(snip)
If something needs to be refactored, FreeAndNil makes no difference, it
might be just as wrong in its new place.
(snip) I've been speaking from a POV of what I consider "best practices", not an
|
131 |
Hans-Peter Diettrich
replied
on 16-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
What's relevant at all?
"is often sign of wrong design" is not an absolute statement, so why
discuss it at all? Do you want an exact percentage of the cases, where
the sign is wrong, or the design is wrong? Or the number of people that
|
41 |
Hans-Peter Diettrich
replied
on 16-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
You even didn't *try* to understand, IMO :-(
An abstract design and its concrete implementation are different things.
FreeAndNil can help to find errors in the implementation, that may or
may not be related to the design.
|
22 |
Joanna Carter
replied
on 16-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip) And I would agree, whch is why I mentioned the possibility :-)
Joanna
--
Joanna Carter [TeamB|http://www.teamb.com]
|
10 |
Joanna Carter
replied
on 16-Feb-2010:
Tom Brunberg a __crit :
(snip)
:-)
(snip)
Indeed, that is my point. Your code shows a method that accepts an
externally created TDevice for addition to the internal array. It gives
no indication whether you hold on the the externally created TDevice or
|
90 |
Tom Brunberg
replied
on 16-Feb-2010:
"Joanna Carter" wrote:
(snip)
Joanna,
I still don't get your point. Are you assuming something that you did
not reveal yet?
You wrote:
|
80 |
Rudy Velthuis (TeamB)
replied
on 16-Feb-2010:
Paul Scott wrote:
(snip)
A destructor DESTROYS. That kind of code should ONLY be in the
destructor, and only there.
(snip)
Not how destructors work. And fields that are freed in a destructor
should be the private proeprty of the class, so NOTHING should be able
|
125 |
Rudy Velthuis (TeamB)
replied
on 16-Feb-2010:
Wayne Niddery wrote:
(snip)
I disagree. It is not unnecessary, in a destructor.
An example. Say we have this:
type
TOwner = class
|
53 |
Rudy Velthuis (TeamB)
replied
on 16-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
Apparently your reply isn't.
(snip) So "relative" statements are not relevant to you? What about "smoking
is often the cause of cardiopulmonary diseases", or "speeding is often
the cause of serious accidents"? Those are not absolute statements
|
37 |
Rudy Velthuis (TeamB)
replied
on 16-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
Someone who uses FreeAndNil in a destructor does it to avoid possible
(human) errors in the rest of the code. But in a destructor, ONLY the
code of the destructor can access the fields that are being freed (and
when the destructor ends, nothing can access them anymore).
|
42 |
Wayne Niddery
replied
on 17-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
My arguments have been including other uses of FreeAndNil besides just
within destructors. Within the context of destructors I am in complete
agreement with you.
|
36 |
Loren Pechtel
replied
on 17-Feb-2010:
On Tue, 16 Feb 2010 03:17:20 -0800, Paul Scott
<✉inf-rem-ove-these-bits-mansys.com> wrote:
(snip)
Exactly. It's simply being defensive.
|
36 |
Wayne Niddery
replied
on 17-Feb-2010:
"Loren Pechtel" <✉hotmail.invalid.com> wrote in message
news:✉forums.codegear.com...
(snip)
The reason why I argue this is because I have *predominantly* seen uses of
FreeAndNil, and people defending it as "defensive programming", where the
call is as "defensive" as writing the following:
|
49 |
Roy Lambert
replied
on 17-Feb-2010:
Rudy
But you shouldn't get ____ B := TB.Create;__ // exception in well designed code
Roy Lambert
|
4 |
Marjan Venema
replied
on 17-Feb-2010:
"Wayne Niddery" <✉chaffrogers.com> wrote in message
news:✉forums.codegear.com...
(snip)
Do you ever expose inner instances through a (readonly) property or
function?
Unless you adhere stricly to the Law of Demeter, and code wrappers for all
|
115 |
Hans-Peter Diettrich
replied
on 17-Feb-2010:
Wayne Niddery schrieb:
(snip)
What will happen when code later is inserted here?
This is my first question when I see or write such code. Consequently
it's good practice to use FreeAndNil here.
(snip)
It is.
|
47 |
Hans-Peter Diettrich
replied
on 17-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
They seem not to be relevant to *you*, since you demonstrate your
ignorance of the other side.
(snip)
They are as relevant and true as their opposite is. In this context:
"FreeAndNil is often sign of good design"
|
29 |
Hans-Peter Diettrich
replied
on 17-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
WRONG!
inherited Destroy;
//do something more
(snip)
No rule without exception.
|
26 |
Joanna Carter
replied
on 17-Feb-2010:
Hans-Peter Diettrich a __crit :
(snip)
If you were to insert any code in Wayne's example, where would it go?
Unless you are the kind of programmer that doesn't understand the
try..finally construct, the only placesuch code would be valid, would be
between the try and the finally lines - placing code outside of that
|
56 |
Joanna Carter
replied
on 17-Feb-2010:
Hans-Peter Diettrich a __crit :
(snip)
Rubbish!!! Any programmer, who truly understands what inherited Destroy
does, would never do this.
(snip) As has been said by others, FreeAndNil does have a valid place, just not
where you think.
|
32 |
Paul Scott
replied
on 17-Feb-2010:
On Wed, 17 Feb 2010 08:59:30 -0000, Joanna Carter <✉no.spam.for.me>
wrote:
(snip)
Sorry, Joanna, but I disagree with your (and Wayne's) interpretation of
"scope".
And, as defender of my sanity, I call the Delphi compiler...
|
50 |
Wayne Niddery
replied
on 17-Feb-2010:
"Roy Lambert" <✉skynet.co.uk> wrote in message
news:✉forums.codegear.com...
(snip)
If that constructor must do other things that are not under your control
(e.g. allocating resources or expecting a DLL or file to exist, or connect
to a database, etc) then that can cause an exception - and it's also
|
28 |
Wayne Niddery
replied
on 17-Feb-2010:
"Marjan Venema" <✉everyangle.com> wrote in message
news:✉forums.codegear.com...
(snip)
Of course. If I tried to claim immunity from such mistakes I'd be a liar.
However, in general, when it does happen, I typically find it is because I
have allowed myself to take a shortcut in some way, for example, keeping a
|
59 |
Wayne Niddery
replied
on 17-Feb-2010:
"Hans-Peter Diettrich" <✉aol.com> wrote in message
news:✉forums.codegear.com...
(snip)
Only if you consider it proper to defend against incompetence or ignorance
from some future developer. That is not the goal of defensive programming,
*nor will it succeed*.
|
44 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Wayne Niddery wrote:
(snip)
OK.
(snip)
Yes, probably.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
21 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Roy Lambert wrote:
(snip)
That is nonsense. I never said you can't get exceptions or that you
can't make mistakes. Of course exceptions can occur, even in well
designed code.
|
24 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Marjan Venema wrote:
(snip)
Yes, and there is no way you can protect the Font or Canavs against
someone calling Free on them. Trying to protect against that is futile,
and FreeAndNil would not solve this either.
(snip)
No, unless that is part of a given protocol. But then it must be
|
58 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Loren Pechtel wrote:
(snip) It is like turning the car radio louder because your engine is making
funny noises.
Most of the time it is not "defensive", it is simply "defective", and
frequent uses of FreeAndNil and Assigned are required to cover up the
|
25 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Wayne Niddery wrote:
(snip)
Fully agreed.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"In law a man is guilty when he violates the rights of another.
|
20 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
Code accessing frm should not be inserted after the try-finally. I
expect a competent programmer to know this.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
26 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Paul Scott wrote:
(snip)
Depends on how you define scope. I guess that Joanna knows that the
syntactical scope is indeed the function, but I guess she meant the
extent of application (for which "scope" is another term too).
--
|
35 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Wayne Niddery wrote:
(snip)
Indeed. Otherwise we must reset integers to 0 (or some other default
value) too, since there is always a chance someone uses the previous
value of an integer, even if it is not appropriate.
As you said, there is no way you can protect agains the incompetence of
|
33 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
I actually have no idea what you are talking about, or what you are
trying to tell me. I guess you call that "ignorance".
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
24 |
Paul Scott
replied
on 17-Feb-2010:
On Wed, 17 Feb 2010 17:33:02 -0000, Rudy Velthuis
<✉rvelthuis.de> wrote:
(snip)
No, it is completely the opposite!
It is like turning your car radio OFF so that if your engine ever makes
any funny noises you will *definitely* hear them.
|
43 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
I expect a competent programmer to be able to overview the code of a
destructor, and not to access items that were freed a few lines before.
It is futile (and not the purpose of defensive programming) to try to
prevent against any stupid error that may be made. People who think
|
28 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
IOW, you are objecting to what I said because it was me who said it?
OK.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
23 |
Rudy Velthuis (TeamB)
replied
on 17-Feb-2010:
Paul Scott wrote:
(snip)
Yes, OK. From what you describe, that is probably one of the valid
applications, although I would most likely not free the objects, just
mark them as invalid, and set their new values when a new item is
reloaded. But your approach is probably OK.
|
41 |
Loren Pechtel
replied
on 17-Feb-2010:
On Wed, 17 Feb 2010 00:34:12 -0800, Hans-Peter Diettrich
<✉aol.com> wrote:
(snip)
Right. It's not about hiding bugs, it's about exposing them.
Think of FreeAndNil as a relative of Assert.
|
11 |
Loren Pechtel
replied
on 17-Feb-2010:
On Wed, 17 Feb 2010 09:03:46 -0800, Wayne Niddery
<✉chaffrogers.com> wrote:
(snip)
Of course it needs fixing. The point is that if the variable is
nilled then it blows up immediately and makes the problem more
obvious.
|
25 |
Marjan Venema
replied
on 18-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
But in a destructor, which is the end of life of an instance, nothing
_SHOULD_ access the private fields of the class anymore except the code in
the destructor. So FreeAndNil has no place there, _BUT_ is a good means to
|
37 |
Marjan Venema
replied
on 18-Feb-2010:
"Wayne Niddery" <✉chaffrogers.com> wrote in message
news:✉forums.codegear.com...
(snip)
Granted, which is where Alan's suggestion of using FreeAndInvalidate is
valuable.
--
|
27 |
Marjan Venema
replied
on 18-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
Exactly and part of controlling my code is not just freeing the memory I
used, but also invalidating any pointers to that memory. As Wayne said
nilling them can leave you wondering whether an instance was freed or never
|
77 |
Rudy Velthuis (TeamB)
replied
on 18-Feb-2010:
Marjan Venema wrote:
(snip)
Nothing CAN. The code of the destructor is already running, and after
that, the object is gone.
Even Allen Bauer's rather construed example in his latest blog about
FreeAndNil doesn't make any sense to me. If the outer class is already
|
57 |
Rudy Velthuis (TeamB)
replied
on 18-Feb-2010:
Marjan Venema wrote:
(snip)
There is no need for that, in a destructor or anywhere else. If you can
still access the item that was free-and-nilled, then it should not have
been freed yet. IOW, you should never be able to access the freed
reference, and then it doesn't matter if it is just an invalid
|
45 |
Hans-Peter Diettrich
replied
on 18-Feb-2010:
Joanna Carter schrieb:
(snip)
I trust nobody but me, from experience ;-)
(snip)
No need to elaborate the sample code for me, I already gave the same
solution in abbreviated form.
(snip)
Exactly this was my conclusion as well. Glad to see that we agree :-)
|
33 |
Hans-Peter Diettrich
replied
on 18-Feb-2010:
Wayne Niddery schrieb:
(snip)
FreeAndNil does not cover the error. In contrast it foreces an AV on the
*first* use of the nilled reference - what's not guaranteed when the
destroyed object still sits in memory, at the now invalid former address.
DoDi
|
24 |
Rudy Velthuis (TeamB)
replied
on 18-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
It forces an AV only when your design is wrong. In proper design,
access to the freed value is impossible.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
40 |
Marjan Venema
replied
on 19-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
Actually, Rudy ANYTHING that has a pointer to an instance CAN access that
instance regardless of whether the destructor is running or even has
finished.
|
90 |
Marjan Venema
replied
on 19-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
Granted.
(snip)
Again, should, seems to be the crucial word here. That something shouldn't
happen doesn't make it so.
|
55 |
Andreas Dorn
replied
on 19-Feb-2010:
Marjan Venema wrote:
(snip)
One danger here is that FreeAndNil allows you to add
"if (obj = nil) then ..." hacks just to hide the Access Violations.
Your "I can decide whether..." thing is the real evil. Anything that
doesn't immediately raise an exception here has to be considered an evil
|
83 |
Joanna Carter
replied
on 19-Feb-2010:
Andreas Dorn a __crit :
(snip)
Precisely the point that some of us are trying to make.
Yes, there are all sorts of uses that one can make of FreeAndNil but...
In the long run, most uses are a cover up for shoddy design and, as as
has been rightly pointed out by several sages, can still come back to
|
32 |
Rudy Velthuis (TeamB)
replied
on 19-Feb-2010:
Marjan Venema wrote:
(snip)
I am saying that, assuming a somewhat proper design, it CAN'T happen,
not that it SHOULD not happen. If it happens, we can be sure the design
sucks.
--
|
30 |
Rudy Velthuis (TeamB)
replied
on 19-Feb-2010:
Marjan Venema wrote:
(snip)
As I said: AS LONG AS ANYTHING (beside the owner, of course) HAS A
REFERENCE to an instance, it should not be freed.
But that is not what is going on here anyway. The destructor is freeing
INTERNAL private fields, to which only the code of the instance has
|
48 |
Loren Pechtel
replied
on 20-Feb-2010:
On Fri, 19 Feb 2010 08:57:21 -0800, Rudy Velthuis (TeamB)
<✉rvelthuis.de> wrote:
(snip)
Nope. They're still accessible.
Remember that objects themselves are really just pointers and remain
accessible even though they have been freed. Just because it requires
|
59 |
Wayne Niddery
replied
on 20-Feb-2010:
"Loren Pechtel" <✉hotmail.invalid.com> wrote in message
news:✉forums.codegear.com...
(snip)
TFoo = class
private
bar: TBar;
|
41 |
Joanna Carter
replied
on 20-Feb-2010:
Wayne Niddery a __crit :
(snip)
Methinks our gainsayers may either be used to declaring public fields
or, at least, they are talking about the published fields necessary for
form designers to work.
I still am amazed that, after all this time, the Delphi form designer
|
25 |
Paul Scott
replied
on 20-Feb-2010:
Joanna,
On Fri, 19 Feb 2010 10:24:02 -0000, Joanna Carter <✉no.spam.for.me>
wrote:
(snip)
I could use your own phrase (the one with all the exclamation marks) but
I'm much too polite to do that.
|
77 |
Rudy Velthuis (TeamB)
replied
on 20-Feb-2010:
Loren Pechtel wrote:
(snip)
Well, your design will, of course, have to prevent that too. That means
that there is only one reference (except for local copies of the
reference, which disappear when the routine ends), and that is not
freed before it can be freed, i.e. not as long as it is accessible.
|
44 |
Rudy Velthuis (TeamB)
replied
on 20-Feb-2010:
Joanna Carter wrote:
(snip)
There is no way around it. You can't protect such items (nor exposed
properties like Font) from being freed. Fortunately, most people will
not even think of doing that. They rely on the ownership mechanism.
--
|
38 |
Rudy Velthuis (TeamB)
replied
on 20-Feb-2010:
Paul Scott wrote:
(snip)
I wonder how that works. If there are unknown, extra references to an
object, how do you nil them? You can't, so they will still (try to)
access your freed object. No nil access there.
Or are you saying there are unknown extra references to private objects
|
48 |
Joanna Carter
replied
on 20-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
Interestingly, .NET designer files have all their components declared as
private, therefore, inadvertently accessing them directly is much less
likely.
Joanna
|
16 |
Rudy Velthuis (TeamB)
replied
on 20-Feb-2010:
Joanna Carter wrote:
(snip)
Well yes, but in Delphi, they have to be published, otherwise they
don't contain any RTTI. OK, these days, with the new RTTI, I guess they
could be private.
--
|
28 |
Joanna Carter
replied
on 20-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
One can but hope. It's obvious that, if the IDE appears to encourage bad
practice, folks think that is the correct way to write apps.
I have to admit to not regarding the visibility of ivars (fields) in
Objective-C, mainly because most of the example code I find doesn't seem
|
28 |
Rudy Velthuis (TeamB)
replied
on 20-Feb-2010:
Joanna Carter wrote:
(snip)
I doubt it. People are used to being able to access the components on a
form, so they will very likely remain published.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
24 |
Joanna Carter
replied
on 20-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
Hmmm, of course, it would be too much like real programming to force
people to add public properties to access private fields.
Sheesh! And folks wonder why their code develops bugs?
Joanna
|
17 |
Rudy Velthuis (TeamB)
replied
on 20-Feb-2010:
Joanna Carter wrote:
(snip)
IMO, RAD can also be real programming, but I assume you mean "manual
coding".
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
20 |
Andreas Dorn
replied
on 20-Feb-2010:
(snip)
Let me try to be more clear:
With FastMM in debug-mode it practically doesn't matter if you nilled the pointer or not - the bug won't go unnoticed. Theoretically nilling it is a little bit more safe (~0,01%). So nilling surely has at least a theoretical advantage here.
But:
Nilling the object allows programmers to add ill-designed workarounds "if (obj <> nil)" instead of fixing the design-problem. And those don't get caught by anything.
I don't use FreeAndNil because:
|
65 |
Joanna Carter
replied
on 20-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
Heheh, now to find out what that odd looking slab with the alphabet all
jumbled up is meant to do :-)
Joanna
--
|
12 |
Loren Pechtel
replied
on 20-Feb-2010:
On Fri, 19 Feb 2010 20:59:25 -0800, Wayne Niddery
<✉chaffrogers.com> wrote:
(snip)
tFoo still can. The dead instance of tFoo can still be referenced.
|
48 |
Joanna Carter
replied
on 20-Feb-2010:
Loren Pechtel a __crit :
(snip) TFoo is a classnot an instance. Unless you still have a reference to an
instance of TFoo, then you can't access the dead instance.
And, if your code calls the destructor on anything other than the last
reference left alive, then you have a logic error.
|
30 |
Roy Lambert
replied
on 21-Feb-2010:
Joanna
(snip)
I'm not sure just what you're proposing or suggesting here. Properties with getters and setters are no more intrinsically secure than a public variable.
Roy Lambert
|
12 |
Rudy Velthuis (TeamB)
replied
on 21-Feb-2010:
Roy Lambert wrote:
(snip)
Of course they are. They can protect the internal state of an instance
against (inadvertent) changes from outside.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
24 |
Roy Lambert
replied
on 21-Feb-2010:
Rudy
(snip)
I said intrinsically. Its always possible to write code to protect against unwanted changes. A bit more difficult with public variables I agree.
Roy Lambert
|
18 |
Rudy Velthuis (TeamB)
replied
on 21-Feb-2010:
Roy Lambert wrote:
(snip)
Not against unwanted changes of global variables or public/published
objects. That is why properties are more secure.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
33 |
Paul Scott
replied
on 21-Feb-2010:
On Sat, 20 Feb 2010 10:17:52 -0000, Rudy Velthuis
<✉rvelthuis.de> wrote:
(snip)
Strawman alert! Who ever said anything about +extra+ references?
Ok, to expand my comment...
Nilling the pointer means that any further (incorrect) usage of +that+
|
40 |
Joanna Carter
replied
on 21-Feb-2010:
Paul Scott a __crit :
(snip)
If there are no extra references to a private field in a class, after
the destructor is called and Free is called on the private variable,
nothing, I repeat nothing, can access that variable.
Joanna
|
31 |
Rudy Velthuis (TeamB)
replied
on 21-Feb-2010:
Paul Scott wrote:
(snip)
Well, code that can't manage its own pointers is badly designed, don't
you think? Shows again that FreeAndNil only covers up bad design, it
doesn't expose it.
(snip)
Yes. But code that uses such a pointer is badly designed: as long as
|
54 |
Rudy Velthuis (TeamB)
replied
on 21-Feb-2010:
Joanna Carter wrote:
(snip)
Exactly. Well, unless something is still accessing the freed owning
instance.
TOwner = class
private
|
67 |
Joanna Carter
replied
on 21-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
Precisely. If you always guarantee to balance the create/destroy
lifetime, then it is impossible to access the freed instance.
(snip)
I can absolutely guarantee that anyone who has a problem with invalid
references has not followed the *really simple* rules of allocation and
|
53 |
Hans-Peter Diettrich
replied
on 21-Feb-2010:
Joanna Carter schrieb:
(snip)
When an object exposes a reference to a local object, like
"Items:TStrings" in many VCL controls, the object has no control over
the external storage and use of such references.
Of course it's not good practice to store such references for later use,
|
50 |
Rudy Velthuis (TeamB)
replied
on 21-Feb-2010:
Joanna Carter wrote:
(snip)
Yes, that is what I have been saying all the time. Either balance it in
one single routine (using try-finally) or make sure something is freed
in the destructor only. Lazy initialization is fine, but one must know
how to do it. OTOH, if an object does not require many resources before
|
53 |
Rudy Velthuis (TeamB)
replied
on 22-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
Correct. And if some idiotic programmers free the TStrings, (or
otherwise abuse it) that is their problem (and their responsibility),
not the problem of the author of the class, IMO.
If I cut the brake hoses of my car, I can't blame the manufacturer if I
|
40 |
Joanna Carter
replied
on 22-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
FreeAndNil can prevent brake failure? Wow! Embarcadero could make a
fortune if this ever gets known
Joanna
--
|
16 |
Rudy Velthuis (TeamB)
replied
on 22-Feb-2010:
Joanna Carter wrote:
(snip)
They should talk to Toyota.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"A computer makes it possible to do, in half an hour, tasks which
|
23 |
Marjan Venema
replied
on 22-Feb-2010:
"Joanna Carter" <✉no.spam.for.me> wrote in message
news:✉forums.codegear.com...
(snip)
Nope.
Wayne does not expose his internal instance in anyway, so his statement is
correct.
|
68 |
Marjan Venema
replied
on 22-Feb-2010:
"Joanna Carter" <✉no.spam.for.me> wrote in message
news:✉forums.codegear.com...
(snip)
Exactly. And anybody having a reference can call methods on that reference
that access the inner object.
(snip)
Finally...
|
52 |
Marjan Venema
replied
on 22-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
And since when is everybody following the rules a given?
I prefer not to rely just on the rules, but to enforce them by any
strategies at my disposal. Compile time, or runtime. Even automated test
|
51 |
Paul Scott
replied
on 22-Feb-2010:
On Sun, 21 Feb 2010 23:17:07 -0000, Rudy Velthuis
<✉rvelthuis.de> wrote:
(snip)
Rudy, while I hesitate to quibble over a word you have quickly typed in a
message in your third (fourth?) language, the fact that both you and
Joanna frequently use the same term leads me to think that we are talking
|
135 |
Rudy Velthuis (TeamB)
replied
on 22-Feb-2010:
Paul Scott wrote:
(snip)
I don't think so. Language is not the issue here. I mean design. It is
not really hard to write code thus that such situations as you describe
CAN'T happen. Actually, if they CAN happen, there is something wrong
with your *design*, i.e. such situations are impossible if you follow
|
58 |
Rudy Velthuis (TeamB)
replied
on 22-Feb-2010:
Paul Scott wrote:
(snip)
There you are wrong. If your design is done well, it is pretty easy for
a human to understand when and where an item can be freed and when not.
If that is not possible, that is a design error.
IOW, a complex design IS a bad design.
|
88 |
Paul Scott
replied
on 22-Feb-2010:
Rudy,
On Mon, 22 Feb 2010 12:43:42 -0000, Rudy Velthuis
<✉rvelthuis.de> wrote:
(snip)
Did you actually read my message?
The whole point is that mistakes CAN and DO happen - irrespective of the
|
43 |
Rudy Velthuis (TeamB)
replied
on 22-Feb-2010:
Paul Scott wrote:
(snip)
Of course.
(snip) No. If you follow a few simple design rules, you fully rule them out.
They CAN'T happen. If they CAN happen, the design is lacking, pure and
simple.
|
45 |
Roy Lambert
replied
on 22-Feb-2010:
Paul
(snip)
I'm on your side here, in fact I asked about this earlier. Nice to see it answered here.
Personally I find it fascinating that neither Rudy nor Joanna can separate design from implementation.
Roy Lambert
|
28 |
Joanna Carter
replied
on 22-Feb-2010:
Roy Lambert a __crit :
(snip) That's because we usually implement our designs.
Joanna
--
Joanna Carter [TeamB|http://www.teamb.com]
|
11 |
Roy Lambert
replied
on 22-Feb-2010:
Joanna
(snip) Ah. So your comments are based on the designer being the implementer. Makes sense now .
As an aside I thought I'd look you up on the web. Your website needs a bit of updating. Some of the links have been freed but you're still pointing to them
Roy Lambert
|
13 |
Joanna Carter
replied
on 22-Feb-2010:
Roy Lambert a __crit :
(snip)
Ah yes, that's due, not to lazy instantiation but lazy garbage
collection ;-)
Joanna
--
|
14 |
Paul Scott
replied
on 22-Feb-2010:
Rudy,
On Mon, 22 Feb 2010 12:54:02 -0000, Rudy Velthuis
<✉rvelthuis.de> wrote:
(snip)
"pretty easy"? Really? Wow!! Then I definitely want to see all the
evidence you must have which allows you to dismiss one of the most highly
|
166 |
Rudy Velthuis (TeamB)
replied
on 22-Feb-2010:
Paul Scott wrote:
(snip)
I don't quite care about it. Knowing when objects are created and when
they can or must be freed is part of proper design. A programmer should
master such things.
Oh, but design can be too complex. That is bad design. Just modularize
|
50 |
Rudy Velthuis (TeamB)
replied
on 22-Feb-2010:
Paul Scott wrote:
(snip)
To avoid such situations in programming, one should follow the simple
design rules. Then these situations can't happen. As Joanna said, it is
not so hard to balance creation and destruction of objects. If they are
fields, they are freed in the destructor (and created in the
|
41 |
Rudy Velthuis (TeamB)
replied
on 22-Feb-2010:
Roy Lambert wrote:
(snip)
You don't seem to see that proper design (and following a few simple
rules) can avoid errors in the implementation. It makes the errors
brought up here by you impossible. I find it fascinating that
progfessional programmers don't know this.
|
34 |
Marjan Venema
replied
on 23-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
There is a big hidden IF in that statement, one that can easily not be met
by making a mistake: IF you follow the design rules, such mistakes are
impossible. You seem to ignore the fact that someone's mistake may be
|
41 |
Marjan Venema
replied
on 23-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip) Wow, so everything complex is bad?
Some things simply (pun intended) are complex. Any design dealing with those
things, can't help but be complex as wel.
|
13 |
Marjan Venema
replied
on 23-Feb-2010:
"Joanna Carter" <✉no.spam.for.me> wrote in message
news:✉forums.codegear.com...
(snip)
Aren't you lucky.
Most of us get to deal with designs and implementations of others.
--
|
15 |
Marjan Venema
replied
on 23-Feb-2010:
"Marjan Venema" <✉everyangle.com> wrote in message
news:✉forums.codegear.com...
(snip)
Complex is not the same as Complicated
http://codebetter.com/blogs/dru.sellers/archive/2009/09/25/complex-vs-complicated.aspx
--
|
23 |
Rudy Velthuis (TeamB)
replied
on 23-Feb-2010:
Marjan Venema wrote:
(snip)
Yes. And every more or less capable programmer should be able to follow
these design rules without an exception. I don't know if I am more or
less capable, but I am sure that errors as described here can't happen
in my code(*), because I follow these rules. Not following them would
|
109 |
Rudy Velthuis (TeamB)
replied
on 23-Feb-2010:
Marjan Venema wrote:
(snip)
A design that is so complex that the author can't oversee it anymore
is. Especially if you look at the maintainability of such code. Even
someone who can oversee it now may not be able to oversee it anymore
after 6 months.
|
49 |
Rudy Velthuis (TeamB)
replied
on 23-Feb-2010:
Marjan Venema wrote:
(snip)
You don't design and implement your own code?
--
Rudy Velthuis (TeamB) http://www.teamb.com
"Opportunities multiply as they are seized."
|
18 |
Joanna Carter
replied
on 23-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
As most folks will know, I designed an OPF layer for .NET. Although it
would take me a couple of days to get back into knowing exactly what
lives where, I know the essential design inside out and could more than
likely answer most people's questions about the design without even
|
79 |
Joanna Carter
replied
on 23-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
Heheh :-)
(snip)
We all make errors. The trick is to learn from those errors and avoid them.
"Doctor, doctor, it hurts when I hit myself on the back of the head"
"Well, stop hitting yourself on the head"
|
42 |
Hans-Peter Diettrich
replied
on 23-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
The presentation of arguments often is more important than the arguments
themselves.
I'm one of those that can not follow most of your explanations - my or
your bad?
|
16 |
Hans-Peter Diettrich
replied
on 23-Feb-2010:
Rudy Velthuis (TeamB) schrieb:
(snip)
You never worked in a team? [except as its boss? ;-]
DoDi
|
16 |
Rudy Velthuis (TeamB)
replied
on 23-Feb-2010:
Joanna Carter wrote:
(snip)
Just an aside: if I see "decomposed", I think of dead bodies. Do I
perhaps watch too many crime series, or is your code really falling
apart?
--
|
20 |
Rudy Velthuis (TeamB)
replied
on 23-Feb-2010:
Hans-Peter Diettrich wrote:
(snip)
In my clinic, I am the boss. If I am not there, no patient can be
treated.
But I think everyone should design their own code. Not the specs, not
the overall design, but their own code.
|
32 |
Joanna Carter
replied
on 23-Feb-2010:
Rudy Velthuis (TeamB) a __crit :
(snip)
That'll be your medical training kicking in :-)
Joanna
--
Joanna Carter [TeamB|http://www.teamb.com]
|
13 |
Paul Scott
replied
on 23-Feb-2010:
Rudy,
On Mon, 22 Feb 2010 21:12:16 -0000, Rudy Velthuis
<✉rvelthuis.de> wrote:
(snip)
Nobody could possibly disagree with that - and I certainly don't.
(snip)
Merely follow a few simple rules - and nothing can ever go wrong? Perhaps
|
138 |
Quentin Correll
replied
on 24-Feb-2010:
Rudy,
| Just an aside: if I see "decomposed", I think of dead bodies. Do I
| perhaps watch too many crime series, or is your code really falling
| apart?
LOL!
|
10 |
Loren Pechtel
replied
on 24-Feb-2010:
On Tue, 23 Feb 2010 04:46:12 -0800, Rudy Velthuis (TeamB)
<✉rvelthuis.de> wrote:
(snip)
The only case it's legitimately *NEEDED* (and even then simply nilling
it afterwards does the same thing) is a case where an internal
structure may be allocated and disposed during the lifecycle of it's
|
37 |
Marjan Venema
replied
on 24-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
No argument here.
(snip)
Yes. That happens. Doesn't mean you can turn the argument around.
(snip)
Probably yes.
|
148 |
Marjan Venema
replied
on 24-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
My real world differs. :-)
The single parts themselves can be so complex as to require single parts of
their own, that in turn require... etc. Then throw in some heavily
|
60 |
Marjan Venema
replied
on 24-Feb-2010:
"Rudy Velthuis (TeamB)" <✉rvelthuis.de> wrote in message
news:✉forums.codegear.com...
(snip)
I do. But that is not all I do. In addition I get to work on the code
(design and implementation) of others and they get to work on my stuff.
--
|
24 |
Marjan Venema
replied
on 24-Feb-2010:
"Joanna Carter" <✉no.spam.for.me> wrote in message
news:✉forums.codegear.com...
(snip)
Yep, working with just two developers, it is easy to keep abreast of
changes. Working in a larger team that becomes more of a challenge. Your
original design will be changed without you knowing about it.
|
94 |
Joanna Carter
replied
on 24-Feb-2010:
Marjan Venema a __crit :
(snip)
If the interface to the design changes, then that change should be
published. It should be obvious from either documentation or comments in
the code.
(snip)
But the key is still that each part of any suite must retain its
|
55 |
Rudy Velthuis (TeamB)
replied
on 24-Feb-2010:
Marjan Venema wrote:
(snip)
I'm sure I won't spot any pink elephants.
--
Rudy Velthuis (TeamB) http://www.teamb.com
"In theory, there is no difference between theory and practice.
|
31 |
Rudy Velthuis (TeamB)
replied
on 24-Feb-2010:
Loren Pechtel wrote:
(snip)
Sure, but there it is not even needed. In such cases, nil is being used
as a flag that the slot is empty. There are other ways to manage the
slots. But it can be used that way, OK.
I'd prefer allocating the objects when required and only assigning new
|
39 |
Rudy Velthuis (TeamB)
replied
on 24-Feb-2010:
Marjan Venema wrote:
(snip)
The overall design can be complex. That does not mean it is impossible
to balance construction and destruction.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
29 |
Rudy Velthuis (TeamB)
replied
on 24-Feb-2010:
Marjan Venema wrote:
(snip)
You mean they design your code? Of just the interfaces?
--
Rudy Velthuis (TeamB) http://www.teamb.com
"The shepherd always tries to persuade the sheep that their
|
18 |
Loren Pechtel
replied
on 24-Feb-2010:
On Wed, 24 Feb 2010 07:40:34 -0800, Rudy Velthuis (TeamB)
<✉rvelthuis.de> wrote:
(snip)
I'll agree it's often put to a bad use. We know of one legitimate
case--and it's unlikely that's unique. Thus you shouldn't
automatically condemn it. You're trying to throw the baby out witht
|
47 |
Dalija Prasnikar
replied
on 24-Feb-2010:
(snip)
No pink elephants here ;)
Dalija Prasnikar
|
29 |
Krzysztof Szyszka
replied
on 05-Mar-2010:
Uzytkownik "Rudy Velthuis (TeamB)" <✉rvelthuis.de>
napisal w wiadomosci news:✉forums.codegear.com...
(snip)
I have only one question. Why the code located below was written as is?
(unit DBGrids.pas - Delphi 2010, but without any changes since Delphi 3)
destructor TCustomDBGrid.Destroy;
|
51 |
Joanna Carter
replied
on 05-Mar-2010:
Krzysztof Szyszka a __crit :
(snip)
Because nobody reviewed the code before it was released and nobody else
has had the time to change it?
See the "Lava Code" antipattern
Joanna
|
31 |
Rudy Velthuis (TeamB)
replied
on 05-Mar-2010:
Krzysztof Szyszka wrote:
(snip)
I don't know WHY it was written like that, but it shows that the VCL is
not always an example of stellar design.
--
Rudy Velthuis (TeamB) http://www.teamb.com
|
33 |