"High-Level" Considered Meaningless

Posted 19 Mar 2004 at 08:43 UTC by ncm Share This

Once upon a time, the adjective "high-level", applied to a programming language, denoted an increased degree of expressive power, implying not only economy of expression -- terseness -- but an ability to encode new abstractions encapsulating notions not actually envisioned by the language designers themselves. In the decades since the lambda calculus was first elucidated, and embodied to increasing degrees in the LISPs and their successors, language designers have learned to enable many different kinds of abstraction, and have increasingly concentrated on providing the scaffolding needed to manage the complexity that comes with such power.

Modern languages like Common Lisp, Dylan, ((O)Ca)ML, Haskell, Mercury, and (a bit unexpectedly) ISO C++98 demonstrate and embody much of what has been learned. Modern scripting languages like Python and Ruby bring some of the lessons to the masses. Even XSLT shows some evidence of this experience. These languages enable what would not only be unpleasant to express in assembly language, but effectively impossible without actually implementing something akin to these languages.

The term "high-level" has lately been abused to describe languages which offer none of the power it has been taken to imply, but instead only such incidental details of those languages' typical implementations as the bytecode representation, and garbage-collection apparatus, commonly used to simplify their (academic) deployment. This misuse is most egregious for the case of Java and C#, whose advocates assert the productivity benefits associated with scripting languages, and the power associated with truly high-level languages, without actually providing any of the language features that are prerequisites to these benefits.

Is C a "high-level" language? Most would say not: C89 provides some type-checking, and economy of expression over assembly language, but mainly practical portability. Are Java and C# high-level languages? What do they offer, beyond C? Do they offer the tools necessary to automate resource management? Do they automate anything besides management of the single resource, memory? How can a user encapsulate management of such resources as sockets, threads, or database connections?

Do Java or C# offer any kind of recursive compile-time evaluation, or pattern-matching? Can they implement anything akin to lambda, or monads? Do they provide the scaffolding and fundamental power needed to write libraries that successfully hide the implementation details behind powerful abstractions? What, in fact, is "high-level" about these languages?

The term "high-level" has sometimes been interpreted not to imply great power, but rather great convenience. Thus, SQL, Python, and sh have been described as high-level, not particularly because one can express, abstract, and encapsulate difficult concepts in them (although one might), but rather because one can very quickly bang out code to express commonly-used ideas without getting bogged down in the organizational apparatus necessary to keep large systems maintainable.

Do Java or C# offer any of the convenience, the economy of expression for common ideas, or the incremental interactivity of a scripting or specialized language? In a word, no.

