The Artima Developer Community
Sponsored Link

Weblogs Forum
Designing a Language for Library Developers

47 replies on 4 pages. Most recent reply: Oct 17, 2005 1:28 PM by Max Lybbert

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 47 replies on 4 pages [ « | 1 2 3 4 | » ]
Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Designing a Language for Library Developers Posted: Oct 12, 2005 11:06 PM
Reply to this message Reply
Advertisement
> But aren't you falling into the trap that C++ did? The
> first C++ “compiler” was nothing more than a preprocessor
> that converted the code into C, which was then converted
> into assembly, then assembled and linked. So now you are
> writing a “compiler” that is nothing more than a
> preprocessor which converts Heron into C++.

You are assuming that I am supporting backwards compatibility as C++/CFront did (which I am not), and that the language design is going to have a clean mapping to C++ (which for the most part it doesn't).

> I suspect the reason you are targeting C++ is that you
> don't want to write a full compiler, just a translator and
> leave the heavy lifting to something like g++. But I
> think that in the end may limit the usefulness of Heron
> (how much as the baggage of C hurt C++?).

I understand your concern, but I am doing a *lot* of heavy lifting in the Heron translator. If I was doing a simple one-to-one mapping you would be very much correct.

> But as I play around with langauge design (which is a
> hobby of mine since college) all my lanauges seem to
> evolve (or devolve, take your pick) to either Lisp or
> Forth, which, when you think about it, are two sides of
> the same coin (only Lisp and Forth don't really have the
> sheer number of libraries like Perl does).

They are definitely very elegant languages, and worthy of emulation.

Kristian Dupont

Posts: 22
Nickname: chryler
Registered: Dec, 2003

Re: Designing a Language for Library Developers Posted: Oct 13, 2005 2:28 AM
Reply to this message Reply
I would hardly consider this a "trap" that C++ fell into.
C++ doesn't support closures or nested functions but this is by design, not because of the limitations the original compiler had. The reason why C++ has all of its c baggage is that Bjarne wanted C code to work together with C++.

Greg Jorgensen

Posts: 65
Nickname: gregjor
Registered: Feb, 2004

Re: Designing a Language for Library Developers Posted: Oct 13, 2005 9:32 AM
Reply to this message Reply
It's a good thing that Bjarne Stroustrup doesn't have a thin skin, because C++ sure gets trashed enough. Designing a new language and weathering the process of getting nit-picky opinionated programmers to use it must be hard on the ego.

Dr. Johnson said "You may scold a carpenter who has made you a bad table, though you cannot make a table. It is not your trade to make tables." Any C++ programmer can find things about C++ to criticize, but few can write something even half as useful as C++ themselves.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: The "trap" Posted: Oct 13, 2005 10:04 AM
Reply to this message Reply
/* But aren't you falling into the trap that C++ did? The first C++ “compiler” was nothing more than a preprocessor that converted the code into C, which was then converted into assembly, then assembled and linked.
*/

I'm not sure this is a trap. It's a common method of doing things (http://www.joelonsoftware.com/articles/FogBugzIII.html and http://home.in.tum.de/~baueran/thesis/ for instance). In fact, there's probably a reason that heron.standard was (until recently) called "HeronFront" (cf. cfront).

However, *if* I understand what you're referring to, I think Heron will avoid the quicksand. Stroustrup designed C++ in such a way that there was *always* a C way of doing things. For instance, a class could map to a struct, each method in a class would map to a standalone function that took the struct as the first argument (cf. name mangling), etc. But Stroustrup also made decisions so that there would often be an even more efficient way to do things (const variables can be put in any memory, for instance, but they *can* also be put in fast read-only memory for performance gains). This meant that C++ theoretically would be at least as fast as comparable C programs.

Unfortunately, because of the extra code to implement type checking, most early C++ compilers did things the slow, reliable, C way *after* doing extra work to make sure there were no unintentional typecasts. This meant that C++ programs were guaranteed to run no faster, and often slower, than comparable C programs.

HeronFront, on the other hand, can use C++ template metaprogramming to use any faster "Heron way" of doing things (something that would be pretty difficult if Heron code were compiled to C). For instance, Heron objects don't not have virtual method calls, so the C++ code generated is designed as a template pattern that guarantees there will be no virtual table implementation.

/* I'm not trying to be mean here, but to take just one thing from your list of features: closures. ... I can't see doing closures in C (and by extension C++) portably.
*/

Here are a couple of places to start: http://okmij.org/ftp/c++-digest/Functional-Cpp.html and http://people.debian.org/~aaronl/Usenix88-lexic.pdf (notice the date on that last one -- the C++ standard has made the job even easier).

/* Taking another feature—nested functions. I can see how to write a translator that can spit out C code, but with a few restrictions on function pointers.
*/

Here's where to look: http://www.cs.uiowa.edu/~jones/arch/notes/33call.html .

And, remember, even C programs are often linked to a runtime library (http://www.boost.org/more/separate_compilation.html#auto-link).

Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Re: Designing a Language for Library Developers Posted: Oct 13, 2005 10:49 AM
Reply to this message Reply
> It's a good thing that Bjarne Stroustrup doesn't have a
> thin skin, because C++ sure gets trashed enough. Designing
> a new language and weathering the process of getting
> nit-picky opinionated programmers to use it must be hard
> on the ego.
>
> Any C++ programmer can find
> things about C++ to criticize, but few can write something
> even half as useful as C++ themselves.

Having spent a fair amount of time around Bjarne, I have been very impressed with his diplomacy. Also true for Guido Van Rossum, who spends his time hip-deep in his community. But I've occasionally seen both of them lose their composure after being pecked to death by ducks once too often.

Designing a language for mainstream acceptance requires, I believe, much more than a technical understanding of things, but especially a sense of economics and of psychology. The irony is that, although we as programmers inhabit a digital world, there are very few binary questions. For example, checked exceptions seem brilliant on the chalkboard, but they may actually impact the productivity of programmers and cost more than they're worth, and at the same time become part of the background noise so you can't see the impact, and continue believing they are the best of all possible worlds.

One difference between my C++ experience and my Java experience is that, because I participated in the C++ committee, I saw the decisions being made, argued and justified. And indeed, a lot of it came back to "backwards compatibility with C," C++'s strength and the millstone around its neck. So I know why the decisions were made and I don't think the language could be less complex than it is, all things considered.

Java, on the other hand, has many misfeatures (some of which have been fixed over time) that came, probably, from rushing the thing out and having part of it designed by marketers, or at least marketing-minded people. And since the Sun crew is usually reluctant to admit mistakes, we are left to our own devices, sometimes years later figuring out by ourselves that someone just didn't know what they were doing when they put suspend(), resume(), stop() and destroy() into Java threading (of course, that was an obvious one. There are far more subtle "fixes" that slip through the radar, that just leave you with an uncomfortable feeling, but it's put forth like "we've always known what we're doing, we're infallable." We're now finding out that EJB1 and 2 really were the emperor's new clothes because of a complete ivory-tower misunderstanding of how that tool would be used (and I think the backlash from this will last for years). I think the approach to Java generics will, after the years it takes for everyone to finally figure them out, be understood to be a collection of design decisions made based on faulty assumptions, and the cost to programmers (and, eventually, the language) will be significantly greater than the short-term benefits gained by making these choices.

But with Java I can't always know what was a mistake and what was a well-thought-out decision until sometimes long after the fact, whereas with C++ I know, and have come to trust that, even if I don't understand something right away there is logic behind it. That gives me a fundamentally different feeling about the two languages. (And if it isn't obvious by now, Python is still my favorite out of all of these).

Again, language design is a really tough thing to do. It's really hard to be omniscient (although that would be the ideal for a language designer -- just do it and throw the thing out there), but once you open yourself up to everyone's opinions, you have to sort through all the half-baked or half-understood ideas, figure out what's really right, and end up making decisions as if you're omniscient anyway.

I applaud Christopher for trying, and for struggling along this path. But it's going to be a huge struggle, and I believe that a lot of the struggle will probably involve learning to become both a diplomat, and when enough of the information is in, a strong decision maker, like Stroustrup and van Rossum.

Sean Conner

Posts: 19
Nickname: spc476
Registered: Aug, 2005

Re: Designing a Language for Library Developers Posted: Oct 13, 2005 9:43 PM
Reply to this message Reply
It wasn't my intent to imply that Heron would be backwards compatible with C++. What I'm having trouble wrapping my mind around is how you are going to implement some of your features with C++ as your backend. As an example, let me give you some code in my own language (which I just made up) called Egret:


typedef double (*F)(double);

F[] makefs()
{
F list[];
double c;
size_t max;

F makef(double a,double b)
{
return lambda(double x) { return a * x + b * c; };
}

for ( max = random(0,100) ; max ; max--)
{
c = random(-1.0 , 1.0);
list.append(makef(random(-1.0,1.0),random(-1.0,1.0)));
}

return list;
}


I have no intention of being compatible with C++ (although it bears an uncanny resemblance to C/C++). I might even entertain the notion of converting this to C++. Now, what would this look like in C++? The function makefs() returns an array of functions that are generated during the call. Each function must capture the values of a, b and c (yup, quite a few closures there), and the pages that Max pointed to don't seem to quite do the trick (but I admit that I know very little about C++).

Now, about nested functions in C. That, I know how to do (in fact, as an undergrad, I helped a graduate student facing that very problem in her compiler class). But given the code:


sometype A(parameter a,paramter b)
{
sometype B(parameter c)
{
}
}


A() can certain take the address of B() and pass it to, say bsearch() or qsort(), but it cannot safely (i.e. in every case) return the address of B() to callers of A() (again, assuming we're converting this code to C).

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

What happens when you post to articles you didn't read completely Posted: Oct 14, 2005 7:10 AM
Reply to this message Reply
Aargh! I need to do more than skin some articles before I post:

/* I can however, see how I could do closures in Assembly on several different platforms
*/

To which I responded by pointing to an article that *proposes* an assembly code solution. But I can still salvage this. The MIT article (from Usenix '88) did include the following sentences (p. 6 - 7):

/* Changing the representation of a C++ function pointer to be two pointers large rather than one pointer is unacceptable. This would mean, for example, that a "function pointer" could not be assigned to a variable of type void* without losing information.

An alternative might be to introduce a new data type, "closure", that must be used to express references to functions and their environment if those functions are not defined at global level. Using implicit type conversions from function pointers to closures would allow us to mix function pointers could be used in place of closures. However, closures could not be passed to existing functions that expect function pointers. Furthermore, the language becomes unnecessarily cluttered by two data types for essentially the same concept. Clearly, neither of these alternatives is acceptable.
*/

Well, today they are both acceptable. "The C++ Programming Language" explains the "new data type" concept in section 22.4.7 ( compare with http://www.research.att.com/~bs/glossary.html#Gclosure). I won't go into the detail, but (changing the syntax pretty wildly in order to make the implemantation clearer) consider:

class closure { ... };
closure my_closure(*function_taking_three_args);
my_closure.arg_1(16);
my_closure.arg_2 ("some string");
my_closure.arg_3("third arg, and depending on implementation, my_closure can call itself now, or can wait 'till I say 'my_closure.call()'");

The "two-pointers in one" technique would involve smart pointers which (1) are more common today than 17 years ago, and (2) are extremely common in machine-generated code.

How would Heron know the second address to pass? That could be part of building the parse tree.

Now, regarding your code example -- you may consider looking at http://www.research.att.com/~bs/glossary.html#Gfunction-object for ideas.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Better link for function objects Posted: Oct 14, 2005 7:12 AM
Reply to this message Reply
http://www.research.att.com/~bs/bs_faq2.html#function-object

You'll find this link if you chase pointers in Stroustrup's glossary, but just in case ...

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

I may not have responded clearly on one ... Posted: Oct 14, 2005 7:19 AM
Reply to this message Reply
/* Now, about nested functions in C. That, I know how to do (in fact, as an undergrad, I helped a graduate student facing that very problem in her compiler class). But given the code:


sometype A(parameter a,paramter b)
{
sometype B(parameter c)
{
}
}


A() can certain take the address of B() and pass it to, say bsearch() or qsort(), but it cannot safely (i.e. in every case) return the address of B() to callers of A() (again, assuming we're converting this code to C).
*/

That makes the assumption that the source language's scoping rules are like C's, and that functions cannot hold data (compare with function objects, my two most recent posts). It also makes the assumption that the language can't put restrictions on what A can do with B's address. You may be interested that gcc permits nested functions in C code (http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html).

Sean Conner

Posts: 19
Nickname: spc476
Registered: Aug, 2005

Re: Designing a Language for Library Developers Posted: Oct 14, 2005 10:27 AM
Reply to this message Reply
/* Well, today they are both acceptable. "The C++ Programming Language" explains the "new data type" concept in section 22.4.7 */

Well, I never claimed to be a C++ expert, or even well versed in C++. The solution (to me) looks clunky, but seeing how the programmer will never see the generated C++ code (in much the same way that a programmer “never” sees the generated Assembly*) it's probably a moot point.

I've also heard (from a friend who is a C++ expert) that exceptions are quite clunky in their implementation (understandable, since there doesn't seem to be anyone that understands all the possible interactions between C++ “features” that were hacked in) and for some of his projects (embedded) he turns that feature off to get tighter code. Which has me wondering just how efficient the generated C++ (from Heron) would actually be.

/* You may be interested that gcc permits nested functions in C code */

Doesn't surprise me, and the limitations on functions pointers are the ones I had in mind (I've never used the GCC extenstions, having spent quite a bit of time writing C code for different platforms where I might not have GCC).

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: Designing a Language for Library Developers Posted: Oct 14, 2005 11:23 AM
Reply to this message Reply
/* I never claimed to be a C++ expert,
*/

I can understand that. I keep getting blindsided by Java ways of doing things.

/* The solution (to me) looks clunky,
*/

That's probably because I chose syntax that most programmers wouldn't use. It's possible to create function-like objects to work like:

class adder
{ const int x;

public:
adder(int to_add) : x(to_add) { };

int operator()(int y) { return x + y;};
}

adder add_7(7);
int i = 5;
i = add_7(i); // guess how big i will be now
...

x does not have to be const (you could use it to accumulate things, etc.). These are also more efficient to call than function pointers.

/* I've also heard (from a friend who is a C++ expert) that exceptions are quite clunky in their implementation ... and for some of his projects (embedded) he turns that feature off to get tighter code.
*/

That's common. If he's interested, a team came up with a very efficient method (http://netlab.ru.is/exception/LinuxCXX.shtml), but there's actually a standard for embedded C++ that doesn't use exceptions (http://www.caravan.net/ec2plus/). And it's well-known that exceptions (and RTTI, and virtual methods) require run-time support (i.e., they are likely inefficient and are not suitable for many cases).

/* Which has me wondering just how efficient the generated C++ (from Heron) would actually be.
*/

There's only one way to find out. However, the performance pitfalls in C++ are well-known and well-marked. The feature list for Heron was picked partly because efficient implementations exist and efficient code can easily be generated.

Gregor Zeitlinger

Posts: 108
Nickname: gregor
Registered: Aug, 2005

Re: Designing a Language for Library Developers Posted: Oct 16, 2005 8:48 AM
Reply to this message Reply
I don't know wheather it was brought up before, but API compatability is also an issue that library developers have to consider, while application developers can ususally ignore this issue.

This includes
1) identifying API (or published) elements and
2) keeping the API compatible when changing it

1) Therefore, I am wondering if there is any merit in supporting "published" visibility in Heron. Published elements are classes or interfaces that are meant to be used by clients.
See Martin Fowler's definition: http://www.martinfowler.com/ieeeSoftware/published.pdf

The Eclipse project (which is bascially a set of libraries), for example, uses a convention to identify published elements:
The package statement must not contain "internal".
See http://eclipse.org/eclipse/development/java-api-evolution.html

2) The previous link also describes how an API may be changed without breaking compatability.
It's an excellent article and maybe one of the most important aspects when designing a library.

Gregor Zeitlinger

Posts: 108
Nickname: gregor
Registered: Aug, 2005

Re: Designing a Language for Library Developers Posted: Oct 16, 2005 9:47 AM
Reply to this message Reply
> The Eiffel folks even point to
> the fact that having the test in front of the programmer
> (instead of in a separate file as in Boost.Test or JUnit)
> can help remind him of what, exactly, the function
> promises to do and can avoid expensive errors
I was just wondering:
Is it possible to use pre- and postconditions and class invariants to generate unit tests automatically in the following way:
class A { public int b(int c); }
1) use the field invariants of A and the preconditions of b to initialize A
2) use the preconditions of b to initialize c
3) the unit test fails if the postconditions of b are not met.

