C++, Ada, ...

I agree that it takes a mental leap to go from an imperative language to a functional languge, or to a logic-programming / declarative language.

To maintain a Haskell program, one would certainly prefer to hire a programmer experienced in functional programming, over one experienced only in C, C++ or Ada.

Relying on libraries/packages from the Internet is also a huge vulnerability. Not long ago a large part of the world's programs in one of these languages (unfortunately I forget which -- it was reported on comp.risks) suddenly stopped working because they all depended on real-time download of a small library package from a certain repository, where the maintainer of that package had quarreled with the repository owner/provider and had removed the package. Boom... Fortunately it was a very small piece of SW and was easily replaced.

The next step is for a malicious actor to replace some such package with malware... the programs which use it will seem to go on working, but may not do what they are supposed to do.

Reply to
Niklas Holsti
Loading thread data ...

If the call is not in fact inlined, it seems to me that the compilation of the caller does not see the "asm volatile" in the callee, and therefore might reorder non-volatile accesses in the caller with respect to the call. But perhaps such reordering is forbidden in this example, because p is a pointer, and the callee might access the same underlying object (*p) through some other pointer to it, or directly.

I mostly agree. However, there is always the possibility of having an exception, and the question of which variables an exception handler can see and use.

When all variable declarations are collected in one place, as in

declare begin exception end

it is easy and safe to say that the handlers can rely on all the variables declared between "declare" and "begin" being in existence when handling some exception from the . If variables are declared here and there in the , they might or might not yet exist when the exception happens, and it would not be safe for the local exception handler to access them in any way.

Of course one can nest exception handlers when one nests blocks, but that becomes cumbersome pretty quickly.

I don't know how C++ really addresses this problem.

Yes, I have not yet used it at all, although I believe GNAT already implements it.

I imagine one not uncommon use might be in function calls, such as

x := Foo (@, ...);

I believe that the main reason this new Ada feature was formulated in this "more flexible" way was not the desire for more flexibility, but to avoid the introduction of many more lexical tokens and variations like "+=", or "+:=" as it would have been for Ada.

Reply to
Niklas Holsti

Unless the compiler knows otherwise, it must assume that a call to a function might access volatile information, so can not migrate volatile access across that call. Non-volatile accesses. that can not be affected by the call, can be.

>
Reply to
Richard Damon

It also helps with concurrency. From

formatting link

"Initially, the Rust team thought that ensuring memory safety and preventing concurrency problems were two separate challenges to be solved with different methods. Over time, the team discovered that the ownership and type systems are a powerful set of tools to help manage memory safety and concurrency problems! By leveraging ownership and type checking, many concurrency errors are compile-time errors in Rust rather than runtime errors."

I haven't kicked Rust's tyres, but that seems plausible

Reply to
Tom Gardner

In this case use the book I mentioned, plus Stroustrup's introductory book "Programming: Principles and Practice Using C++" is supposed to be good (I haven't used it). He also wrote "The C++ Programming language" which is more of a reference manual and which I found indispensible. Make sure to get the most recent edition in either case. C++ changed tremendously with C++11 and anything from before that should be considered near-useless. So that means 4th edition or later for the reference manual: I'm not sure for the intro book.

Alternatively it might be best to skip C++ entirely and use Ada or Rust. I don't have a clear picture in my mind of how to address that.

Yes, C++ is a superset of C, more or less. You do have to maintain some awareness of where dynamic allocation can happen, to avoid using it, at least after program initialization is finished.

Heh, if that means what I think it means.

Reply to
Paul Rubin

Oh, this is nice.

Preferable these days is to use a separate type for a value that is nullable or optional, so failing to check for null gives a compile-time type error. This is 't Option in ML, Maybe a in Haskell, and iirc std::Optional these days in C++.

I know about SPARK. Is CodePeer something along the same lines? Is it available through GNU, or is it Adacore proprietary or what?

I still have Burns & Wellings' book on SPARK on the recommendation of someone here. It looks good but has been in my want-to-read pile since forever. One of these days.

Reply to
Paul Rubin

Either the compiler "sees" the definition of the functions, and can tell that there are things that force the memory access to be done in middle (whether these functions are inlined or not), or the compiled does not "see" the definitions and must therefore make pessimistic assumptions about what the functions might do. The compiler can't re-order things unless it can /prove/ that it is safe to do so.

