Language feature selection

A quick/informal/UNSCIENTIFIC poll:

What *single* (non-traditional) language feature do you find most valuable in developing code? (and, applicable language if unique to *a* language or class of languages)

Reply to
Don Y
Loading thread data ...

Op 06-Mar-17 om 00:03 schreef Don Y:

I can't think of any language feature that is usefull in isolation.

Wouter "Objects? No Thanks!" van Ooijen

Reply to
Wouter van Ooijen

What do you mean be "non-traditional"?

The two languages I find most useful in developing embedded code are English and C, followed by Norwegian, C++ and assembly.

If these count as "traditional", then maybe it would be Python - that's the language I use most for scripts, auxiliary programs, test programs, etc.

Reply to
David Brown

Understandabililty, of the language and of programs written in that language.

Reply to
Tom Gardner

Flexibility/expandability. In vpa if I miss something for a while I can simply implement it rather than work around it every time.

Flexibility also means that being the lowest sensible level it allows me to go to higher levels of abstraction without changing language (with high level languages you can do that too on the way up, not so on the way down hence the tons of workarounds/ manufacturer libraries/templates etc. "unchangeable" thing which dominate nowadays).

IOW the most useful part of using vpa is the one which makes its use like using an alphabet as opposed to using a phrase book (the case with higher level languages).

Dimiter

------------------------------------------------------ Dimiter Popoff, TGI

formatting link

------------------------------------------------------

formatting link

Reply to
Dimiter_Popoff

Having read the other replies, I see you asked for "language /feature/", not "language". Sorry!

As Wouter said, I don't think it is possible to pick a single language feature like that. You want a language that gives you a balance of features - readability, maintainability, flexibility, efficiency, static error checking, high-level features, existing libraries, development efficiency, debug capabilities, etc. The balance may change according to different projects or applications.

Reply to
David Brown

I suspect we'd all agree that the ability to support "procedures" is highly valuable (imagine writing a complex piece of code *without* being able to invoke one). And, that adding support for functions enhances this capability (though functions without procedures makes little sense)

Call these (and similar) "traditional" features: "Givens".

Reply to
Don Y

Closures. Far more useful than (OO) objects.

YMMV. George

Reply to
George Neuner

What's the definition of "non-traditional"?

--
Grant Edwards               grant.b.edwards        Yow! My haircut is totally 
                                  at               traditional! 
 Click to see the full signature
Reply to
Grant Edwards

Whatever you want ("unscientific"). The question is meant to draw attention to that aspect of that you consider to be most valuable (using *your* definition of "valuable").

Reply to
Don Y

What about functional programming languages? They don't have procedures in the same sense as in a procedural programming language like C. You do have functions, but they are rather different from C functions.

Or BASIC? I believe some people make embedded software written in BASIC without procedures as such.

I believe I understand roughly what you mean, but I think it would take quite an effort to give a decent rigorous definition. And the way you pose the question implies that people regularly use programming languages that are have "non-traditional" features. Does that mean you think some features of C are non-traditional (since the majority of embedded programmers use C), or that some people use C in a non-traditional manner, or that you are interested in people who use languages other than C?

Perhaps a clearer question would be, "if you use a language other than C for your embedded programming, what language do you use and what feature(s) are particularly useful?".

Reply to
David Brown

But doesn't this complicate the run-time (e.g., drag in GC)? Or, can all of this (subsetted) be handled at compile time?

Reply to
Don Y