In the previous decade, the term "object-oriented" was often misused to mean, simply, "good". Now that the former term seems less modern and mysterious, we seem to be adopting a term that is more vague for the same purpose. But is "high-level", even in either of its more carefully-applied definitions, a useful distinction? All modern languages (except Java and C#) seem to have become "high-level". Python even has lambda expressions.

A much more useful distinction is dynamic range -- how hard are the problems a language is good for?

For easy problems almost any language could be used -- speed doesn't matter, programs are small, and maintenance is more or less trivial -- so coding convenience is the most important consideration.

For hard problems, you need efficiency, apparatus to help organize huge masses of code, compile-time evaluation to abstract code generation, higher-order functions to operate on abstractions, control of execution details to enable tuning, and effective compile-time error checking to make broad, sweeping changes safe.

Python covers the easy-problem space easily, and (with its access to libraries) reaches far up into hard-problem space. C++ offers everything needed for the hardest problems, but is not so convenient to use for banging out trivia. They have an enormous overlap. Java and C# fall somewhere in the middle of that overlap -- far too inconvenient to displace Python where it is strongest, but lacking the other features needed to take on hard problems confidently. Their advocates often, indeed, describe it as ideal for "middleware", but have never elucidated why we need such a thing as "middleware". Most of what is coded as "middleware" would better be performed either with a specialized language or library, or in a scripting language, or, more likely, a little of both, at radically lesser expense.

The term "high-level" has been abused to the point of meaninglessness. A more useful measure of a language is "range": what discoveries about a problem, late in development, might lead to a realization that the language isn't really up to the job? Promoters of weak languages like to say that no language is inherently better than any other, and that every language is the right tool for some job. But do you always know, when you start, what exactly the job is? I don't. When you do know, that often implies the problem has already been solved many times, and a solution might better be encapsulated in a library using a powerful language, or embodied in a specialized language, or banged out in no time in a scripting language. When you don't, honestly, know, you are better off with a language that won't become another obstacle: a language with range.


Application specific languages, posted 19 Mar 2004 at 10:59 UTC by abraham » (Master)

The term high-level has often been used for what would be better described as application specific languages.

Java is an application specific language, still looking for an application to be specific to. It started by being ignored in the "embedded programming" area, then it became known in the "web browser toys" arena. Currently it has some success in the "teaching programming in trade schools" application area, that used to be owned by Pascal.

do i dare?, posted 19 Mar 2004 at 15:58 UTC by trance9 » (Master)

Java has reflection/introspection, generics, regular expressions, runtime binding, built in object serialization, built in lock management, etc., etc., etc. The j2ee/ejb extensions add automatic persistence, automatic thread management, automatic distributed transaction management, distributed object name binding, automatic generation of remote object interfaces, database connection pooling, message queues, translation of an object to and from xml, and so on.

You ask how users can encapsulate sockets, database connections, etc., and I'm wondering whether you are really serious as such it's a small matter for you to look at the java.io, java.nio, java.net, java.sql, etc., packages, and find out how it is done--unlike C/C++ it's a standard part of the langauge. Those are relatively "low level" things, though, in j2ee all of that is abstracted away from the developer to the extent that you don't need to think about it, as object persistence and the client/server grunt work is done by the container anyway. In fact, the linking between objects is abstracted away from the developer in j2ee.

Java doesn't have LISPy lambda expressions, it's not a functional language. It has a collection of tools which can be used to solve similar problems like reflection, anonymous classes, etc., but they're not lambda or s-expressions. Java also hasn't made the mistake of including things like operator overloading in the language.

A key thing that makes any *production* quality language high level, as opposed to academicy things like lisp, is the nature of its standard library. I can't bring myself to call a langauge high level if it doesn't include as a minimum basic ADTs like hashtables, lists, stacks, strings, regular expressions, etc.; and these days I would wonder at calling it "high level" if it didn't include relatively low level abstractions like database connections, directory services, message queues, and support for distributed objects.

I'm amazed at your ignorance about the size and scope of the Java market. You seem to think this is 1998 when Java was mostly used by academics and for web browser toys. You go on with these assertions apparently content to ignore the reality of the situation. Have you checked the number of Java projects on sourceforge and freshmeat lately? There are probably more Java projects underway than there are C++, if you exclude those written purely in standard C from C++. Certainly the paid programming market for Java is larger than much larger than for C++.

You mentioned XSLT as a high level language apparently unaware of the fact that in Java it's provided as part of the standard library. You might want to browse the javax.xml.transform package some day.

Try these: core API, J2EE.

I know I'm taking a risk trying to post substantive material on a thread started by ncm, but I'm gonna give him another chance.

Bjarne the dinosaur ..., posted 19 Mar 2004 at 16:39 UTC by redi » (Master)

... can point out that "modern" doesn't necessarily mean "better", and that both Java and C# are rooted in 1980s style OOP to an even greater extent than early C++ was.
Bjarne Stroustrup, on "modern, advanced" languages.

Re: do i dare?, posted 19 Mar 2004 at 18:37 UTC by tk » (Observer)

For one thing, this really makes me laugh:

Java also hasn't made the mistake of including things like operator overloading in the language.

Yes, a * b is too low level. Better to write a.multiply(b). Or, in accordance with Java's time-honoured tradition of using verbose, hard-to-remember method names, a.bagbitingMatrixMultiply(b).

And if operating overloading is such a grave mistake, then what's the thing that's used to concatenate strings in Java?

Agreed, then., posted 19 Mar 2004 at 19:41 UTC by ncm » (Master)

trance9: Your posting only re-emphasizes an early point of the article, that the term "high-level" has been stripped of its meaning, and is now only a marketing noise. Yes, Java and C# certainly are "high-level" (as well as "object-oriented") by the newspeak definition, and certainly generate demand for crowds of interchangeable coders in certain quarters. At issue, though, was whether they can legitimately claim to offer a thoughtful system architect/implementer the benefits that would accrue from satisfying the old, meaningful definitions. I presume that if they could, you would have suggested how.

Anyway, Java and C# were just examples, intrinsically no more interesting than such other inheritances as C and Forth. The purpose of the article was to suggest new, meaningful criteria to help in evaluating implementation language choices along dimensions of more than strictly commercial interest.

We still experience the fundamental conflict between "static", or compile-time, type-checking and inferring, as supported in ML-family languages, and in C++, but not in Ada or Java, and the traditional "dynamic", or runtime-bound approach found in LISPs, in Smalltalk, and in scripting languages, and (perforce) emulated in Java. Personal preferences seem still to depend more on imprinting experiences and on temperament than on evaluations of objective merit for particular purposes. "It's the sort of language you'll like if you're the sort of person who likes that sort of language." People who favor a sort of language also tend to favor problems best suited to that sort of language. Conflicts arise when the various problems don't sort themselves out neatly among the various people. I don't have any answers.

operator overloading, posted 19 Mar 2004 at 20:40 UTC by trance9 » (Master)

tk, operator overloading is one of those things seems really cool when you first hear of it, but soon enough you realize that you need to avoid it like the plague.

One problem is that it allows you to omit *important* information from your program code. If there is a bug in this line:

foo(bar() + baz())

there are a LOT of different methods being called that could be causing the trouble. It might take you some time to realize it's an oveloaded method that is at fault, or an implicit conversion method, or an implicit copy constructor, etc., and it might take you even longer to work out actually which classes method it is that's being called. Had you typed it all out explicitly it would have been obvious what methods were being called. Yes, you did save a few *seconds* of typing. But you cost someone else hours, if not days, of time trying to read and debug it.

What's worse is that C++ overloaded operators don't even work the way they're advertised. A large motivation in their design was to make strings more natural in the language, so you could write this:

String s1 = "hello"; String s2 = s1 + " foo"

and so on. That's great, as far as it goes, but it doesn't go much further than that, because this is impossible:

String s3 = "hello" + " foo";

No matter how many operators you overload that will never work. Which is amusing, given how much time C++ designers spent trying to make strings "first class citizens" in the langauge--they still aren't. They would have been better off hardcoding the string operators into the language anyway. The problem here demonstrates two things: how unobvious operator overloading makes your program, and how they didn't succeed in what they set out to do anyway.

What is &quohigh level&quo?, posted 19 Mar 2004 at 20:41 UTC by mslicker » (Journeyer)

ncm, if you could put in answer in precise language please. Is it a property of the language? Is a property of the implementation? Both? What are the specific criterion for a language to be considered "high-level"? This should not be a difficult request for someone who apparently such an authority on the term "high-level".

I will try to limit my correspondence to this notion of "high-level". Before you posted this we all had the knowledge that, for example, Java is not Lisp. We do not need to retread the ground that different languages are different.

Perhaps we can resolve this notion of "high-level" in less then 100 posts.

ncm, posted 19 Mar 2004 at 21:01 UTC by trance9 » (Master)

So I would say ease of working with abstraction would be the key, and the the criteria are:

  • How easy is it to understand an abstraction?
  • How easy is it to debug a problem with an abstraction?
  • How easy is it to use and re-use an abstraction?

And, as you said, we would be interested in commercial uses, not academic debates. So, for example, we could compare the easy of developing and using an abstractions like "bank account" and "persistence" and "distributed computing" and then combining them into a "persistent bank account", then accessing that persistent bank account from a remote machine, and so on. The key question would be how easy it is for someone else to understand the code when they see it.

One thing you've mentioned a few times which I think is NOT a criteria is terseness. Personally, I prefer readability over typeability. I would rather spend a few seconds more typing something if the result is more readable for others. These days I think the important relationships are those between major objects in the system, rather than the relationship between the variables in a local method, for example. It's important that the larger relationships be made clear.

"High-level" Considered Meaningless, posted 19 Mar 2004 at 21:04 UTC by ncm » (Master)

mslicker: I wrote an article, visible above, which you may feel free to read, at your leisure. I have reproduced the title immediately above, for your additional convenience.

terseness, posted 19 Mar 2004 at 21:14 UTC by trance9 » (Master)

Maybe this is a clearer explanation of my point about terseness:

Terseness of *design* is a good thing: Given a basic understanding of the langauge and its libraries, the reader of a program ought to be able to understand an abstraction by concentrating their attention on just a few components of the program, which they are able to identify and locate easily.

Terseness of a line of code or a method or function is irrelevant.

A good high level language reduces the number of "things" that someone has to think about at any given moment, not the number of lines of code they have to read. A bad high level language increases the number of things someone has to think about, or makes it more difficult to figure out what those things might be.

I asked for ncm's answer only., posted 19 Mar 2004 at 21:16 UTC by mslicker » (Journeyer)

ncm, You said "high-level" once had meaning when applied to programming languages. I am asking for you to state in precise language what this meaning was, what the criterion was, ect.

Was "high-level" always meaningless? If not please respond with the criterion.

Lambda not strictly necessary, posted 19 Mar 2004 at 23:05 UTC by johnnyb » (Journeyer)

Classes/Objects are actually just differently-packaged closures. Lambda's are simply more efficient for single-function closures, while objects are more efficient for multi-function closures.

My thoughts, posted 20 Mar 2004 at 01:56 UTC by Omnifarious » (Journeyer)

I don't consider operator overloading to be that important. But it is nice. |, ^, and & can be nicely overloaded for set operations, for example, and it will make perfect sense to anybody who realizes the operands are set types. The fact that it can be abused isn't an argument for not including it. Now, the fact that Koenig lookup is required to make operator overloading useful once you have namespaces might be a good argument for getting rid of it all-together, but I still don't really buy it.

With regards to lambda expression, johnnyb is not completely correct.

You can't implement lambda expression as classes in statically typed languages unless you have a meta-language for making decisions about types at compile time. In C++, this meta-language is the templating system. The templating system in C++ is actually a functional (as in paradigm, not 'functional' as in working (though, in gcc3 it largely works)) programming language that lets you make compile-time decisions about types.

I do not know if Java generics are powerful enough to do this. But, if they aren't, you cannot implement lambda expressions as classes in Java. A big part of the power of lambda expressions is the way they can be used to apply a function to any type of arguments.

As near as I can tell, with Java's numerous APIs, Java is very much like Microsoft Windows. In Microsoft Windows, there is an approved method of doing practically everything, and that method is largely not useful for any practical problem you might try to solve. It's vendorware, and not real. It requires many man hours and many developers to turn all that structure into something useful, and by the time you have, you've bypassed most of it to get things done. But, it's great for selling your platform to managers who don't know any better.

For example, it's pretty easy to use the C++ template system to build data structures that can automatically serialize themselves and don't look particularly ugly.

But, in the programs I've seen, automatic object serialization is thrown away as soon as the program gets beyond the toy stage anyway because it handles class version changes extremely poorly. It's just not that useful a feature unless you design a set of classes that have almost no behavior and consist largely of fixed data. They, in fact, strongly resemble database tables. It's a feature that sounds really great, until you use it, at which point you realize it's mostly useless for any practical purpose.

This post is a bit of a ramble, but I guess that I demand one main feature out of any new programming language I evaluate. The language must make it easy for programs to build programs, either at compile time, or at run time.

Java, last I looked carefully, couldn't do that. It has a static type system, so you can't combine objects together into new programs like you can in Python, Ruby, or even *shudder* perl. You can create new classes on the fly by using introspection, hand building byte code and feeding it to the class loader, but that's like pounding in a nail with a screwdriver. And it doesn't have C++'s sophisticated templating mechanism, so you can't build new programs at compile time. Now, it recently added generics, but I have a strong suspicion that generics will turn out to not be powerful enough to do what C++ templates can do. But that's just a guess.

As an example of what I mean....

Python has three functions, filter, map, and reduce. They are built in functions. They work easily and simply on any type. In more recent versions of Python, they even work well on any abstraction at all of a sequence.

I can build template functions that do the same thing, and are just as type agnostic (and preserving) in C++.

I doubt, even with generics, that I can build anything even remotely similar for Java. Note that the lambda expression (or object) passed in must have a method that takes objects of the type the sequence holds. It must not be required to take things of type Object.

Omnifarious,, posted 20 Mar 2004 at 02:30 UTC by trance9 » (Master)

The means of extending serialization is, for the classes where it becomes an issue, to make them "externalizable" as well; but for many applications actually serialization suffices because versioning isn't an issue--for caching, for RPC stuff, etc., it's not required. Aside from serialization there's jaxb, etc., which by using XML dispense with the versioning issues and are also standard APIs.

The way to build programs out of programs at runtime in Java is to use reflection and introspection. The typical design is to have the program structure specified in an XML or .properties file, and create it on load; you can also modify it at runtime dynamically. Almost all Java programs beyond a certain size follow this "deployment descriptor" sort of design. Even WebMacro way back in 1997 was built like this; obviously it's been expanded in EJB. Even for relatively lightweight and simple systems Class.forName("foo").newInstance() is easy enough that it's commonplace. For simple applications you would insist that the dynamically loaded class implements a particular interface; more advanced applications (eg: WebMacro/Velocity) simply introspect whatever is loaded to determine what can be done with it. Maybe what you want is the JSP model, a'la the way PERL and Python do this kind of thing, where you can dynamically build your own executable code--but I hate that, I think it's ugly and unsafe. C++ templates or Java's reflected interfaces are better approaches. Templates are slightly more elegant to write; reflected interfaces have the advantage that they can make use of code that was deployed *after* the application launched (let alone compiled) or which arrived over the network at runtime.

I don't buy your criticism of the Java API. The vast majority of them are excellent. There are a few exceptions where the API was hacked on at some last minute (eg: AWT) but most of them are simple, sound, and efficient. The process by which new ones are added, the JSR thing, is actually a good enough process that the newer APIs have all been quite good.

It IS possible to find examples where Sun adopted a worse API than the public was using apparently because Java is not opensource. The inclusion of java.util.logging instead of simply absorbing IBM's log4j is just mindblowing. So basically, most people still just use log4j; hopefully the java.util.logging API will improve.

But in most other cases the APIs that exist and that are being added are high quality and well thought out--the JSR process does work fairly well, and does get high-level people involved in thoughtful discussions. The java.nio and java.util.regex APIs are good examples. Though I haven't used them yet, some of the new APIs in 1.5 also look sound and well thought out, especially the addition of Doug Lea's advanced locking and lock-free concurrency packages.

As for lambda expressions I do agree that classes are not the same thing really. It would be nice if some day anonymous inner classes were actually full closures rather than only partial. They solve 90% of the cases where you would want a lambda; the other 10% there are generally alternate designs.

Java reflection and APIs, posted 20 Mar 2004 at 03:25 UTC by Omnifarious » (Journeyer)

I've seen the XML method of deploying Java, and it is as ugly as sin, and twice as evil. It creates vast gobs of program that do nothing at all, and then it takes even more man months making it do something. I worked at a company that almost died following that path. I avoided the project like the plague, but the people on it designed for months, and had a very *ahem* elegant system for loading whole UIs from XML files that made use of introspection, but their code didn't actually do anything.

5 months into the project, two developers ignored the whole mess and wrote a working system in a week. 2 months later, 60% of the development staff was laid off, and it was revealed that the project had put us over $1e6 in the hole, and we now were in danger of going bankrupt, despite the fact that we had a 20 year old product that was still selling well and had supported the company for years. A total boondoggle.

And, no, my criticism of the API is spot on. I've read many Java APIs, and they are mostly a lot of abstraction wanking with very little useful being done. I don't really understand how anybody writes working systems in Java, looking at the APIs beyond the base container library and things.

I think you're missing my point of the criticism of Java's reflection. Reflect is a bit uglier than templates, but what's really the problem is that in order to actually accomplish what templates do, you have to somehow create new bytecode at runtime and get the classloader to load it for you. *yech*

java.nio is something Java was forced into doing when threads turned out to not actually be the solution to everybody's problems like they were played up to be. And it doesn't hold a candle to Python's Twisted library or my own The StreamModule System.

Actually, the thing that prevents objects from being lambda expressions in Java is the lack of a compile-time interpreted language for talking about types, like C++'s templates. Anonymous inner classes are an interesting feature, and the fact that they aren't full closures isn't actually that much of a problem if Java is simply trying to be a better C++ instead of a better Python (which also doesn't have full closures if I'm not mistaken) or lisp.

It's a matter of degree, I think, posted 20 Mar 2004 at 06:18 UTC by Mysidia » (Journeyer)

Java, C++, or C# are higher-level than C or assembly. They provide the higher-level structures of expressions, classes, callable functions, and arrays.

In my estimation 'high-level' has almost always applied to languages like C++ according to some people, and others have had the opinion that something else is required.. there are reasons to think either way.

C++/C#/Java 's standard type libraries provide structures like vectors, lists, and maps/hash tables, for example.

Certainly they count as part of the language, and certainly they are better than the assembly or hardware languages, which definitely counts them as somewhere up there on the language pyramid.

You don't need Lambda, Patterns, Monads, or [insert cool feature of the year] to be high-level, and once a language is high-level people will keep calling it that, even when other languages of higher levels appear so that XXX language is nothing special. I mean: people won't magically stop thinking of a language as being high-level.

As popular languages appear with more features, or more features become popular, it won't necessarily move the definition of high-level.

[Good notation is important, but convenience of the notation in a language doesn't necessarily mean that it is a higher level.]

New groups of languages merit new terms to classify them. I really can't think of anything offhand... "ultra high-level" seems lame...

I don't know, I propose perhaps the likes of python, ruby, Lisp, [[O]CA]ML, etc, the things at the very high end should be called something like Extreme Programming Languages.

A name for very high-level languages, excluding such gems as C or C++.

I think it's natural that people want their pet language (like C++) to be a xxx language if xxx is cool, and the solution is to describe languages that have great things to offer with something more specific.

High-level Functional language is one thing you could say... 'Scripting' language, unfortunately, has negative connotations around some C++ programmers who don't understand that script languages _can_ perform as well as C++... (Maybe people whose total experience with script languages includes just 'BASIC')

Re: It's a matter of degree, I think, posted 20 Mar 2004 at 13:46 UTC by richdawe » (Journeyer)

New groups of languages merit new terms to classify them. I really can't think of anything offhand... "ultra high-level" seems lame...

Maybe the problem is that you're trying to think of an absolute term, when it's a spectrum. C++ is higher-level than C, which is higher level than assembly, etc.

Omnifarious,, posted 20 Mar 2004 at 16:32 UTC by trance9 » (Master)

Your bias shows through when you talk about using reflection as a way to simulate templates. That's insane. It's as insane as trying to simulate reflection with templates. Reflection implies a component based architecture which pulls itself together at runtime; possibly even months after the program was launched. Templates imply an approach which favours compile time code-generation. Those are very different approaches, but they both satisfy your "build new programs" criteria for a highlevel language.

Reflection is simple and elegant, and should consome no more than a few lines of code. If your company spent months on it, rather than minutes or hours, then you were trying to force it to be a template system or something else just as idiotic, rather than using it to build a simple component architecture. Nobody in their right mind would even *think* about trying to generate bytecodes on the fly in Java, so it sounds like you wound up spending months trying to pound in a nail with a screwdriver. Java is not C++. C++ is not Java. The best solution to a problem in one language will look very different than the best solution to the same problem in the other language.

As for the APIs, please be more specific, this vague handwaving that they are a lot of abstraction with little done--it isn't very constructive. My own experience has been just the opposite. I've found that the APIs contain good, sensible implementations of most of the things I need to do. For example, what do you think is wrong with java.nio? You've basically lobbed invectives at the APIs without giving any example of a problem with them.

Java strings apologetic, posted 20 Mar 2004 at 17:05 UTC by tk » (Observer)

trance9:

If there is a bug in this line:

foo(bar() + baz())

there are a LOT of different methods being called that could be causing the trouble. It might take you some time to realize it's an oveloaded method that is at fault, or an implicit conversion method, or an implicit copy constructor, etc., and it might take you even longer to work out actually which classes method it is that's being called.

The same holds with string concatenation. If you do a + of a string with an object that's not a string, you get an implicit toString() call, and you have to figure that out. Why's it that operating overloading is to be avoided "like the plague" because of this problem, except in the case of strings, then the exact same problem suddenly becomes very unimportant?

(A suggestion: before giving a counter-argument to the above, remember to check whether it applies equally well to strings and non-strings.)

"High-Level" Considered Meaningless, posted 20 Mar 2004 at 17:16 UTC by ncm » (Master)

mysidia: As I said. Certainly C++ as defined in 1992 was little "higher-level" than Java is today, and the only feature beyond C's that was much more than a convenience was its destructors. If you don't accord C++98 expressive power on a par with the MLs, though, you really don't know enough about it. (For a discomfiting education, visit boost.org.) In any case, as I (also) said, the term just isn't useful any more -- all modern languages (which doesn't include Java or C#) are high-enough-level, more or less.

Where modern languages distinguish themselves is not their relative abstract expressiveness, but rather the likelihood that you will discover, in the course of solving a large and difficult problem, that they don't offer the tools you need to solve one or another obscure subproblem that has ballooned to the point that it threatens the project.

Now, in principle, you can even use C to generate custom C code, and then compile and link or (at runtime) dynamic-load the result, so higher-order semantics are not entirely unavailable even for C. The fftw package does this. When the language has a weakness, you can go outside the language, albeit typically at a cost in portability, and always in convenience.

There are two ways to get convenience. You can build specific tricks into the language, as is commonly done in scripting languages. Then, you're limited to those tricks the language designer has thought up so far. The other way is to make the language powerful enough to code, and encapsulate in libraries, features that the designer might never have thought of. Then anyone can invent new ones, and anybody can use them.

In that sense, each built-in user-level convenience represents a failure, where the language just wasn't strong enough to express the feature directly. Garbage-collection means the language isn't up to general resource management. Built-in serialization, built-in string operations, built-in regular expressions, built-in matrix operations, all are indications of weakness.

High-level exists, and Java isn't, posted 20 Mar 2004 at 19:46 UTC by pphaneuf » (Journeyer)

trance9: "Java doesn't have LISPy lambda expressions, it's not a functional language."

Ahem, lambda expressions or closures aren't a staple of functional languages. Witness the following Perl:

sub get_fptr {
  my($obj, $method) = @_;
  my $code = $obj->can($method);
 
  if(defined($code)) {
    return sub {
      return $code->($obj, @_);
    };
  } else {
    return undef;
  }
}

The returned function pointer can be used anywhere where a pointer to a function with the same signature as the method it will call is needed. Do that in Java (or even C++, unfortunately).

Without really dissing what Omnifarious said on C++ templates allowing that (because it does), I have to say that this is very awful in C++ and the execution of which has a much higher cost than what it could be. IMHO, the pointer to member function feature in C++ is horrible, recording the class type. It could have be done as only recording the signature of the method, resolving any virtual method at binding time and being a simple 8 byte structure with the function pointer to the method and the this pointer, which would be wholly sufficient and *quite* useful. If it would be possible to also put in a normal function pointer (setting the this pointer to NULL to indicate that case), that would be extra sweet but would require a extra conditional to see whether or not to add the pointer to the stack frame. This could be worked around with a compile-time generated thunk, which bring us back to templates, but even then, C++ lacks tail-calls to make those extra-efficient (even if GCC uses them internally when using multiple-inheritance).

Omnifarious: "It's a feature that sounds really great, until you use it, at which point you realize it's mostly useless for any practical purpose." I totally agree with you, wlach and I even have a name for such things, "sexy things". For example, distributed objects, other forms of RPC and transparent object persistence are very common examples.

Mysidia: "You don't need Lambda, Patterns, Monads, or [insert cool feature of the year] to be high-level, and once a language is high-level people will keep calling it that, even when other languages of higher levels appear so that XXX language is nothing special." Well, "patterns" aren't a language feature, and both lambda and monads have existed for a very long time (lambda, which I am more familiar with, came from McCarthy's original LISP work in the 60's, if I am not mistaken). When you don't have them, you're not high-level.

This is like saying that a language is object-oriented even if it doesn't have inheritance, polymorphism or encapsulation. See HeInventedTheTerm.

boost.org -- what should we be looking for?, posted 20 Mar 2004 at 20:00 UTC by mslicker » (Journeyer)

ncm, Are you saying C++98 is now a typed lambda language?

Please support your statements, not with vauge references. Is this too much to ask?

My ex-company's project, posted 20 Mar 2004 at 21:05 UTC by Omnifarious » (Journeyer)

No, trance9, they were doing exactly what you were talking about. They had a complete description of a UI in XML files that loaded on runtime. And working with that god-awful, bloated mess is what nearly (or may have, the jury is still out on their survival) sunk the company.

They were not generating bytecode and runtime or anything like that. That idea was my own invention.

Also, when they were thinking about how to integrate their system with things that didn't run Java, they had to go through even more backflipping contortions. I suggested having a socket that the program listened on and accepted commands from non-Java programs, but this just wasn't something that the developers considered acceptable because it didn't use Java RPC, EJB, web services, or anything else. It was just simple, and it worked, and that's not the Java way.

Rants, posted 21 Mar 2004 at 02:22 UTC by tk » (Observer)

mslicker: How about this?

pphaneuf:

both lambda and monads have existed for a very long time (lambda, which I am more familiar with, came from McCarthy's original LISP work in the 60's, if I am not mistaken). When you don't have them, you're not high-level.

It's generally accepted that the first high-level language is not Lisp, but Fortran. The origin of the term "high-level" used to describe either Lisp or Fortran seems to be lost now, but Fortran was certainly called an "Automatic Coding" language back then.

..., posted 21 Mar 2004 at 04:59 UTC by trance9 » (Master)

Omnifarious: Well to be fair I wouldn't use Java as GUI langauge if that's what they were doing; the GUI APIs in Java do suck. Maybe not SWT, but it's not standard (yet?). And I don't know what this company did with the "whole UI in xml", that does sound a little complex. As I said, it sounds like they have issues that had nothing to do with language choice. It certainly doesn't sound like a typical component architecture to me. I'd need more information. EJB deployment descriptors, and the traditional servlet.xml, or the Apache groups's digester class (the way it's used in tomcat) are examples of the approach put to good use.

pphaneuf: PERL is a lispy language by design, read the language history, Larry Wall and co. explicitly say that was a goal. The equivalent in Java is this:

        public Runnable getRunnable(final String s) {
             return new Runnable() {
                   public void run() { System.out.println(s); }
             };
        }
Of course you can do whatever you like in the method body; call a function, whatever. You can use reflection if you want to call a function by name if you don''t want to hardcode it into your application. As has been said on this thread this solves the closure problem about 80% of the time, but since it's not theoretically a true closure you have to jump through a few hoops--in particular, you have to jump through hoops to access the dynamically changing state of the enclosing context. It can easily be done by way of an extra reference, but it's not natively in the language like with a lambda function.

ncm: What's an example of a problem that isn't soluble if you are missing some "high level" language feature? Never, ever, have I heard of a project getting stuck because it lacked a language feature. For example Java lacks lambda but you can simulate it completely by one extra line of code--you can get around the "references to the context must be final" limitation on inner classes by making a final instance variable a reference to the surrounding context. So you had to write an extra line? It hardly's going to cause your project to fail. Also, you keep saying "X is more high level than Y" but you have not yet provided your metric. By what criteria is it possible to judge that X is more high level than Y? You have been asked repeatedly and have not yet answered--I suspect that's because your true answer is "If it is C++ it is more high-level, because I say so."

tk: When you've had a little more development experience you will begin to understand why it's important to be clear in the code you write. You will come to understand that readability and debugability are more important than coolness or terseness. I know C++ pretty well, I was a C++ developer for years, a PERL developer for years, and a Java developer for years. Most langauges have cool features which you should avoid in the name of clarity. Operator overloading should be avoided in C++ because it makes software opaque. C++ templating, on the other hand, is a hands-down brilliant langauge feature. I've taken shots at C++ here mostly to deflate the people here who are so gooned on C++ that they can't see or think clearly when they look at other languages.

Functional programming in C++, posted 21 Mar 2004 at 05:20 UTC by mslicker » (Journeyer)

No, tk, I don't think that qualifies.

I found FC++, which attempts to bring "functional programming" to C++. On a technical note, among the limitations listed is:

Creating closures: Our functoid objects correspond to the functional notion of closures: they can encapsulate state together with an operation on that state. Note, however, that, unlike in functional languages, "closing" the state is not automatic in our framework. Instead, the state values have to be explicitly passed during construction of the functoid object. Of course, this is a limitation in every approach to functional programming in C++.

Looking at some example code, this is how they define "map":

struct Map {
   template <class F, class L>
   struct Sig : public FunType<F,L,List<typename F::template
      Sig<typename L::ElementType>::ResultType> > {};
   template <class F, class T>
   typename Sig<F, List<T> >::ResultType
   operator()( const F& f, const List<T>& l ) const {
      if( null(1) )
         return NIL;
      else
         return cons( f(head(l)), curry2(Map(), f, tail(l)) );
   }
} map;

For comparison, I implemented "map" in OCaml:

let map f l = if l = [] then [] else f (hd l) :: map f (tl l)

If C++ is to be considered a functional language "on par" with ML, it is clearly the Java of the group.

Aesthetically, C++ misses the whole point of functional programming, this is to avoid rampant featurism in favor of a simple and consistent formally defined syntax and semantics. Programs written in such a language were meant to be easier to write, understand and prove properties about.

..., posted 21 Mar 2004 at 06:02 UTC by mslicker » (Journeyer)

Again in OCaml, previously missing the keyword rec:

let rec map f l = if l = [] then [] else f (hd l) :: map f (tl l)

Dolts, posted 21 Mar 2004 at 06:07 UTC by tk » (Observer)

trance9: Did you understand the English in my last paragraph? To repeat:

(A suggestion: before giving a counter-argument [...] remember to check whether it applies equally well to strings and non-strings.)

mslicker: And why do you "think" that Boost doesn't qualify?

tk, posted 21 Mar 2004 at 06:30 UTC by mslicker » (Journeyer)

tk, Did what I post upset you?

For the record, you are the first to resort to name calling in this thread.

It is not obvious to me that expression "on par" with ML is possible in C++ and Boost included. I fully admidt to not being a C++ expert nor do I intend to ever be a C++ expert. This is why rely on experts in C++ who have attempted functional programming in C++, and have published their results in refereed journals. I understand the code provided by the authors of "FC++" only to the point that this is a C++ expression of "map" as can also be expressed in functional languages like ML.

If there is a better way to express "map" in C++ "on par" with languages like ML, please feel free to provide the code.

Three Points, posted 21 Mar 2004 at 07:01 UTC by ncm » (Master)

First, nobody ever said functional programming in C++ would ever be pretty. The point, though, is that it's possible. (C#, by contrast, clearly lacks any such capability, pretty or otherwise.) Languages that enable equivalent idioms qualify as "on par" with one another, by my definition. Any time a functional construct matters much, it can be placed in a library for all to use. A little bit of higher-order-ness goes a long way.

Second, while the resulting library component definitions aren't even close to pretty, the use is. Mark omitted a usage example for good reason.

Finally, the "whole point" of functional programming varies with who you are talking to. Some of us have work to do. There will certainly be languages in the future that exceed C++'s industrial range, along various axes, and every C++ user awaits them eagerly. What rankles is to have languages that came after, but that manifestly fall far short, treated as somehow better, solely on the basis of marketing dollars spent. What rankles more is to have conclusions that apply only to C misapplied to C++, solely on the basis of an aggressive ignorance.

Yes, several academic languages demonstrate an economy of expression better than is possible in C++. Let's work to adopt their techniques into an industrial language that can exceed C++'s range, and define a standard to enable multiple implementations, and promote it versus C++. Weak, money-oriented languages are worse than a distraction.

tk, posted 21 Mar 2004 at 07:20 UTC by trance9 » (Master)

You need experience, dude. The difference between having special code to handle the extraordinary case of strings, and having multiple layers of implicit conversions and overloaded operators all over your program is something I guess you will just have to learn the hard way. To answer your question, yes I understood your English; I am not as sure that you understood what you have been told. Despite what Bjarne may imagine, strings are not like "bank account" types. Today's lesson is over. You can go home now and study up on your own to learn why Strings have been special cased in so many languages, right back to the assemblers of yore. Tommorows test will cover the unit on managing the exponential growth of complexity in computer programs. Be prepared.

Re: tk, posted 21 Mar 2004 at 08:00 UTC by tk » (Observer)

The difference between having special code to handle the extraordinary case of strings, and having multiple layers of implicit conversions and overloaded operators all over your program is something I guess you will just have to learn the hard way.

Decoded: "There's really no difference, so I'll just get away by citing my `experience' at misusing overloaded operators."

You can go home now and study up on your own to learn why Strings have been special cased in so many languages, right back to the assemblers of yore.

Oh, really. I can write fluent x86 assembly using modern-day assemblers even as I speak -- how much experience do you have with that, by the way? There are only two things about strings which are really "special-cased":

  • Specifying a string: db "Hello world". Not really a special case, because many assemblers also allow you to directly specify bytes, words, structures, and sometimes floats. Nobody's complaining that this is bad, not even James Gosling.
  • So-called "string" manipulation instructions -- lodsb, stosd, insw, etc.; these are part of the CPU rather than the assembler. However, the word "string" here's used in a very general sense, as these operations can be applied not only to "strings" of characters, but also "strings" of floats, "strings" of words, "strings" of opcodes, and so on.

And...

Tommorows test will cover the unit on managing the exponential growth of complexity in computer programs.

The best way to manage complexity is to remove it. The end. Oh wait, that's a fail?

The difference, posted 21 Mar 2004 at 08:08 UTC by Omnifarious » (Journeyer)

trance9: The difference between having special code to handle the extraordinary case of strings, and having multiple layers of implicit conversions and overloaded operators all over your program is something I guess you will just have to learn the hard way.

No, the difference is between a programmer that knows what (s)he's doing, and one that doesn't. Extensive use of overloaded operators is bad. Careful use in controlled situations can greatly increase a program's clarity. Java has chosen to limit the number of controlled situations in which operator overloading can be applied to just one, because Java fundamentally believes programmers are incapable of doing the right thing unless forced to.

I prefer languages that give a greater range and power of expression to ones that restrict me to what I'm supposed to do because I'm supposedly an idiot.

I want to overload |, &, and ^ for sets. It makes perfect sense. The use will be obvious to anybody who looks. I want to overload && and || so I can leverage the C++ parser into building expressions for me. I want to write SQL as a series of C++ expressions and have a nice set of classes that build a parse tree and generate the appropriate SQL. I want to overload [] for vector and map types so I can index them as if they were random access arrays, because that's what they are, and it makes perfect sense to do it that way.

The lack of ability to express an idea does not make a language better. I thought we'd managed to deconstruct that argument in the bad old days where people were comparing C to Pascal.

"on par", posted 21 Mar 2004 at 18:04 UTC by mslicker » (Journeyer)

ncm, I don't know what your experiece with ML is, however the definition of functions like "map" are idiomatic to ML, they are an example of language usage. This example does not even touch what many consider the gem of ML, pattern matching. I am pretty sure any ML programmer told that C++ is "on par" with ML expression will be thouroughly disapointed. On the other hand, they might be quite impressed with the attempt, I was.

I don't support the marketing of any language, Java or otherwise. This article is an example of marketing. C++ is not the same kind of language as Lisp, ML, or Haskell, not aesthetically, not technically, it does not offer a comparable level of expression. I don't understand the repeated attempts to promote it as such. This is not to talk about which is better, I don't wish to enter such a debate.

As for Gnome's choice of future language, ultimately it is up to developers to decide. It is obvious to me other considerations have far more weight than technical or aesthetic considerations.

Re: "on par", posted 21 Mar 2004 at 18:44 UTC by tk » (Observer)

mslicker:

As for Gnome's choice of future language, ultimately it is up to developers to decide. It is obvious to me other considerations have far more weight than technical or aesthetic considerations.

For once I agree.

functors, posted 21 Mar 2004 at 21:39 UTC by pphaneuf » (Journeyer)

The Java example of the equivalent of the Perl code I gave is pretty horrible. For that simple example, it works, but what I don't like about it is that both the caller and the callee have to be quite prepared to cooperate like this, possibly to the point of having to declare a class.

For example, using Runnable only works if you do not have parameters. If you need any other signature, the one needing the list of callbacks needs to define a class with the one appropriate method, and the callee has to give a derivative of the exact same class. That is, another class with a run() method of the same signature won't do! So not only do you have to use an adapter class (instead of giving a pointer to member function of the real target, you have to give an object that will convert the call), but it requires a previous arrangement. If you deal with two frameworks that both have their own functor-like class for a method that happens to have the same signature, you'll have to have two of these adaptors.

Now, my Perl example was in fact an adaptor, and C++ requires the same (see my take on it), but the method they bind to doesn't need any previous arrangement. For example, a use of my callback:

void foo(int a, int b)
{
    ...
}
 
class Bar
{
    ....
    virtual void do_bar(int x, int y);
};
 
typedef WvCallback<void, int, int> MyCallback;
 
int main()
{
    MyCallback callback;
    Bar* bar = new Bar;
 
    callback = foo;
    callback = MyCallback(bar, &Bar::do_bar)
}

Notice how anything that can take two ints and returns nothing can be passed, without any specific syntax. With a normal function, WvCallback behaved like a normal function pointer. In my example, the method was virtual, but it doesn't need to be, it literally works with anything you can stick parentheses after (functors, real functions, methods of any type).

Now, I'm pretty disappointed, because if C++ was any better, I wouldn't need the adapter object at all, I would just have a resolved function pointer and a this pointer, and I'd be happy as a clam, tail-calling into my callback in the most optimal way possible, even if you'd look at the assembly output.

So C++ isn't exactly my dream language either (witness the horrible emulation of variable template parameters I had to do, beware, it can cause eyeballs to bleed!), but can be bullied into something usable. Java isn't my dream language and won't let itself be bullied into making some sense.

Higher Order Operational Techniques in Semantics - HOOTS, posted 21 Mar 2004 at 22:54 UTC by badvogato » (Master)

"Most object-oriented or functional languages are higher order languages, i.e., ones in which the means of manipulation, e.g. object or function, can itself be manipulated." Higher order languages present difficult challenges for any style of semantics, be it axiomatic, denotational, or operational. The first two have much in common with semantic studies in mathematical logic and linguistic, the third, operational semantic, is distinctive of computer science. In an axiomatic semantics, meaning is defined indirectly via the axioms and rules of some logic of program properties. In a denotional semantics, the meaning of programs is defined abstractly using elements of some suitable mathematical structure. In an operational semantics, the meaning of programs is defined in terms of their behaviour, for example the steps of computation they can take during program execution. Nevertheless, operational semantics is often regarded as the 'poor relation' of the other two approaches. The reason for this has to do with the fact that it tends to be quite concrete, with important general properties of a language's various features sometimes obscured by the low-level description of how program execution takes place. Thus at its worst, an operational specification may come perilously close to committing the sin of 'definition by implementation' (which is a sin because such a definition is not particularly useful). Such a criticism was certainly pertinent in the early days of the subject and was a stimulus to the development of the more mathematically principled methods of denotional and axiomatic semantics. To quote Plotkin, the early attempts at semantic definitions based on abstract machines had 'a tendency to pull the syntax to pieces or at any rate to wander around the syntax creating various complex symbolic structures which do not seem particularly forced by the demands of the language itself."

These days, the challenge of higher order languages for operational semantics is somewhat different. In contrast to the axiomatic and denotational approaches, it is relatively easy to give inductively defined, structural operational semantics for all of the language features mentioned above. What is not easy is to develop the mathematical properties and applications of such operational definitions. And i believe computer science research in this area should look more intensively at applying HOOTS into how to solve the problem of computational 'go' at all fronts: axiomatic, denotional and operational

On a &quobuzzword&quo, posted 22 Mar 2004 at 03:08 UTC by Pseudonym » (Journeyer)

In 1974, David Parnas wrote a paper entitled On a "Buzzword": Hierarchical Structure. I'm afraid I can't find an online copy. However, it contains this choice quote:

It is so common to hear phrases such as "high level language", "low level language", and "linguistic level" that it is necessary to comment on the relationship between the implied language hierarchy and the hierarchies discussed in the earlier sections of this paper. It would be nice if, for example, the higher level languages were the languages of the higher level "abstract machines" in the program hierarchy. Unfortunately, this author can find no such relation and cannot define the hierarchy that is implied in the use of those phrases. In moments of skepticism one might suggest that the relation is "less efficient than" or "has a bigger grammar than" or "has a bigger compiler than", however, none of those phrases suggests an ordering, which is completely consistent with the use of the term. It would be nice, if the next person to use the phrase "higher level language" in a paper would define the hierarchy to which he refers.

Interestingly, 20 years later, one point no longer holds true. Most "higher level languages" are implemented in the abstract machine provided by the C language. (This is partly because many modern operating systems, especially the Unix-like ones, are basically implementations of C.) In that sense, all languages built on top of C can reasonably be called "higher level" than C.

Re: On a `buzzword', posted 22 Mar 2004 at 03:16 UTC by tk » (Observer)

Pseudonym: Does that mean that machine code is higher-level than C, because a machine code emulator written in C implements it?

Re: Is machine code higher-level than C?, posted 22 Mar 2004 at 04:04 UTC by Pseudonym » (Journeyer)

Tk, the "level" that I suggest is not "any level at which it is possible to implement X". What I suggest is "the lowest level at which it makes sense to implement X", or perhaps "the level at which X is customarily implemented". This is, at best, a partial order, so it should be possible to find two languages which are incomparable in terms of "level", but there should always be a least upper bound. (The "bottom" element is probably somewhere deep inside quantum field theory.)

So in this case, Python (say) is almost always implemented in terms of C, which is almost always implemented in terms of assembly language, which is almost always implemented in terms of machine code, which is almost always implemented in terms of "hardware". ("Hardware" here is a black box which contains its own "levels" which depend on the specifics of how the hardware is designed and constructed.)

As a side note (and this has nothing to do with tk, it's about geeks in general, including myself), most of the world's definitions are not specified precisely. For example: The kinds of tests that courts produce, such as those used to determine what is "fair use", are rarely based on binary yes/no tests. It's more commonly a set of criteria each of which weights the decision in one of two directions, and even then, human judgement still has to come into play should the decision end up on the "borderline". This is one of those situations. Don't look for binary decisions where there are none to be found.

Re: Is machine code higher-level than C?, posted 22 Mar 2004 at 04:23 UTC by tk » (Observer)

Pseudonym: But this still raises further questions. Is Brainf*** higher-level than C? Is Brainf*** higher-level than assembly language? Which is at a higher level, C or flex? ......

I agree, "high-level" has always been a vague term. Personally I don't object to people using it, except I get really pissed off when some borkheads use the term as some sort of hard criterion for choosing a language, or as an excuse to lambast other people's choice of language.

Re: Is machine code higher-level than C?, posted 22 Mar 2004 at 04:41 UTC by Pseudonym » (Journeyer)

tk: As I noted, human judgement has to come into play when there are things on the borderline. Brainf*** is a good example, partly because it's a highly contrived one. Let's face it, Brainf*** is just plain contrived.

Flex vs C is a less contrived example, and it has an easy answer. Flex is implemented in terms of C. It compiles to C. Nobody has yet produced a C implementation which compiles to flex. Therefore flex is higher level than C.

Suddenly tempted, posted 22 Mar 2004 at 09:08 UTC by Omnifarious » (Journeyer)

For some bizarre reason, I am now suddenly tempted to implement a Brainf*** backend to gcc. A maybe use Xerblin's C to Xerblin translator, then a Xerblin to Branf*** translator. :-)

By their bootstraps, posted 22 Mar 2004 at 13:28 UTC by abraham » (Master)

Compilers for most languages are implemented in themselves. C is almost always implemented in C. Common Lisp compilers tend to be written in Common Lisp. GNU Ada is written in GNU Ada. CFRONT was written in C++. BM's Eiffel is, nowadays, written in Eiffel. It makes bootstrapping more difficult, but there are obvious advantages in having the people who write the compiler program in the same language.

A few languages aren't well suited for implementing compilers, COBOL and older version of FORTRAN spring to mind.

And for some compiler suites, it makes it makes everything easier when sharing implementation language. Many GCC languages are written in C for that reason among others.

For interpreters, the case is different. If there is no compiler, if the interpreter came first, or if the interpreter for some reason should be independent of the compiler, another language may be used.

..., posted 22 Mar 2004 at 16:35 UTC by trance9 » (Master)

Omnifarious: The good uses of overloading are all things the language designers do when they implement the STL, etc., not things that belong in ordinary code. Also it's pure sugar; there's no design-level difference or even compiler difference between v[i] and v.get(i), so it's not making C++ a higher level language. Contrast with templates, which do go beyond being just sugar, and give you the ability to express new kinds of overall designs for your applications.

pphaneuf: Yes, Java is a strongly typed language, and PERL isn't. But that has nothing to do with closures. You could have specified any signature you liked in my example, with any number of arguments, but yes the caller/callee have to agree on a signature in a strongly typed language.

signature, not parent class!, posted 22 Mar 2004 at 19:58 UTC by pphaneuf » (Journeyer)

trance9: the problem is that you can't agree just on a signature, you have to agree on a parent class. But I have to give extra bonus points for anonymous classes, I wish C++ had those.

C++ _could_ have anonymous classes, posted 22 Mar 2004 at 21:30 UTC by Omnifarious » (Journeyer)

C++ could have anonymous classes, but their semantics would have to be odd. They would have to act, from a scope standpoint, like they were declared in the scope the function they were in was declared in. For member functions, that would be interestingly dicey and weird.

In order to have Java-like anonymous classes with their limited closure semantics, you'd have to implement garbage collection, or else the memory management issues would be too hairy. And no jumping on me saying that C++ memory management is already hopelessly hairy. If you adopt a certain mindset and programming style, it's actually pretty easy to manage memory in most instances. Bare pointers should generally be a rarity in C++ member variables and function arguments.

inner classes, posted 22 Mar 2004 at 22:01 UTC by trance9 » (Master)

pphaneuf, you do not have to agree on a parent class, you only need to agree on an interface, as in my example, "Runnable" is just an interface.

Re: By their bootstraps, posted 22 Mar 2004 at 23:41 UTC by Pseudonym » (Journeyer)

abraham: Yes, compilers for many languages are implemented in themselves. There are huge benefits to doing this, not the least of which is that you automatically have a big test case for your compiler.

That definition is reasonable for an "interpreted" system, but it's not reasonable for a "compiled" system. A better definition for compiled systems is to look at what a language is compiled to. Unless you're doing some kind of weird bootstrapping, there's no point in translating language X into language X.

C++ and bare pointers, posted 22 Mar 2004 at 23:52 UTC by Pseudonym » (Journeyer)

Bare pointers should generally be a rarity in C++ member variables and function arguments.

I dissent in part.

Bare pointers play a very important role in modern C++ because they document a useful property, namely, that anyone who holds a bare pointer to an object is not expected to manage that object's lifetime. A function like foo(SomeClass* p_sc) is making an explicit statement to the caller that it will not delete p_sc, it will not store the pointer anywhere which persists after control returns from foo and so on. In many respects, this is like const, only it's not checked by the compiler.

Similarly, bare pointer members are useful for the situation where there is a guarantee that any instance of the class will never survive longer than the object pointed to. This guarantee happens quite often in practice, for example, for classes which are only ever instanced on the stack and never on the heap.

bare pointers, posted 23 Mar 2004 at 04:34 UTC by trance9 » (Master)

Bare pointers can be fun sometimes.

Meaning of "high-level", posted 23 Mar 2004 at 14:19 UTC by dan » (Master)

Three and a half billion replies ago, trance9 wrote

So I would say ease of working with abstraction would be the key, and the the criteria are:

  • How easy is it to understand an abstraction?
  • How easy is it to debug a problem with an abstraction?
  • How easy is it to use and re-use an abstraction?

The criterion you've missed which (for me, at least) is more important than all of the above is: "how easy is it to /create/ an abstraction?"

Abstraction, posted 23 Mar 2004 at 16:28 UTC by ncm » (Master)

More to the point, is it even possible to create said abstraction without first writing an interpreter for some other language?

Re: Abstraction, posted 23 Mar 2004 at 17:22 UTC by tk » (Observer)

On a related tangent: APIs Considered Harmful.

/create/ an abstraction, posted 23 Mar 2004 at 17:39 UTC by badvogato » (Master)

what is it that people want to /create/ an abstraction so that artificial processing is greatly enhanced without any benefit of enhancing the aesthetic feelings in the counter parts of human intelligence and human interactions?

abstraction or distraction?, posted 23 Mar 2004 at 21:08 UTC by ncm » (Master)

badvogato: Are you offering to be our target machine? Shall we code our algorithms to execute in your noggin (or other body part)?

Apropos that, "They're Made out of Meat".

i've been executed too many time..., posted 23 Mar 2004 at 22:10 UTC by badvogato » (Master)

as the saying goes, God is in the details. 'we are both doing Lord's work. You in your way, i in His.' And ncm think i have a body. That is remarkable. And I confess that my brain cells have limit functionality. This is what appears under my nose today:

I said that I wasn't clever. I was just noticing how things were, and that wasn't clever. That was just being observant. Being clever was when you looked at how things were and used the evidence to work out something new. Like the universe expanding, or who committed a murder. Or if you see someone's name and you give each letter a value from 1 to 26 (a = 1, b = 2, etc.) and you add the numbers up in your head and you find that it makes a prime number, like Jesus Christ (151), or Scooby-Doo (113), or Sherlock Holmes (163), or Doctor Watson (167).
Whoever bother themselves to actually add those numbers must be genius. But whoever bother themselves to actually add those numbers without ever being taught about the life of Jesus Christ, what should we call them?

Bother, posted 23 Mar 2004 at 23:42 UTC by ncm » (Master)

I believe the technical term, within Christendom, is "heathen". But why should those beyond its borders trouble to name themselves, or ourselves, in reference to it? We are as we are, and Christendom is as it is.

That does not answer the question, though. Totting up figures and identifying smallish primes is not an activity, particularly, of a genius, but of a savant, an autist, an obsessive-compulsive. What can such cipherings tell us of Truth? And what of creosote in tubes, shipped in a plain brown wrapper fnord?

distraction, posted 24 Mar 2004 at 01:42 UTC by badvogato » (Master)

i beg your pardon to be as much of a distraction as you can manage to abstract all other reader's response to my posting. Amen.

Re: i've been executed too many time..., posted 24 Mar 2004 at 17:14 UTC by tk » (Observer)

Clearly, Jesus Christ was murdered by Scooby-Doo.

At least this is more funny than creating abstractions to do HTTP.

who murdered ME!, posted 24 Mar 2004 at 17:42 UTC by badvogato » (Master)

and whoever murdered badvogato is also the prime suspect of causing fainting of my sister here whenever tk enters the room. "Back off, man. I'm a scientist." Anyway, advogato faints from time to time when room is full or when moon is full. agreed?

Tricksy C++ hacks, posted 5 Apr 2004 at 23:05 UTC by emk » (Master)

pphaneuf: The returned function pointer can be used anywhere where a pointer to a function with the same signature as the method it will call is needed. Do that in Java (or even C++, unfortunately).

It's not quite so nice in C++, but you can get close using boost.

using boost;
// Bind a three-argument member function, specifying the
// first argument and leaving the others unbound.
bind(mem_fn(&Class::DoSomething), the_obj, "first arg", _1, _2);

The mem_fn wraps up the member function, and bind fills in various subexpressions. _1 and _2 are placeholders for lambda arguments. As with most things in C++, it has a lot of warts. As with most bits of boost, I can live with it.

You could actually write something even closer to your example, but it would take a depressing amount of template hackery because of limitations in bind1st. Yeah, I'd rather program in something a little better than C++, but things have gotten much better with the latest major compilers and the various free class libraries. C++ can actually be used as a very high-level language these days.

Re: Tricksy C++ hacks, posted 7 Apr 2004 at 13:34 UTC by pphaneuf » (Journeyer)

Yes, we have a WvBoundCallback functor that takes a WvCallback, allowing you to set the first parameter (like bind1st). It also has freeze and thaw methods that allow you to save a set of parameter values so you can defer the call (useful for event queueing).

Like I said and like we both showed, you can at least bully C++ into behaving like you want, but it'd sure be nice to have better delegate support or tail-calls (so I could implement better delegate support more efficiently).

The Great Computer Language Shootout, posted 9 Apr 2004 at 03:07 UTC by badvogato » (Master)

the shootout is unfinished. Today is the first day that i encountered yet another web programming language Moto

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!

X
Share this page