If c is not a primitive type, the invariants of c could be used to create a mock version of c.

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Designing a Language for Library Developers Posted: Oct 16, 2005 10:38 AM
Reply to this message Reply
> I was just wondering:
> Is it possible to use pre- and postconditions and class
> invariants to generate unit tests automatically in the
> following way:
> class A { public int b(int c); }
> 1) use the field invariants of A and the preconditions of
> b to initialize A
> 2) use the preconditions of b to initialize c
> 3) the unit test fails if the postconditions of b are not
> met.
>
> If c is not a primitive type, the invariants of c could be
> used to create a mock version of c.

IIUYC what you are describing is Aspect Oriented Programming rather than Design by Contract. AOP is more general than DbC, and can be used to implement contract verification, or to implement inlined unit testing as you suggest, which incidentally I think is an excellent idea.

Gregor Zeitlinger

Posts: 108
Nickname: gregor
Registered: Aug, 2005

Re: Designing a Language for Library Developers Posted: Oct 16, 2005 12:23 PM
Reply to this message Reply
> AOP .. can be used to implement contract verification
is there another way to verify contracts?
Is formal proof a practical alternative?

> or to implement inlined unit testing as you
> suggest, which incidentally I think is an excellent idea.
hmm... maybe it's even possible to add this to JUnit via XDoclet (Java 1.4)/Annotations (Java 5).

BTW: I was wondering why you want to include type inference in Heron. I think it's a counterproductive feature:
1) There is nothing that you cannot do without (unlike closures, for example) - am I missing something?
2) It makes code harder to understand, just like dynamic typing.

Flat View: This topic has 47 replies on 4 pages [ « | 1  2  3  4 | » ]
Topic: Implicit Casting, Good or Evil? Previous Topic   Next Topic Topic: All Your Eyes Are Belong To Us


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2017 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us