C++ syntax without C++

Without it, the onus falls on the developer to *know* what's happening to the heap (for that particular class of object) and/or overspecify resources. Can you even *know* how much memory a C++ program will require? (without constraining the developer to never need temporary objects, never allow multiple threads to share a resource, etc.)

These sorts of mechanisms can be a real *boon* to developers. The problem that I see with them is their needs/cost seem to increase geometrically.

I.e., it's a real win if I don't have to worry about memory management on a tiny piece of code. I just mention an object and it's *there*! And, it magically goes away when I am done with it.

I can provision a modest amount of time.memory and easily accommodate this.

OTOH, when these sorts of things see more pervasive use in bigger applications, you quickly lose track of what's being consumed -- at any given point in time. It's just too complex to wrap your head around --and *keep* it wrapped around!

E.g., in my automation system, I supply all the base services usually implemented in C+ASM. And, there are a LOT of them! The "applications" can be more like "applets". *Tiny* pieces of code that concentrate on a specific functionality. (this is where limbo/inferno come into play) All the heavy lifting is provided by external services. "Apps" can be a few KB and do immense mounts of work! And, *migrate* because they fit in a jumbo packet (or two)!

You want to know if its anyone's birthday, today? (so you can alter the doorbell chime to play "Happy Birthday") Query the "contacts" database -- which has been created, maintained, implemented and SERVED by "others" -- for "people of interest to me" AND birthday==today.

If you get any results, *tell* the doorbell service to contact the music server for "Happy Birthday" and bind that to the FRONT doorbell event.

Then, die.

I.e., "one screen full of code" (which has always been a goal of modern languages)

No need to worry about setting up the connection to the RDBMS. Or, figuring out how to retry the request if the communication fails first attempt. Nor figuring out

*where* the doorbell service happens to be executing at this present time. Nor whether the birthday-boy (or girl) name fits in a 23 character buffer[]. Or...
Reply to
Don Y
Loading thread data ...

There are obvious, unspoken incentives to NOT making things simple. "If it was easy, EVERYONE would/could be doing it -- what role do

*I* serve??"

You see this often with "consultants" -- coming up with solutions that effectively "ensure job security". I take the opposite approach (because I consider having to revisit something to be a "chore" -- like mowing the lawn... AGAIN!)

This can be perverse! E.g., there will ALWAYS be police -- because there is no incentive for them to "do away with crime" and, thus, their own jobs! :> (tongue-in-cheek)

I had a colleague who had a great take on this! He was in charge of quality. He would openly state that his goal was to make his job obsolete! I.e., to improvethe process(es) to the point where quality was *inherent* in everything. A lofty goal, of course. But, consider the opposite attitude: that of "traffic cop".

If you *don't* need a language lawyer to understand a language, then what role does the language lawyer have, going forward? :>

But, "job security" (again, tongue in cheek)

Reply to
Don Y

Garbage collection in C++ is a categorical mistake: it isn't C++ anymore (and whatever it is called, it won't work reliably anyway)

If you want GC, use Java. Period.

If you are worried about GC pauses in hard-realtime systems then 1) the "high frequency trading" application domain is the place to look. They push /everything/ to the limit[1] 2) you /are/ using processors and systems which don't have any form of cache nor interrupts, *aren't you*?

[1] to shave 30ms of the latency, they install a $600m trans-Atlantic dark fibre link. They will also hardcode business rules (i.e. when and how much to trade) in /FPGAs/.

Reply to
Tom Gardner

If you try to ignore a checked exception, your code simply won't compile.

You must either explicitly catch the exception in your method, or explicitly define that your method can throw the exception. (Inserting either requires one keystroke in a modern IDE :) )

That's the best kind of documentation - something you cannot ignore!

Reply to
Tom Gardner

I'm not using C++ at all. Just hoping to use some of the "free" features/syntax if I can to pretty-up the code. I use C/ASM for all the [SH]RT work and big services. Limbo for the "toys apps" that run atop it.

My point about no GC in C++ means *someone* has to worry about memory -- fragmentation, etc. All those hidden "in the whitespace" operations that you may or may not be constantly aware of...

I find Java equally bad. "It takes a lot to say a little".

Limbo has the "C version of Java" mentality. It tries to do a bit more *for* you than C did. But, doesn't have all that syntax that Java (and C++) bring to the table.

I.e., you can write short programs that actually *do* something (without having to build lots of libraries to bring in all the help you need).

No garbage collector in real-time paths. Anything "iffy" then the RT tasks deal with the possibility of not meeting deadlines (and recover/react appropriately). Often at disproportionately higher costs! :<

