Re: How come Ada isn't more popular?
- From: Markus E Leypold <development-2006-8ecbb5cc8aREMOVETHIS@xxxxxxxxxxxxxxxxxxxxx>
- Date: Tue, 06 Feb 2007 12:45:20 +0100
Maciej Sobczak <no.spam@xxxxxxxxxxx> writes:
I think the absence of manual memory management code actually
furthers
clarity.
I believe so. And I stress again - GC is not the only solution for
manual memory management.
OK. I accept that for the moment. I'm just not convinced you can do
everything you need with scope bound memory and if you introduce
manual MM again, you'll be back to confusing manual memory
management. I say this just to restate my point of view clearly once
again -- not that I think that either of us can prove his position at
the moment.
Being able to just drop things on the floor is a nice feature when
considered in isolation, but not necessarily compatible with other
objectives that must be met at the same time.
Which?
Determinism in both timing and resource consumption?
Which brings me back to what I said repeatedly to other people:
(1) That this determinism is very often not a requirement (outside of
embdedded programming)
(2) The determinism is shot anyway by using a heap, not by using
GC. Even better: GC can introduce detereminism in space
consumption by compacting the heap, which naive heaps with manual
MM don't do because of fragementation.
(3) What is often needed are upper limits not determinism and thos
upper limits can be guaranteed with GC or with an appropriate
collector.
People who don't have GC often say that they can do anything with
manual memory management.
And I say that this is misconception.
Good. :-)
Ada this point is spelled [Limited_]Controlled (it's a complete mess,My impression was that Ada Controlled storage is actually quite a
but that's not the fault of the concept) and in C++ it's spelled
automatic storage duration.
clean concept compared to C++ storage duration.
Clean? It adds tag to the type, which then becomes a controlling type
in every primitive operation.
I got bitten by this recently. Adding a destructor to C++ class
never has any side effects like this.
I understand. But the Ada OO way is peculiar, but not unmanagable.
Apart from this, the bare existence of *two* base types Controlled and
Limited_Controlled means that the concepts of controlled and limited
are not really orthogonal in the sense that adding one of these
meta-properties affects the interface that is "shared" by the other
aspect.
Still. Being able to add a Finalize means you need to have a tagged
type. I see no alternative.
It's a mess. Actually, it prevents me from thinking clearly about what
I want to achieve.
Wow.
But both tie allocation to program scope, synchronous with a stack. I
insist that is not always desirable: It rules out some architecture,
especially those where OO abounds.
What architecture?
I already say in another post: That is difficult to show with a toy
system. It only shows in larger systems where you really can't / don't
want to say in any give subsystem module how long a certain peice of
data lives. So none of those can be burdened with deallocating it.
The problem with Controlled, BTW, is that it seems to interact with
the rest of the language in such a way that GNAT didn't get it right
even after ~10 years of development. Perhaps difficult w/o a formal
semantics.
You see.
Yes, I see. But GNAT is also a political problem (see the role of
AdaCore, formerly ACT), so (public) GNAT not getting things right
might well not indicate a problem with reading the Ada standard, but
in the release politics for public version. My hint: There is no
incentive to release a high quality public version GNAT.
On the other hand, most languages with GC get it wrong by relying
*only* on GC, everywhere, whereas it is useful (if at all) only for
memory.
Now, now. Having GC doesn't preclude you from managing ressources
unrelated to memory in a manual fashion.
Of course. No, thank you. I prefer a language which enables me to use
the same logic for all resources, so I *don't have to* manage
*anything* manually.
Which as you said yourself, is difficult to do. And memory is
ressource used most frequently, whereas the temptation to e.g. drop
file descriptors is much less.
In other words, it's very nice that GC doesn't preclude me from doing
some stuff manually, but that's not enough.
I'm appalled: You don't want GC, but no, it doesn't do enough for you?
Of yourse YMMV. but when I have it, it works really well for me.
Apart from that languages
with GC often provide nice tricks to tie external ressources to their
memory proxy and ditch them when the memory proxy is unreachable
These "nice tricks" are not so nice. Most of all, they provide no
guarantee whatsoever, even that they will be invoked at all.
That's not quite true. Those tricks are building blocks to implement
ressources that are automatically finalized when becoming
unreachable. But it's up to the library author to write a complete
implementation.
A friend of mine spent long evenings recently hunting for database
connection leaks in a big Java application. That's telling something.
Well -- so he was naive and should have handled / understood that part
of the system better. A friend of mine spent half a month with finding
problems with manual allocation/deallocation and sneaking heap
corruption. Does that prove anything? I don't think so.
And BTW - in
fcuntional langauges you can do more against ressource leaks, sicne
you can "wrap" functions:
(with_file "output" (with_file "out_put" copy_data))
It's not always done, but a useful micro pattern.
Yes, it basically emulates something that is just natural in those
languages that provide scope-based lifetime out of the box.
This is no emulation, but how FP does "scope based". Without the
necessity to add exception handling at the client side or without
having to introduce tagged types / classes. Isn't THAT nice? :-)
Languages like Ada or C++ provide more general solution, which is
conceptually not related to any kind of resource and can be
therefore applied to every one.
Since you're solving a problem here, which I deny that it exists
You might wish to tell this to my friend - the one hunting database
connection leaks. :-)
Yes, I'll hold that up. Your friend got bitten by believing in a
mechanism where he shouldn't while I deny the the necessity to manage
other ressources by GC for the general case. It's a nice trick
sometimes, but one doesn't need it.
But I notice, that
"Languages like C provide a more general solution (with regard to
accessing memory), which is conceptually not related to any kind of
fixed type system and can therefore implement any type and data model"
would become a valid argument if I agreed with you.
Except that it's not the point I'm making.
No, but the structure of the argument is basically the same. The
analogy should help to show why it is (IMHO) invalid.
In an FP I write (usually) something like:
with_lock "/var/foo/some.lck" (fun () -> do_something1 ();
do_something2 param; ...).
The fact that Ada and C++ don't have curried functions and cannot
construct unnamed functions or procedures is really limiting in this
case and probably causal to your misconception that it would be
necessary to add tons of exceaption handling at the client side.
Tons of exception handling (and not only - every way to leave a scope
needs to be guarded, not only by exception) are necessary in those
languages that rely on GC without providing the above possibility at
the same time.
No. I've done the same in Ada w/o controlled objects, but using a
generic procedure.
procedure mark_data_records is new process_cache_with_lock( Operation => mark_record, ... );
begin
mark_data_records(...);
end;
The client side has no burden with exceaption handling.
The other possibility is to rely on scoped lifetime in
the first place, where neither GC nor the above tricks are necessary
to achieve proper cleanup.
Always assumed that works as a general apporach. Personally I cherish
the additional freedom I get from GC.
And BTW: In Ada I would encapsulate the ressource in a Controlled
object (a ressource proxy or handle) and get the same effect (tying it
to a scope).
Yes.
Indeed I have already done so, to make a program which
uses quite a number of locks, to remove locks when it terminated or
crashes. Works nicely.
Of course. That's my point.
(except, maybe, the crashing part, when likely there is nobody to
handle the cleanup)
By "crashes" I mean uncaught exceptions propagating back to the main
procedure. In those cases Finalize() runs.
I've BTW, done the same on OCaml (library for automatically
deallocating locks), so I don't see how GC prevents me from doing so.
Note also that I didn't say that references/pointers should be
dropped. I say that you don't need them everywhere. That's a
difference.
OK, so you need them _almost_ everywhere :-). I take your point.
No, you don't. I agree for references/pointers in polymorphic
collections. That's not even close to "almost everywhere" for me, but
your application domain may differ.
Yes. it does, abviously. You might not be aware, but code destined for
mere consumers (as opposed to embedded code and code destined as tools
for other developers) has a large amount of GUI code in it.
'Controlled' buys you a lot in Ada, but there are 2 problems
(a) AFAIS (that is still my hypothesis, binding storage to scope is
not alway possible (esp. when doing GUIs and MVC and this
like). I cannot prove but from what I experienced I rather
convinced of it.
I don't follow this.
(b) AFAIR there are restrictions on _where_ I can define controlled
types. AFAIR that was a PITA.
That's a mess. I'm sorry to repeat that.
Yes. But does C++ do it better? The Ada restrictions AFAIK come from
the necessity of separate linking and compilation (you must be able to
relink w/o looking at the body) and C++ treats that against the
ability to add finalizers everyhwere.
But how does a program become less structured by removing the
manual memory management? The GC is not magically transforming the
program into spaghetti code ...
You get spathetti once you start adding finalizers - the spaghetti is
then formed in both time (when something is invoked) and space (where
the code is).
No. Neither GC nore finalizers make code incomprehensible. I can only
assert it again, since are not discussing proofs here ore specific
examples.
Regards -- Markus
.
- Follow-Ups:
- Re: How come Ada isn't more popular?
- From: Maciej Sobczak
- Re: How come Ada isn't more popular?
- References:
- Re: How come Ada isn't more popular?
- From: Markus E Leypold
- Re: How come Ada isn't more popular?
- From: Maciej Sobczak
- Re: How come Ada isn't more popular?
- From: Markus E Leypold
- Re: How come Ada isn't more popular?
- From: Maciej Sobczak
- Re: How come Ada isn't more popular?
- From: Markus E Leypold
- Re: How come Ada isn't more popular?
- From: Maciej Sobczak
- Re: How come Ada isn't more popular?
- Prev by Date: Re: in defense of GC
- Next by Date: Re: in defense of GC
- Previous by thread: Re: How come Ada isn't more popular?
- Next by thread: Re: How come Ada isn't more popular?
- Index(es):