Are you thinking of superficial/syntactic differences (e.g., things that could be addressed with a macro preprocessor)? Or, genuine semantic differences (e.g., adding interprocess communication operators to a language that doesn't currently support it)?

Reply to
Don Y

There's no need to bind the discussion to C -- or any other language.

I suspect most folks (i.e., damn near everyone) has used more than one language in their career. And, formed preferences for particular languages largely based on what the language allowed them to *do* -- and, at some fuzzy point in time, they thought to themselves: " wouldn't let me *do* things like this!"

Limbo won't let me use pointers. I consider that a *huge* handicap as my coding style relies heavily on them in ways that feel "clumsy" to approximate using the mechanisms that Limbo supports in their stead.

OTOH, I can type "a few characters" and communicate with another process (even on a remote node) without all the cruft of having to open a connection to that process (as well as figuring out *where* it resides).

Reply to
Don Y

Which Norwegian: Bokmal or Nynorsk?

For non-traditional languages, how about APL - cryptic, for sure?

--

-TV
Reply to
Tauno Voipio

Not necessarily. Closures don't require GC at all unless they can persist beyond their definition scope.

Think about nested functions as in Pascal, but augmented with private persistent variables (trying to avoid the word "static" to prevent unwanted associations with C). This form of closure is stack-strict and does not require any heap allocation[1].

Such closures are confined to the scope in which they are defined, so a little thought (vs C) has to be given to program structure. But many programmers successfully used Pascal and modular descendants of it ... it isn't *that* hard.

Nested functions do require a little bit of runtime bookkeeping. A "display" (static scope array) is generally more performant than scope links in call frames. The size of the display for the program/module is fixed at compile time, and because it is accessed frequently (at every function call/return), it tends to cache quite well.

If you are providing GC anyway, then IMO there is no reason not to provide 1st class closures as they are just a small object containing a pointer to the code and a pointer to a separate heap allocation for the persistant variables[2]. Closure objects can be handled like any other data.

If you want GC to clean up unneeded code as well, that gets a little more interesting. You need to know the size of the code block to deallocate it, and it needs a global "name" (like any other data) so that closures can reference it. When there are no more closure objects referencing the block, it can be deallocated.

[Obviously, there is a race condition: what if GC runs before any closures referencing the code block are created? Best way to handle that is deliberate unloading of the containing module. Alternatively you could use (compiler directed) reference counting and define a special count value to indicate the block should be retained despite currently having no references.]

George

[1] persistant variables can be heap allocated rather than stack allocated to reduce/control stack size. In either case the persistant variables would be defined as a structure (de)allocated by the *surrounding* scope rather than by the closure function itself. [2] if there are no shared persistant variables, then a closure object can contain them directly rather than having a pointer to a separate allocation. This saves an indirection at runtime, but at the expense of more complexity in the compiler (non-uniform handling of shared vs non-shared variables).
Reply to
George Neuner

Forgot to mention: you can lambda-lift and remove the need for any kind of scope links iff the program is a single module.

But lambda-lifting doesn't work across modules.

George

Reply to
George Neuner

But that limits their utility. E.g., I instantiate heaps by allowing the instantiating entity to specify the nominal heap parameters (location, size, granularity, etc.) along with default *policies* (how it selects a piece of itself to allocate, how it handles the release of that allocation, how greedy/stingy it is in satisfying the request, etc.).

So, the instantiating entity can (often!) cease to exist before the supplied parameters are ever referenced. The selected allocation algorithm could reside in this "zombie" module... or, in the code space of the "task" using that heap... or, in the heap module "library of algorithms".

Of course, it means the instantiated heap needs some way of tracking these parameters (d'uh) and has to assume responsibility for ensuring that they are in place before the heap is used and disposed of when the heap is torn down.

[Making sure they are in place is relatively easy. Disposing of them can also be easy -- as long as you're careful not to attempt to use them after they have "been disappeared".]

Yes, but that limits the function's scope. It makes it difficult to "import" these from other modules.

I don't see it as a case of "difficulty" but, rather, "convenience". It forces code to take a particular form, regardless of how "natural" it may (not) seem.

[E.g., consider the heap instantiator example: why does *it* have to persist just so something it provides remains accessible?]

For "run forever" systems, its not an issue.

OTOH, if you can load and unload modules (as in my case), then you're faced with more explicit managing of those resources -- I can't kill off a module that has an outstanding reference to some *portion* of itself persisting in another module.

[In my case, an "object handle" ensures the OS will keep track of the "thing" for me -- including if it migrates elsewhere]

The advantage of having the *language* do this is that it enforces a consistency on the implementation (and, catches careless errors on the developer's part).

[In my case, the OS carries most of that burden -- *if* the developer treats these things as "managed objects"] [[Pecan Sandies tonight]]
Reply to
Don Y

I suppose both. The macro functionality in vpa is an example how I have proceeded over the years; at first I could just pass arguments (also trough macro within macro, not sure I ever used that but I had made it). At some stage I added partial argument passing, i.e. you can specify [starting character][character count]. Later I made the variable etc. script infrastructure thing available to vpa (dps shell variables are similar to those in unix shell but more complex in that a variable name can be put together of variables).

The interprocess communication is not vpa inherent, it is higher level. That is, at the lowest level your code must make a system call (named "signal" or sort of); at a higher level the code would refer to a dps object and ask it to do something like passing a message, an event etc (e.g. a display_window object contains an ID of a lowest level window descriptor, if you ask the display_window to do a "getevent" it will do what it takes at the lower level and get you an event descriptor which another object can "process" etc.). The variety of what different objects do can grow huge so it is impractical to put that in the language; the language itself is responsible just to provide the macros for "do" (which is a wasted word, was the first I used in a type of call which is useless but legacy supported.... :), I may add some higher level do-likes which would include passing the object quick ID, action initiator plus initiator quick id etc. (now I do the latter with plain operators explicitly, not sure I need to change this though).

I think of this higher level thing as of phrases built using the language though. Not sure where to put this re your query, when do phrases become part of a language? When does it become practical to invent a new symbol? In alphabet based language it just does not become practical (the Latin alphabet has been unchanged for a while), in hieroglyph based languages I don't know how it is (my feeling about the latter is they are limiting by nature though).

Dimiter

------------------------------------------------------ Dimiter Popoff, TGI

formatting link

------------------------------------------------------

formatting link

Reply to
Dimiter_Popoff

I am not sure you are right about that. A lot of embedded programmers know only C - perhaps with a vague knowledge about assembly from courses they took. Many other programmers have only ever learned one programming language.

Agreed (for people that have learned more than one language).

But what people view as "traditional features" is going to be based almost totally on the languages they are most familiar with. If you learned to program using Haskell, then you are going to think in terms of lists, recursion, functions-of-functions, etc. The idea of incrementing a variable or using a pointer would be completely alien - but infinite lists are perfectly normal and "traditional". The opposite is true for someone programming in C.

Reply to
David Brown

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.