Article Discussion
Elegance and Other Design Ideals
Summary: Bjarne Stroustrup talks with Bill Venners about many aspects of software design, including growing small applications into larger ones, avoiding class distinctions between designers and users, the dangers of premature generalization, and the essence of elegance.
36 posts on 3 pages.      
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: March 16, 2004 9:54 AM by
Daniel
Posts: 5 / Nickname: dyokomiso / Registered: September 17, 2002 2:50 PM
Re: Elegance and Other Design Ideals
February 26, 2004 3:25 PM      
[snip]

> > If you have an online pointer to the paper in question,
> I
> > would be interested in seeing it.
>
> OOPSLA 2003 Garcia, et al: A comparative study of language
> support for generic programming. pp 115-134.
>
> I don't know if it's online.
>

It seems to be available here:

http://www.osl.iu.edu/publications/pubs/2003/comparing_generic_programming03.pdf

Google cache for this paper:

http://www.google.com/search?q=cache:CNwEcvMa0lcJ:www.osl.iu.edu/publications/pubs/2003/comparing_generic_programming03.pdf+%22+A+comparative+study+of+language+support+for+generic+programming%22&hl=en&ie=UTF-8

The paper is in my read list so I can't comment on it. But after skimming through the examples and the conclusions it seems that the authors have some bias toward C++, as they try use the C++ solution to the problem to every other language.