E.g., if audio client misses packets, doesn't blindly resume "playing" future incoming packets. Don't want to get stuck in a mode where the audio is "stuttering" from a persistent problem. "Silence is preferable", etc. Of course, figuring out a real remedy is even MORE preferable (and more expensive!)

If,for example, client dropped a packet, then perhaps it can request a copy from a peer. OTOH, if the server isn't delivering packets as expected, could be a server problem, a fault in the fabric, etc. "Something with more global knowledge will have to decide -- based on conditions that I (and others) report to him"

Reply to
Don Y

But it doesn't force you to "handle" it effectively. I.e., you're still dependant on developers being "responsible" (and not just propagating all exceptions up the food chain, etc.).

I suspect it's much like folks adding extra casts to silence compiler warnings -- instead of thinking about why they were "needed" (a sign of something WRONG elsewhere)?

Language designers really have a tough time. Every time they put something in place to "improve" the code, they risk it being seen as an "irritation", instead. So, instead of its intended goals, it just fosters workarounds that render it useless. Or, *worse* than useless?

:<

Must be sort of what raising kids is like! ;-)

Reply to
Don Y

There area other forms of "pay" than money.

- Bill

Reply to
Bill Leary

Malloc doesn't drag in "error handling, standard libraries, etc." If you *need* to add something to report an error, then *that* is something YOU drag in. You can choose to use malloc without ever emitting an error message (in fact, you may not have a *means* of emitting an error message!).

Or, the error could be just a blinking light.

Or, you could find some other way to recover from a failed allocation.

It's not a necessary consequence of using malloc.

All this is visible to you and allows you to decide if you want to bear the cost.

If you've created a class, you *know* constructors will be needed (even if default). But, you mail fail to appreciate *where* they are all invoked -- even if you (later, after realizing their presence) understand *why*.

I want to use features "known" not to have these sorts of "hidden" consequences.

E.g., returning to my namespace example... I can't see how a *rational* implementation (C++) would add any cost (runtime time/space) to a piece of code that uses them.

[I could see how an *irrational* implementation might -- late binding, etc.]

What I want to know is what I can be "guaranteed" of using along these same lines -- such that the code created is virtually identical to what would have been created had I bracketed everything in extern "C"...

E.g., does C++ compile of main() -- using absolutely no C++ specific features! -- change the initialization process "markedly"? Are any changes purely of a transient nature -- or do they persist throughout execution?

Then, I can (hopefully) go about figuring out how to ensure *only* those features are accessed in the "C++ compiler" with a suitable "my-lint"

Yes. I just want to use the ones that come for free! :>

