From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,21960280f1d61e84 X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Newsgroups: comp.lang.ada Subject: Re: How come Ada isn't more popular? References: <1169636785.504223.139630@j27g2000cwj.googlegroups.com> <45b8361a_5@news.bluewin.ch> <3pejpgfbki.fsf@hod.lan.m-e-leypold.de> From: Markus E Leypold Organization: N/A Date: Mon, 05 Feb 2007 14:43:17 +0100 Message-ID: User-Agent: Some cool user agent (SCUG) Cancel-Lock: sha1:3G6dd9N6oy9UQpf2+WWdVciO7EU= MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii NNTP-Posting-Host: 88.74.38.71 X-Trace: news.arcor-ip.de 1170682695 88.74.38.71 (5 Feb 2007 14:38:15 +0200) X-Complaints-To: abuse@arcor-ip.de Path: g2news2.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsfeed.arcor-ip.de!news.arcor-ip.de!not-for-mail Xref: g2news2.google.com comp.lang.ada:9001 Date: 2007-02-05T14:43:17+01:00 List-Id: Maciej Sobczak writes: > Markus E Leypold wrote: > > [I agree with what you say on historical perspective on language > transitions and the probabilistic effects that languages have on > newbies, so this part was cut.] > >> If you just do f(s.c_str()) and f _is_ properly behaved, that is, only >> reads from the pointer or does a strdup(), everything is fine, but, I >> note, not thread safe. I wouldn't exclude the possibility that the >> resulting race condition is hidden in a nice number of C++ programs >> out there. > > If you have a race condition because of some thread is modifying a > string object *while* some other thread is using it, then you have a > heavy design problem. This is absolutely not related to interfacing > with C. Yes, I realize that. Still, providing a pointer to a the inner state of an object, that only stays valid until I touch the object for the next time is not only not thread safe (which I realized is not the problem) but it's not type safe: A error in programming leads to erronous execution, i.e. reading and writing invalid memory. That is worse. I think there was talk once about a thread safe string library, but at the moment I fail to see how that relates to the problem in question. > >> Your solution is thread safe, if the strings package is (which it >> wasn't in the past). > > Strings package cannot make it any better, because the granularity of > thread-safety results from the program logic, not from the package > interface. String is too low-level (it's a general utility) to be > thread-safe in any useful sense. That's why: a) it should not be > thread-safe on its own, b) you still have a design problem. Yes. I realize that. Don't know what made me write that :-). > Interestingly, Ada doesn't make it any better. Neithe does Java. You > always need to coordinate threads/tasks/whatever on some higher > conceptual level than primitive string operations. So forgive me. Let's ditch the thread safety aspect and instead: Giving pointers to internal state of objects violates (a) encapsulation (it fixes a specific implementation) and (b) is not type safe. I'm sure we can hang c_str() on account of this charge alone and can drop the thread-unsafety allegation. > [about closures] > >>> You can have it by refcounting function frames (and preserving some >>> determinism of destructors). GC is not needed for full closures, as >>> far as I perceive it (with all my misconceptions behind ;-) ). >> Yes, one could do it like that. Ref-counting is rumoured to be >> inefficient > > Which relates to cascading destructors, not to function frames. My impression was it relates to both. Especially since both are interlocked: In a world with closure objects (from OO) and variables can refer to closures (function frames) and vice versa). >> but if you don't have too many closure that might just >> work. > > If you have too many closures, then well, you have too many closures. :-) Yes :-). Only in a ref counted implementation even too many might not be enough. > We've been talking not only about performance, but also about > readability and maintenance. ;-) Of this thread? :-) > >>>> Furthermore I've been convinced that manual memory management hinders >>>> modularity. >> >>> Whereas I say that I don't care about manual memory management in my >>> programs. You can have modularity without GC. >> Certainly. But you can have more with GC. > > In a strictly technical sense of the word, yes. But then there comes a > question about possible loses in other areas, like program structure > or clarity. I think the absence of manual memory management code actually furthers clarity. > > 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? >> People who don't have GC often say that they can do anything with >> manual memory management. > > And I say that this is misconception. I don't have/use GC and I don't > bother with *manual* memory management neither. That's the point. In > Ada this point is spelled [Limited_]Controlled (it's a complete mess, > but that's not the fault of the concept) and in C++ it's spelled > automatic storage duration. My impression was that Ada Controlled storage is actually quite a clean concept compared to C++ storage duration. 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. 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. > Today manual memory management is a low-level thingy that you don't > have to care about, unless you *really* want to (and then it's really > good that you can get it). And as I've already pointed out, in my > regular programming manual memory management is a rarity. > 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. I've heard that complaint repeatedly, but still do not understand it. > The problem is that few programs rely on only memory and in a > typical case there are lots of resources that are not memory oriented > and they have to be managed, somehow. > When GC is a shiny center of the > language, those other kinds of resources suffer from not having > appropriate support. In practical terms, you don't have manual > management of memory, but you have *instead* manual management of > *everything else* and the result is either code bloat or more bugs (or > both, typically). Now, now. Having GC doesn't preclude you from managing ressources unrelated to memory in a manual fashion. 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 (i.e. the programm definitely won't use the external ressource any longer). Examples: IO channels (only sometimes useful), temporary files, files locks, shared memory allocations. Even if you manage ressources manually, GC still limits the impact of leaks. 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. > 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, I can't follow you here. 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. It's the generality we are getting rid of during the evolution of programming languages. Assembler is the "most general" solution, but we are getting structured programming, typesystems amd finally garbage collection. > The result is clean, short and uniform code, >which is even immune to extensions in the implementation of any >class. Think about adding a non-memory resource to a class that was >up to now only memory oriented - if it requires any modification on >the client side, like adding tons of finally blocks and calls to >close/dispose/dismiss/etc. methods *everywhere*, then in such a >language the term "encapsulation" is a joke. Well, you think Ada here. 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. 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). 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. > An ideal solution seems to be a mix of both (GC and automatic > objects), but I think that the industry needs a few generations of > failed attempts to get this mix right. We're not yet there. >>> OO is about encapsulation and polymorphism, these don't need >>> references everywhere. >> Yes, but -- you want to keep, say, a list of Shape(s). Those can be >> Triangle(s), Circle(s) etc, which are all derived from class >> Shape. How do you store this list? An array of Shape'Class is out of >> question because of the different allocation requirements for the >> descendants of Shape(s). > Why should I bother? > > 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. >> I've decided, if I want to deliver any interesting functionality to >> the end user, my resources (developer time) are limited, I have to >> leave everything I can to automation (i.e. compilers, garbage >> collectors, even libraries), to be able to reach my lofty goals. > > I also leave everything I can to automation. It's spelled > [Limited_]Controlled in Ada and automatic storage duration in C++. > I cannot imagine reaching my lofty goals otherwise. ;-) Good. '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. (b) AFAIR there are restrictions on _where_ I can define controlled types. AFAIR that was a PITA. >> The point is to know when to optimise, not to do it >> always. > I didn't even mention the word "optimization". I'm taling about structure. OK. 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 ... Regards -- Markus