IMHO it would be better to present a problem to different groups using different languages and see they implementing it. This approach was used in "Haskell vs. Ada vs. C++ vs. Awk vs. ... An Experiment in Software Prototyping Productivity" (available at http://citeseer.nj.nec.com/hudak94haskell.html). In this paper the Naval Surface Warfare Center (NSWC) required a prototype for a Geometric Region Server from ten different groups (contractor and academics). The resulting programs and development metrics were reviewed by a committee chosen by the Navy. The resukts are shown below:


Language LOC L. of doc. Dev. time (hours)
(1) Haskell 85 465 10
(2) Ada 767 714 23
(3) Ada9X 800 200 28
(4) C++ 1105 130 –
(5) Awk/Nawk 250 150 –
(6) Rapide 157 0 54
(7) Griffin 251 0 34
(8) Proteus 293 79 26
(9) Relational Lisp 274 12 3
(10) Haskell 156 112 8


An interesting fact is that the tenth program was written by a newly hired college graduate with no experience in Haskell, other than a previous ten-day self study of the Haskell Report.

We could also use the sources for each ICFP available, as several different languages are used to solve the same problem, each using a different design.

There's also a relevant paper called "DSL Implementation in MetaOCaml, Template Haskell, and C++", comparing meta-programming techniques in the three languages.

http://www.cs.rice.edu/~taha/publications/preprints/2003-12-01.pdf


> The old short study, which I do not have a reference to,
> ws by Tom Love (of Stepstone fame).
>
> -- Bjarne Stroustrup: http://www.research.att.com/~bs

Best regards,
Daniel Yokomizo.
Bjarne
Posts: 48 / Nickname: bjarne / Registered: October 17, 2003 3:32 AM
Re: Elegance and Other Design Ideals
February 26, 2004 3:27 PM      
>
> When Bjarne made the claim in the interview, I imagined
> him to be talking more about algorithms than program
> infrastructure. Bjarne, you can correct me if I was wrong
> about that. So for example, looking at what code -- the
> while loops and for loops and data structures -- it would
> take to implement an algorithm that does something
> specific.

If I remember correctly, I was thinking of programs written with adequate support from modern libraries. One related thing that I sometimes mention is that "In the language itself, just about anything is hard; with a suitable library, just about anything becomes easy - that's true for any language". Obviously, the distinction between "the language" and "a library" is sharper in some languages than in others.

> I can't remember who said this and in what context, but
> somewhere I heard someone talking about how it is ironic
> that the bigger the language, the smaller the code in that
> language. In other words, the more features a language has
> in it, the more ways a programmer can say what needs to be
> said -- including possibly a very succinct way -- so and
> the smaller the programmer can make the code. I thought it
> was Matz who said this about Ruby in his interview, but I
> can't find it. Regardless, C++ has a lot of features, and
> perhaps that helps make code shorter.

There's something to that. For example, a C++ class offers support for both value types and object types. If you think all types should be object types (or conversely that all types should be value types), you'll find C++'s support overelaborate. However if you write a program that uses both kinds, say a complex number type and a graphics hierarchy, the support in C++ will favor users compared to users of a language that supports only the one or the other. Obviously, my opinion is that most programs can benefit from both kinds of types.

> After one of Bjarne's talks at the JAOO conference where
> we did the interview, someone in the audience asked Bjarne
> about readability. And Bjarne's answer was that many
> people confuse readability with familiarity.

I think that's a separate issue. I think "shorter" is a fairly objective notion.

> Languages that enable more
> terse code probably also assume the readers of the code
> are going to have spent more effort becoming familiar with
> all the various aspects of the language.

Maybe, but complex z2 = z2*4+z4; is readable without any training (in programming) - even if the code implementing the complex library is not.

> I'm curious, Bjarne, if you were talking about C++
> compared to scripting languages like Ruby and Python and
> Perl, or just C++ compared to systems languages like Java
> and C# and Eiffel. And if it is more about comparing just
> the algorithms versus an entire application. Because my
> experience is that at the application level, Java was less
> verbose than C++, and Python is less verbose than Java.
> Although in Python I tend to write in a structured design
> style, not an OO style, so it is kind of an apples to
> oranges comparison. Whereas I have built the same kind of
> OO sytems in Java that I used to do in C++. That said, I
> was programming in C++ long before the STL, so I was not
> using a modern C++ style.

I was thinking about languages such as C, C++, Java, and C#. The OOPSLA paper that I referred to elsewhere considered ML, Haskell, C++, etc. and C# and java extended with generics. The old OOPSLA experiment included languages that were popular 10 years ago, such as Smalltalk, Objective C and C++.

I did not think of scripting languages as such. They have an inherent advantage from requiring less "boiler plate", though C++ comes out pretty well give the STL, a regular expression library (e.g. see boost).

I did a course on distributed computing using Java, C#, and C++. I found C++ on average shorter on the algorithmic and data representation parts, but - as for all single person comparisons - that could simply have been my greater experience with C++.

-- Bjarne Stroustrup; http://www.research.att.com/~bs
indranil
Posts: 4 / Nickname: indranilb / Registered: February 25, 2004 11:41 PM
Re: Elegance and Other Design Ideals
February 26, 2004 3:32 PM      
> >Not really. The language doesnt require you to implement
> those methods, the compiler will generate default versions
> of these methods.
>
> And 90% of the time does it badly.

Not really. Its usually fine. As I said the rule is if you find that you need to write any one of copy constructor, assignment operator or destructor then you will almost certainly need to write the other two. This happens quite often , but considerably less than 90% of the time.

You certainly wouldnt be immune from this in Java for example. If you needed anything more than the default shallow copying of references, then you have to provide a clone() method. If your class was responsible for managing a resource then you'd provide a dispose() or close() method.

Not to mention the fact if you have to override equals() you must remember to override hashCode(). Dont forget to call super() in your constructor. And if you dont override toString() you really arent a professional.

I wont even begin my rants about endless casting to get things in and out of collections or ever growing exception specifications or being forced to implement an entire Listener interface when I just want to override one method or repeating the same clean up code in every finally block in my program.
Bjarne
Posts: 48 / Nickname: bjarne / Registered: October 17, 2003 3:32 AM
Re: Elegance and Other Design Ideals
February 26, 2004 4:00 PM      
>> >
> > OOPSLA 2003 Garcia, et al: A comparative study of
> language
> > support for generic programming. pp 115-134.
> >
> > I don't know if it's online.
> >
>
> It seems to be available here:
>
> http://www.osl.iu.edu/publications/pubs/2003/comparing_gene
> ric_programming03.pdf

Thanks

>
> The paper is in my read list so I can't comment on it. But
> after skimming through the examples and the conclusions it
> seems that the authors have some bias toward C++, as they
> try use the C++ solution to the problem to every other
> language.

Fair language comparisons are very hard - that's why I don't do them - but clearly authors and the OOPSLA program committee didn't think the paper was sloppy.

> IMHO it would be better to present a problem to different
> groups using different languages and see they implementing
> it.> ...
>
> An interesting fact is that the tenth program was written
> by a newly hired college graduate with no experience in
> Haskell, other than a previous ten-day self study of the
> Haskell Report.

It is nice to see someone trying to get experimental data. It's very hard to consider all factors, though.

> We could also use the sources for each ICFP available, as
> several different languages are used to solve the same
> problem, each using a different design.
>

That reminds me: From ICFP Programming Contest 2003 rules: "The contest offers direct, head-to-head comparison of language technology and programming skill. We have a range of prizes for the winners: cash awards, books, invitations to the conference for students, and, of course, unlimited bragging rights. The prizes will be awarded at ICFP 2003 in Uppsala this August."

The results are here:

http://www.dtek.chalmers.se/groups/icfpcontest/results.html


-- Bjarne Stroustrup: http://www.research.att.com/~bs
Tor
Posts: 3 / Nickname: ext / Registered: July 10, 2003 9:32 PM
Re: Elegance and Other Design Ideals
February 26, 2004 4:12 PM      
The paper on generics is available at http://www.osl.iu.edu/publications/pubs/2003/comparing_generic_programming03.pdf and the code is available here http://www.osl.iu.edu/research/comparing/ . I would be very interested in seeing a Smalltalk version of this library which is more compact and elegant than the BGL.
Steven
Posts: 1 / Nickname: pkdick / Registered: February 26, 2004 8:07 AM
Re: Abstraction and Efficiency
February 26, 2004 6:56 PM      
Hi,

first I apologize for commenting on the "Abstraction and Efficiency" part of the article series in the "Elegance and Other Design Ideals" thread, but this discussion seems to be the one that is currently alive, and I discovered www.artima.com just today.

>Abstraction is a mechanism by which we understand things. Expressing a solution in terms of math, for instance, means we really did understand the problem.
>... If somebody has a theory, such as a theory for matrix manipulation, you can just work at the level of those concepts and your code will become shorter, clearer, and more likely to be correct.
> ... The only code faster than the fastest code is no code. By abstracting to matrix manipulation operations, you give the compiler enough type information to enable it to eliminate many operations. If you were writing the code at the level of arrays, you would not eliminate those operations unless you were smarter than just about everybody.

It is exciting to read this: I am in the field of interactive theorem proving and the above thoughts about programming pretty much reflect the feeling that you get when doing theorem proving on the computer (and probably everywhere else in mathematics): if you find the right abstraction level for a theorem, then most of the time it becomes much simpler to supply a proof for that theorem (and to formulate it right, in the first place). So that reinforces my growing belief that theorem proving and programming are very very similar.

Concerning the efficiency of "abstract" code: Does anybody know about a programming language that accepts hints from the programmer at the chosen abstraction level (or failed attempts at such a language)? For example, when I have a class representing an equation, and I have an operation SYM that for a specific equation A=B returns the new equation B=A, then obviously SYM(SYM(x)) is just x, and I would like the compiler to take care of this. Of course I could to this myself in the source code, but if this constellation occurrs after inlining, then the only one who can do this is the compiler.

It would be hard to imagine that in C++, because there should be somehow a way to convince the compiler that the transformation is allowed.

Any comments?
Bill
Posts: 409 / Nickname: bv / Registered: January 17, 2002 4:28 PM
Re: Elegance and Other Design Ideals
February 26, 2004 11:20 PM      
> "Although in Python I tend to write in a structured
> design style, not an OO style"

> Now you are making me curious ;-)
> Why is it that you tend to program in a structured style
> with Python?