E.g., pre C99 being able to "//" had merit in many places (though /* was still useful). Wanting to use it in std C obviously drove its later inclusion in the standard -- it was just a syntax issue (no real "cost" to the feature in terms of the code generator)

Reply to
Don Y

Features can be orthogonal. E.g., floats don't really "enhance" ints. Though they *do* bring capabilities to the language that may have been missing or tedious, before.

E.g., classes, by themselves, don't add much that can't similarly be done with structs in C. But, once you start thinking about inheritance, etc. then a C solution gets to be more trouble than it is worth.

Likewise, you can add exception handling to C -- but at some "manual" cost (in terms of coding effort as well as verifiable syntax, etc.)

Hmmm... I've got a hankering for ice cream... question is, do I yield to it or wait for it to pass...?

Reply to
Don Y

What I said was that it *can* drag it in. It depends on the toolchain and how it is configured. Precisely this happened to me (using newlib+gcc).

My point was that it is *not* always visible. You *cannot tell* without looking in to the details of the implementation or trying it. Just like your c++ examples.

I doubt it is possible to "guarantee" such things, since implementation overhead is not going to be in any standard. For c++ you are going to have to experiment with different features and look at their effects in the executable (as David suggests).

So for a c++ "main" perhaps the compiler will emit a load of code to handle exceptions, even if you never use them. Or not. It is going to depend on the compiler and/or you passing the

--I-dont-want-any-of-those-exception-things flag.

Although AIUI one of the guiding principles of c++ is supposed to be that it does not add overhead for things you don't use, so...

[...]
--

John Devereux
Reply to
John Devereux

There are certainly some features that will be entirely free (assuming a "rational" implementation). Namespaces, function overloading, class /static/ members (variables and functions), references, and strong enumerations will all be completely free in the sense that they will not generate any more code than you would get with C code, and that if you are familiar with the results of C compilation then there will be no hidden surprises. The same also applies to C++ features that have moved into C99, such as // comments, inline functions, and mixing declarations and statements.

As I have noted before, you need to disable exceptions and RTTI - these /might/ make the C++ compiler generate poorer code on C source than it would in C mode. But with these disabled, any C code should produce virtually identical generated code when compiled as C++ (assuming you avoid pathological cases like "sizeof('a')" ).

We disagree on whether C++ classes are free or not. Fair enough - it's a matter of how we choose to define "free" and "hidden costs". But class static member variables and functions will be free by any definition.

As long as you view classes as "not free" due to "hidden" constructors, then you will lose out on a lot of the potential of C++. Maybe you can find a compromise, such as disabling the default constructor in the classes you use so that all class object definitions use a syntax that looks like a function call - then the cost, small though it is, will be obvious. (As long as you don't define a destructor, then destruction is free.)

Template usage is a matter of opinion too, and a matter of usage. Many compilers let you disable automatic template instantiation - then it is only the templates that you explicitly ask for that generate code.

As far as initialisation in main() is concerned, with C++ the compiler will generate code to go through a list of static constructors before main() starts. On some compilers this is done before main() is called, on others this code is injected into the start of main(). If you don't have any static constructors, this will take very little space and time and may be eliminated entirely.

mvh.,

David

Reply to
David Brown

Yes, and it requires highly-specialised experts plus good language support to do it effectively.

With C++ most people aren't experts and the language inhibits them.

But that "lot" has /very/ significant benefits when it comes to writing large programs with many disparate disconnected libraries. There are many "derived" languages that do reduce the number of characters, but with the penalty that none of the following are possible...

Any modern IDE will enable you to type ctrl-cpace and it will then present you with a list /all/ of the available operations at that point in your code. And the list will be pruned as you type each character.

Any modern IDE will also allow you to make major changes to part of your code and will automatically change all other parts to match the change.

Any modern IDE will also save you most of the annoying typing, e.g. "surround this bit of code with try-catch for all the exceptions that can be thrown by that code"

But in HRT, GS is the least of your problems, because it can easily be avoided. Not so the others I mentioned.

Reply to
Tom Gardner

Of course. But nothing forces you to write "a+b" when "a-b" is correct.

That is often (but not always) the most appropriate course of action - if your code can't take appropriate recovery action, then it has to be the higher level's responsibility.

Oh, anybody with any sensibility /knows/ they are going to c*ck up their children in one way or another! Deal with it!

Reply to
Tom Gardner

For me, these go hand in hand. for (auto i : someList) { sum += i; } is more expressive and has less risk of error than, say, for (list_node* p = list_first(&someList); p != NULL; p = list_node_next(p)) { sum += *(int*) list_node_payload(p); }

I've made that experience more with libraries that cite their age as an excuse: we have our own string library, our own containers, our own exception class hierarchy, because we're older than the standard versions.

(Or, "because we're smarter than the standard people".)

Stefan

Reply to
Stefan Reuther

[...]

Last time I looked they also solved the GC problem by installing enough memory to survive a day without GC, and use the GC (or reboot?) in the nights.

Stefan

Reply to
Stefan Reuther

Or, the "flood it with resources and hope" strategy. E.g., if you can use secondary storage for VM, then what's the problem? So what if things get slow... at least they *work*, right?

[I love watching my Firefox sessions grow to multi-GB and slow to a crawl. What the hell are you doing in there? Imagine what it would be like if you were running 24/7/365!!]

C++ (and many modern languages) try to make "programming" like driving a car -- no knowledge required!

There is some appeal to this. A good deal of software truly *is* disposable. Same rationale that gives us "90 day (hardware) products" -- that die just past the warranty period. Should I assume the hardware designers are all incompetent fools? Or, that they have been charged with deliberately screwing their customers?

(Gee, are software bugs the equivalent of "planned obsolesence" in hardware?? Maybe these programmers are NOT idiots! But, rather, highly skilled in producing a product that *almost* works -- just like your disposable TV, phone, etc! :>)

I can usually manage complexity effectively with a good problem decomposition. Lots of *small* subsystems instead of a few *huge* ones.

When I had to pick an "application language" for the automation system, I spent a lot of time "auditioning" a wide variety of languages: C++, C, Lua, Python, Perl, M2, ML, "BASIC", PHP, Java, etc.

This made it a lot easier for me to derive a clearer set of constraints for what I was really *looking* for in that candidate language.

I would fabricate typical "applets" and see how easily they could be coded, how "expensive" the implementations ended up and how "correct" the results.

I quickly decided that I didn't want to need "experts" to create these little things. That a weekend tinkerer should be able to "do something" (as in "produce a complete working program") in a weekend -- cuz he'd waste a lot of time trying to pick up where he left off on the NEXT weekend!)

And, like "hand-me-down furniture", once that code snippet found its way into the system (*his* system), it was probably going to stay there until the legs fell off! (when was the last time you *repaired* a piece of old furniture vs. just kept *using* it?)

Here's the sort of "applet" that I would never be able to anticipate in designing/deploying the system but likely to come up:

We purchased a new washer dryer. Washer is a front loader so it opens with a "door" -- to the *side* (vs. a top loader that opens "up"). Unfortunately, the washer is right "behind" the doorway into the garage -- which tends to be the way we enter/exit the house, most of the time.

Apparently, you are encouraged to leave the door open after a wash to give things a chance to dry out. This wasn't necessary with top loaders becasue they didn't NEED to seal as tightly (water tends to follow law of gravity -- climbing *up* out of a toploader is a lot harder than "falling out" the front of a frontloader!)

Problem: if one of us is out and the other has left the door to washer open, entering the house through this doorway will end up breaking or damaging the dryer's door as the house door crashes into it.

I have an electrically operated doorlock on the door in question (from the garage). So, I can decided when/if to allow it to be opened without requiring human intervention.

If the washing machine had already been instrumented, (the washing machine already *knows* when its door is open/closed!) I could write something like:

while (washer.door == open) { garage.door.lock() garage.door.lock.reason = "The door to the washer is open"; }

So, any party returning home will automatically encounter the locked door (this means the other party who remained at home doesn't have to REMEMBER to lock the door in this case -- AND unlock it when the washer has "dried out").

When he/she wonders *why* the door is locked, the system can tell him/her ("The door to the washer is open"). He.she can then contact the other party -- assuming the system hasn't already reported the blocked attempt to open the door!

So, the problem becomes not one of "how do *I* design incredibly large, complex systems" but, rather, "how does someone who has no engineering depth in understanding EXISTING large, complex systems make effective changes and additions to that system without tearing their hair out

*or* compromising the system -- and, do so in a manner that doesn't bring disproportionate costs to the project (how much $$ is the above feature worth? OTOH, how much could it *save* you if the washer door DOESN'T get damaged on one of these occasions?) [Limbo came closest to fitting all the needs without lots of application scaffolding]

It can be avoided if you continuously remind yourself that it is (or MAY BE) happening! I.e., back to the "in the whitespace" issue that I originally mentioned!

You're far more aware of dynamic objects when you have to explicitly create and destroy them. When temporary objects "magically" come and go, you are less likely to notice. It falls into the background noise (assuming you knew about it to begin with)

Anytime someone/thing does something *for* you (on your behalf) there is a cost. No free lunches. The easier it is to forget about these things (or, simply not notice them in the first place!), the easier it is to get surprised/screwed later.

Reply to
Don Y

+1

Or, because you want to truly *know* how they behave (instead of how someone *thought* to describe them as behaving!)

Reply to
Don Y

But that's my point: if the person writing the code doesn't know what to do with the exception (lack of imagination/specification), then the fact that he now knows about it doesn't buy you anything!

The advantage of exceptions is they *can* percolate more information upwards -- instead of DISCARDING the detail in some lower level and just propagating "FAIL" back up through the call stack.

(Though no guarantee that anyone upstream will be able to figure out *which* operation caused the "ENOMEM")

We have -- by not having any! :> Far easier (and less risky) to be "honorary uncle" to others (seems they also are more appreciative of your time than they are of parents'!)

Reply to
Don Y

Wow. :-)

Even in a higher-level language which actually _has_ a register attribute (ie: C), I think I last used it well over a decade ago.

Advances in hardware and compiler technology have made it redundant in my eyes. About the only _possible_ legitimate use I can think of these days would be the GNU C variant which allows you to specify _which_ register to use.

Even then, I can't think of a time when I personally would choose to take advantage of this GNU C feature, given other available options.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP 
Microsoft: Bringing you 1980s technology to a 21st century world
Reply to
Simon Clubley

Hello Don,

Interesting, thanks; I had forgotten about the Z180. (I was still at school (back in the 80s) when I last played with the Z80 architecture).

Did it by any chance work in a way similar to the I&D space in PDP-11 systems from that time period ?

However, I've forgotten exactly how pointers to functions worked in on the PDP-11 in I&D space mode; it's been a long time since I wrote any PDP-11 code. It was the first architecture of my career, but I've not written code for it since then, and I've long since filled my head with other things. :-)

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP 
Microsoft: Bringing you 1980s technology to a 21st century world
Reply to
Simon Clubley

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.