In C++ (and C99, but it doesn't have exceptions), you don't need to put your variables at the start of a block. But their scope and lifetime will last until the end of the block. So if you need a variable in an exception, you have to have declared it before the exception handling but you don't need it in a rigid variables-then-code-block structure :

{ foo1(); int x = foo2(); // When all variable declarations are collected in one place, as in

Flexible placement of declarations does not mean /random/ placement, nor does it mean you don't know what is in scope and what is not!

And you can be pretty sure the compiler will tell you if you are trying to use a variable outside its scope.

For the kinds of code I write - on small systems - I disable exceptions in C++. I prefer to write code that doesn't go wrong (unusual circumstances are just another kind of value), and the kind of places where exceptions might be most useful don't turn up often. (I use exceptions in Python in PC programming, but the balance is different there.)

Sounds reasonable.

Reply to
David Brown

Certainly. The differences between C++ and Ada are much smaller than to Haskell.

Some languages mix imperative and functional paradigms. In C++, you can do a certain amount of functional-style coding - you have lambdas, and with templates and generic functions you can manipulate functions to some extent. Ranges and list comprehensions are new to the latest standard, though being library features they are not as neat in syntax as you get in languages that support these directly (like Python or, more obviously, Haskell). Pattern matching is on its way too.

You see at least some functional programming features on many interpreted languages too, like Python and Javascript.

Going the other way, you get ocaml that is basically a functional programming language with some imperative features added on.

But for someone unused to functional programming, Haskell does look quite bizarre. (Though it is not at the level of APL!).

Would that have been a Javascript library? It is common (mad, but common) to pull these from external servers (rather than your own webserver), and it would happen every time a webpage with the code is loaded.

Reply to
David Brown

That's not so great if you call library routines that can raise exceptions, and having to propagate error values back up the call chain is precisely the hassle that exceptions avoid.

There is a proposal for "deterministic exceptions" in C++ that work like Haskell's Either monad. I.e. they are syntax sugar for propagating error values upwards, with the compiler automatically inserting the tests so you don't have to manually check the return values everywhere. I guess they are a good idea but I don't know if they can replace the other kind of exceptions. I don't know the current state of the proposal but some info and links should be here:

formatting link

Reply to
Paul Rubin

Baring a few minor issues and easy tweaks, pretty much any C code will also be valid C++ code. Some people use C++ as ABC (A Better C), taking advantage of a few features like better constants, references (rather than pointers), namespaces, and other points that look like they could work as extensions to C rather than a new language.

In general, you avoid dynamic memory in C++ by avoiding "new" or any standard library functions that might use it - just as you avoid "malloc" in C by not using it. There are many standard types and functions that can use dynamic memory in C++, but usually it is quite obvious if they will need it or not.

When you want to be more sophisticated, C++ gives you features to override and control "new" and memory allocation in many ways, with memory pools and custom code. But don't try that in the first couple of days.

Reply to
David Brown

If you think it means anything at all, then you are probably correct about what you think it means. (That sounds a bit cryptic, but it is meant literally.)

Reply to
David Brown

If you don't use exceptions, don't call library functions that raise exceptions. If you don't treat "errors" as something mysterious that might or might not happen, which should wander around the code in the vague hope that something somewhere can make it all better, then you don't need silent propagation of exceptions - also known as invisible and undocumented longjumps.

When you are programming on a PC, you can be using huge libraries where you know the basic interface of the parts that you use, but have no idea of the contents and what might possibly go wrong.

When you are programming for small-systems embedded systems, you /know/ what can go wrong in the functions you call - /nothing/. There are no unexpected or untreated errors - or your development is not finished yet. Any possible returns are part of the interface to the function, whether they are "success" returns or "failure" returns. In this kind of system, you don't have the option of showing a dialogue box to the user saying "unexpected exception encountered - press OK to quit".

They are indeed a good idea. I am quite happy with explicit exceptions or error indications that are part of the interface to functions, and I would be happy with syntactic sugar and efficient compiler support. What I would /not/ use on embedded systems is hidden mechanisms where you don't know what exceptions a function might throw.

There are plenty of other attempts at conveniently and explicitly handling errors using templates and classes that typically work as sum types (like the "Either" you mentioned) or a product type (like a struct with a "valid" flag as well as the real result type). I have found it convenient to use std::optional, for example.

Reply to
David Brown

I'm not aware of proposals for such a thing in Ada.

CodePeer is a for-money AdaCore tool, a static analyzer that basically (AIUI) applies bottom-up weakest-precondition construction and pre-post-condition analysis to detect many kinds of logical programming problems, in particular possible failures of run-time checks.

See

formatting link

To use it in practice on larger programs, one usually has to guide and help its analysis by writing a certain amount of explicit precondition and postcondition aspects into the Ada source (which CodePeer then verifies as part of its analysis), but that has other benefits too, of course.

Note that most if not all of the SPARK-specific comments that were used earlier have now been superseded by the precondition, postcondition, invariant etc. aspects in standard Ada, and the SPARK tools have been updated accordingly. I'm not sure if this replacement is complete; I haven't used SPARK.

By the way, did you know that NVIDIA has started using SPARK? There's a presentation at

formatting link

niklas holsti tidorum fi . @ .

Reply to
Niklas Holsti

I'd like to add: Read the generated assembly code. C++ is prone to exlpode surprises into it.

An experienced C embedded programmer would read the code, anyway ...

--

-TV
Reply to
Tauno Voipio

Agreed.

Unfortunately I've come across too many interview candidates that haven't a clue about the code emitted by a compiler when it encounters a function call.

Reply to
Tom Gardner

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.