It's really just a matter of size for the most part, probably. For the kind of tasks I use Python for, objects seem like overkill. For example, the script I use to do redirects looks like this:


import sys,os

queryString = os.environ.get("QUERY_STRING")
i = queryString.find('url=')
url = queryString[i + 4:]
print "Location: " + url + "\n\n"


No need to make a class here. The most recent Python script I put into production parses an Apache log file and imports data into a database table. It's probably 400 lines of code, but once again objects seemed like overkill. I just have a main method that loops through each line and calls one of three or four other methods depending upon which regular expression matched, and those methods call a handful of other helper methods to do specific tasks the calling methods have in common. That's just a functional decomposition of the problem, which is what I was referring to as "structured design."

But on the other hand, I do feel that Python, because it doesn't force me to put every method inside a class as Java does, doesn't drive me in the object-oriented direction. Java tends to push me rather firmly towards one kind of object-oriented design, which is a kind I feel is a very natural fit for building larger systems. The other installments of this interview with Bjarne Stroustrup, he talks about Java's object-oriented single-mindedness:

http://www.artima.com/intv/goldilocks2.html

He also talks about multiple programming styles with C++:

http://www.artima.com/intv/modern2.html
Bill
Posts: 409 / Nickname: bv / Registered: January 17, 2002 4:28 PM
Re: Elegance and Other Design Ideals
February 26, 2004 11:57 PM      
> I did a course on distributed computing using Java, C#,
> and C++. I found C++ on average shorter on the algorithmic
> and data representation parts, but - as for all single
> person comparisons - that could simply have been my
> greater experience with C++.
>
This gets to the other idea I was thinking about during this exchange: the main point to take away from Bjarne's answer about elegance isn't the extent to which C++ may help you make code shorter, but that in whatever language you happen to be working, brevity is a good thing. Programming is writing in the sense that people must read your code. One of the main tenets of good writing is to avoid having lots and lots of useless words tacked on when just a few will do, including words in clauses that really just say the same thing as something that was already said earlier in the sentence, and what's worse is run-on sentences like this one that seem to never end, which become very tedious to try to read, and that's the same as code that goes on and on to say something hat could be said much more simply. As Strunk and White says in The Elements of Style:

Vigorous writing is concise.
Todd
Posts: 27 / Nickname: tblanchard / Registered: May 11, 2003 10:11 AM
Re: Elegance and Other Design Ideals
February 27, 2004 7:55 AM      
You certainly wouldnt be immune from this in Java for example. If you needed anything more than the default shallow copying of references, then you have to provide a clone() method. If your class was responsible for managing a resource then you'd provide a dispose() or close() method.

The vast majority of the need for writing copy ctors and op= involves sorting out ownership. In a GC system like Java, this problem vanishes. C++ Example:

class Foo { Something* _c; public: Foo(Something* c) : _c(c){} ~Foo() { delete _c; }}

Inadvertent copying of Foo (inadvertent copying in C++ happens a *lot*) will result in a double free.

You can fix this using a reference counting pointer - but that typically requires additional support in the class you are counting and if its not your class you're stuck.
Todd
Posts: 27 / Nickname: tblanchard / Registered: May 11, 2003 10:11 AM
Re: Elegance and Other Design Ideals
February 27, 2004 9:02 AM      
>I was thinking about languages such as C, C++, Java, and C#.

Oh, well, those are all essentially the same language with subtly different runtime models.

Except C++ has this ADT/OO dual nature.

C++ as an OO language (objects on the heap) is probably the weakest and most error prone OO language in existence.

But the ADT nature - (the stuff you do with custom data types/generics that are typically allocated on the stack) is rather unique and I think probably C++'s sweet spot. I think it makes it particularly good for efficient implementation of algorithms.

Right tool for the job and all that.
Merriodoc
Posts: 14 / Nickname: brandybuck / Registered: March 24, 2003 6:00 AM
Re: Elegance and Other Design Ideals
February 27, 2004 10:33 AM      
> You certainly wouldnt be immune from this in Java for
> example. If you needed anything more than the default
> shallow copying of references, then you have to provide a
> clone() method. If your class was responsible for managing
> a resource then you'd provide a dispose() or close()
> method.

>
> The vast majority of the need for writing copy ctors and
> op= involves sorting out ownership. In a GC system like
> Java, this problem vanishes. C++ Example:
>
> class Foo { Something* _c; public: Foo(Something* c) :
> _c(c){} ~Foo() { delete _c; }}
>
> Inadvertent copying of Foo (inadvertent copying in C++
> happens a *lot*) will result in a double free.
>
> You can fix this using a reference counting pointer - but
> that typically requires additional support in the class
> you are counting and if its not your class you're stuck.

Since there is no
new
, you don't need the
delete
. In the initialization all that is happening when you do the member initialication is that _c is pointing to the same thing that c is. At least, that's what my debugger is showing me. In the case you have here, Foo isn't responsible for managing the memory. It's just another reference to something.

If you wanted to do what you are talking about doing, you would have to copy the memory from c to _c. Or not call delete. Since there is no explicit memory allocation, I don't see why you would have tried to explicitly deallocate memory.

I'm not sure what's being inadvertently copied. Other than a contrived example of something that theoretically is a problem, where would something like this show up in a production application? If you had to copy something it would be something like this:


class Foo
{
Something* _c;
public: Foo(Something* c)
{
_c = new Something;
memcpy(_c, c, sizeof(c));
}
~Foo() { delete _c; }
}


Or better yet, if it's some kind of container, you would most likely use a template. Then it would be typesafe and reusable.
Todd
Posts: 27 / Nickname: tblanchard / Registered: May 11, 2003 10:11 AM
Missed it completely
February 27, 2004 0:19 PM      
My point that is.

I'm not sure what's being inadvertently copied. Other than a contrived example of something that theoretically is a problem, where would something like this show up in a production application?

Well of course its contrived - it has to fit on this forum. But your example is better than mine for illustrating my point.

class Foo
{
Something* _c;
public:
Foo(Something* c)
{
_c = new Something;
memcpy(_c, c, sizeof(c));
}
~Foo() { delete _c; }
}

The memcpy of an instance is particularly evil and do you realize you are only copying a pointer sized chunk of memory?

However, even in this case your code will crash under this circumstance:

{Foo f1(new Something); { Foo f2(f1); } }

thanks to the compiler generated copy ctor. Equally (perhaps more) common is people forgetting to make function args take a reference which results in stack created temporaries. This is the usual cause of inadvertent copying.

Anyhow, I see no reason to continue to argue with a fictional character lacking a basic grasp of memory management.
Matt
Posts: 62 / Nickname: matt / Registered: February 6, 2002 7:27 AM
Re: Elegance and Other Design Ideals
February 27, 2004 0:20 PM      
Indeed, why are you deleting something you didn't create? Is this an example of how to create a "dumb pointer" object in C++?

Also, Merry, why would you use memcpy() in C++ instead of a copy contstructor?

Maybe both of these things illustrate a big problem that does occur in C++: many people still use a C approach in their so-called "C++" code. It is the downside of the multi-paradigm capability.

Once again, this may be due in large part to Microsoft's influence, as this kind of thing is especially rampant in thier libraries and example code, where about the only C++ish elements are the "//" comment syntax and the file extension. (and even the "//" comment is standard C, now, I think). I guess they just have a lot of old programmers who agreed to change their file extensions to '.cpp' but stubbornly refused to actually learn C++. The old argument for releasing libraries in plain C used to be for platform-independence (I guess), but I don't see any reason why Microsoft doesn't release their new libraries in pure C++ these days.
Todd
Posts: 27 / Nickname: tblanchard / Registered: May 11, 2003 10:11 AM
Re: Elegance and Other Design Ideals
February 27, 2004 0:27 PM      
I would be very interested in seeing a Smalltalk version of this library which is more compact and elegant than the BGL.

It would be considerably more compact simply because the extensive type notations would be absent. Dynamically typed languages support generic programming natively without templating mechanisms - the participants need only conform to expected protocols to allow substitution of one class for another.

IOW, templates put back the ability to separate protocol from type that is inherent in dynamically typed languages and was missing from C++ prior to the introduction of templates.
Todd
Posts: 27 / Nickname: tblanchard / Registered: May 11, 2003 10:11 AM
Re: Elegance and Other Design Ideals
February 27, 2004 0:31 PM      
Indeed, why are you deleting something you didn't create?

Perhaps an unusual creational pattern (factory or something) is used. Its rather beyond the scope of the example though - let us say that this class's role is as an adopter of its constructor argument.
36 posts on 3 pages.