Eiffel for embedded systems at Hewlett-Packard
``Eiffel is the perfect embedded language...'':
an interview of Christopher Creel,
HP CCD (Color laserjet and Consumables Division)
How HP used ISE Eiffel to develop leading-edge printer software,
used Design by Contract to preserve the work of its best designers,
and in the process found bugs in its legacy software, discovered
in a hardware chip, and learned a few lessons --
such as how to do in weeks what used to require months.
Few industries are more lucrative and more challenging
than the printer business. This is one of the areas where
Hewlett-Packard has built its unparalleled reputation, through
its justly famous and wildly successful printer line. In 1994 alone, HP
sold 5 million DeskJet printers and almost 4 million LaserJets.
An obsession with quality
As company co-founder David Packard writes in his book
The HP Way:
``More for less'' became the goal for each new LaserJet model...
DeskJet single-handedly created the revolution in color printing...
The essence of customer satisfaction at Hewlett-Packard is our commitment to quality, a commitment that begins in our laboratories and extends
into every phase of our operations.
An obsession with quality in software is the very definition of
so it is not surprising that HP has chosen ISE Eiffel to help
maintain and increase its edge in the printer business.
HP's printer division has been taking advantage of Embedded Eiffel,
to tackle some of the most difficult challenges of this
fiercely competitive industry.
Zero Memory Leak. No excuses.
Printer firmware raises some of the most difficult issues
of any embedded development. A software error does not just
mean that your job doesn't print: it can cause all kinds of
catastrophes, starting with jamming and ending, in the worst
case, with a broken engine!
Printer manufacturers typically rely on software to
provide customers with sophisticated functionality while
minimizing hardware costs. As a result, printer
software can be extremely
complex, reaching into the many hundreds of thousands of lines
of code. Yet for cost reasons the
result must fit in extremely limited ROM and RAM space,
and take advantage of every CPU clock cycle available.
The RAM requirements are particularly tough.
Because printers typically remain turned on for months,
it is not enough for the software to use as little memory
as possible: it must return every single byte
that it ever uses. This Zero Memory Leak
requirement was one of the key demands placed on the
Eiffel software, and was met by ISE's garbage collection
Threads and GC: total independence
Garbage collection was in fact one of the primary
reasons why HP selected Eiffel in the first place.
The printer software had to
be multithreaded, taking advantage of
the natural concurrency of printer tasks to divide the
processing into a number of parallel threads. ISE Eiffel provides
both a sophisticated multithreading library,
EiffelThreads, which works in concert with the garbage collection
A unique property of this combination is that
each thread has its own garbage collector.
In most existing thread-GC solutions, all threads share
a single GC, so that if one thread runs out of memory
all other threads must come to a halt until the GC has run
its course. With ISE Eiffel, each GC manages the memory
for one thread, so that no thread ever penalizes another's
memory management. This one of the key properties of
the environment that enabled HP to use software to meet
some of the most ambitious goals for its new printers.
Christopher Creel talks about embedded Eiffel
Christopher Creel, R&D Firmware Engineer at Hewlett Packard,
recently talked with Ann Bailey of Business
about his experiences of using Eiffel for
embedded systems development at Hewlett-Packard.
In this candid and wide-ranging discussion, Christopher
tackled many issues,
from the use of Eiffel to improve the software culture of a company
to the role of Design by Contract, how to manage the results
of a company's programming gurus, and the future of object technology
in the embedded world.
Here are some excerpts for the benefit of eiffel.com readers.
What were the goals of this project? What were you trying to achieve?
What we originally set out to do was just a feasibility study. We were never supposed
to ship this thing as a product! All we were trying to do was figure out if Eiffel was a good
language for embedded applications --
a better alternative to the more classical languages that have
been done in an embedded world.
``We feel that Eiffel is the perfect embedded language.''
This is what most of HP would be interested in, since most of HP
is doing embedded work.
This is an
interesting study in how one division broke away and decided to try something that
has not classically been used in the embedded systems world. And, as it turns out,
we feel that Eiffel is the perfect embedded language.
Initially you were not going to ship. How did you start?
``The issues are RAM, ROM and speed.''
To understand why we were asking ourselves whether Eiffel was a suitable
language, you have to ask why it would not be suitable.
Many people are
comfortable with C++ as a language for the embedded world. With
Eiffel the three primary concerns are the obvious ones: RAM, ROM
We have to fit into a small amount of RAM. We have to fit into a
small amount of ROM (this is where our code goes).
And it's got to be fast. In fact embedded engineers have classically been speed
``The primary issue is cultural.''
But there was more to the feasibility study than those three requirements.
The primary issue is cultural. We had to deal with the C-C++ culture.
What's the C-C++ culture?
It's the conviction that the engineer
is God. The engineer can do anything. You withold nothing from
You put your ultimate trust and faith in the engineer's abilities.
Many people in the embedded world have been brought up
with an arrogant view of software engineering: that we
that ultimately we'll be able to ship a product that is error-free
because we are such fabulous engineers.
Most of the companies in this country
still have the "Engineer is God" culture,
whether they are using C or C++ or something else;
even Java still has much of that culture.
It really gives an individual a warm fuzzy feeling to have his or
her manager implicitly say
"I trust you never to make a mistake".
Eiffel is the antithesis in every way, shape and form of
the C-C++ culture.
The ground assumption with Eiffel is that the engineer
is not only fallible but extremely so, to the point
that you must question every single
thing that you're doing.
``Eiffel means questioning that the Engineer is God.''
How did that culture affect the feasibility study?
It broadens the question. It means that just meeting the
first three requirements -- RAM,
ROM and speed -- may not be enough.
Ultimately software is not a science,
not even an engineering practice; it's a human event.
You have to give these fallible humans something that they will
be willing to use. They might not be willing to put these types of restrictions on
themselves, to give up the "Engineer is God" culture.
I'm surprised that culture has worked and hasn't been challenged. What if something goes
That's why we started this project to begin with.
Why try anything else? What was broken?
We were of course meeting the cultural requirements -- the
warm and fuzzy feeling. We were meeting the RAM, ROM
and speed requirements, what may be called
the "CPU clock cycles" -- how fast and tight an application
``We had the CPU clock cycles, but not the engineering clock cycles''.
But in the requirements for shipping a
product there is yet another factor, what I like to call
the "engineering clock cycles":
how fast an engineer can turn out
a quality product -- a product that works not just
in the lab but in a factory where it gets bumped by forklifts
all day long, and with code that is more or less bug-free.
We were failing on this miserably, we are still failing on
that miserably, and frankly many large companies are failing
on this miserably.
But then we found that our competitors were able to increase
their engineering clock cycles by giving up on the CPU
clock cycles. They were loosening
up on all of our first three requirements:
loosening up on RAM space, on ROM space and
on speed. But as a result they were able
to speed up their engineers to
produce more features faster than we could.
And we also found that the customers liked it! They liked having a whole
bunch of new features. All of a sudden our archaic yet fast products
weren't meeting consumer demands. That's why we decided to try
We decided that if our competitors were willing to give up a
little bit on the first three requirements -- on the CPU clock cycles
then maybe we could figure out a way to continue beating them on
these performance requirements while tackling the fourth one, engineering
How do you get the engineering cycles without losing the CPU cycles?
The only way to achieve this is to step away from the C-C++ culture.
``As the complexity grows, errors start creeping in.''
But if you stop assuming that the Engineer is God, and accept instead
that you have lots of highly fallible engineers, you suddenly
realize that most likely the state of your software is
horribly flawed! Just as flawed as the humans are.
To make it
worse, as the size of the software applications grows, its complexity
puts more and more of a burden on the engineers, and
errors start creeping in. This is unusually bad in the embedded
world because it is classically filled with electrical engineer
majors who have had no training or experience
in large scale software engineering.
They started a few years ago with
small embedded applications, but now the applications have
often half a million to a million lines
``We are in the Do Or Die phase. That's where Eiffel comes in.''
It's that combination that makes the situation critical:
human fallibility, and lack of
software engineering skills. That's why I decided to try
We are in the Do Or Die phase; that's where Eiffel comes in.
Eiffel one hundred
percent corrects the cultural problems, by accepting
that humans are fallible.
There is another very interesting aspect of Eiffel that few people
can pick up on, because many people are not all that versed in
large-scale software engineering and the realities of
the software industry today. It has to do with the
contribution of Eiffel's Design by Contract to
preserving the work of the top engineers.
``Design By Contract saves the work of the one-ten engineers.''
In most companies today, you have a small group
of hard guns who are responsible for the core job.
They are the engineers who come
in, do the dirty work, and then get out.
Fred Brooks, in his book The Mythical Man-Month, called them
the "one-ten engineers" because such an individual can do the
work of ten normal engineers. Every company
has one of them. They sit
down one day from nine to five, and do more than some other engineer
who has to work from eight until twelve an entire week.
So now you do have an engineer who really is God-like!
the question becomes of how to harness that engineer's abilities
to avoid disaster when he or she leaves.
``That's where C and C++ really fall apart.''
That's where C and C++ really fall apart. We have seen the
result when someone a great engineer leaves after writing
this beautiful thing.
A year later the other engineers come in, and because
they don't immediately understand the
solution they will start hacking it, and in the process
they destroy it.
The consequence for the quality of the code base is
a lowest common denominator effect: even
though you have this great engineer,
after a while the result of his work starts to degrade to
the level of the work of those who are not as good, or don't care
Because C and C++ allow this God-like atmosphere there is nothing
stopping them. They are allowed to do anything --
including destroying the good work of their betters.
They don't do this on purpose, of course; they just don't know
any better. But it makes them feel bad, so you also get
a slow degradation of morale; engineers become unhappy,
get burned out, leave the company.
That is one of the biggest problems with
the Engineer Is God culture:
expectations are so high, and results so far
from the expectations, that people's lives become miserable.
Design by Contract to the rescue.
Eiffel remedies this.
You assume nothing. You assume everything is wrong. You assume
everyone is out to screw you up.
And then you assume that everyone is going
to try and wreck your good work.
That is where Design by Contract comes into place.
How does Design by Contract help preserve the work
of the top engineers?
You build a white-box framework -- effectively, a scaffold. It tells
you where to put
the pieces but it really isn't the mechanism itself. It s simply a template, a specification, to which you will
plug in the working components -- the implementations.
``You forever eradicate an entire class of bugs.''
Any contract that you put in there
will exist forever. That engineer, that one-ten engineer who
builds these contracts at the base level, eradicates an entire class of bugs forever.
Because he or she can see further into the future than most engineers,
he puts the contracts in place for all eternity,
once and for all destroying errors that other
engineers could make 6 months, 2 years or 10 years down the road
because they don't see the whole picture.
Eiffel has lots of other things, all those
wonderful software engineering aspects.
But in my opinion the most powerful concept
in the entire Eiffel approach, which so few people really touch on,
is that you can take that
one-ten engineer and project his good intentions into the future forever. No one can
ever destroy those good intentions again. That
is unique and incredibly powerful.
That's not to minimize all the other aspects, of course. Eiffel is
single-mindedly focused on large-scale software engineering.
Entire classes of maintenance problems, for example, disappear thanks
to the simplicity of the control structure, the one-entry one-exit
That is just one minor example; there are many others.
Eiffel, just by its design -- Bertrand is really a brilliant linguist. He
has such incredible depth into what is required of a language to make it good, to eradicate entre classes of potential defects.
But the best thing is this ability to preserve the work of the one-ten
engineer. By becoming a contract lawyer he
can build contracts into the base classes of the architecture.
Because he can see further than the less experienced engineers,
he can use the contracts to rule out all kinds of things that could
go wrong in the future.
Because of the language itself, because of the way everything is designed
for large scale software engineering, because of this ability
to utilize your one-ten engineers better, morale goes up.
You don't necessarily have to hack and kludge anymore.
How do you document the best engineer's intentions?
Eiffel is just rife with the idea of
As opposed to having a separate document that an engineer
will probably throw away or use to balance his table, you take
that document and embed it into the code.
Most people, when hearing about embedding information into code, think
of comments. Comments are what I call benign documentation.
They don't do anything, they become outdated, people
don't read them or even remove them.
``With Eiffel you get proactive documentation.''
With Eiffel you get
what I call proactive documentation. Whenever you have
a condition that must hold somewhere, you make it part of the
code through an assertion. Much of the time it's simple stuff,
like "this value must be between 0 and 255".
You document all these assumptions that engineers make, especially
the one-ten engineers, and you make them an enforceable part of the
C has a limited form of that, the assert instruction.
In Eiffel it's an integral part of the language, it's closely
integrated with the object-oriented structure of your software,
and it serves both as proactive documentation -- to express the
intent of the one-ten designer -- and as a testing, quality assurance,
Through these mechanisms Eiffel gives the original engineer
the ability to limit future engineers' choices, to lead them by
the hand when they make changes and additions.
It's much more powerful in that respect than C and C++ or any
of the other languages I've studied.
Languages often get used far beyond different their original
purpose. C is a great example.
It started out as a relatively clean language. It was meant to build operating systems,
low level stuff. Bertrand calls it a portable assembly language.
And then what happened? They said "Ah this is the language,
we'll never need another one as long as we live, it lets you do anything!" But as it
turns out it's a terrible software engineering language. So what do they do? They
come up with C++. C++ is C. It is not a different language.
Many people have described C++ as a fancy
macro-language for a macro-interpreter for C.
Yes, you can do anything in C. It's just that the complexity
issues are so great that now you need an initial parser
in order to get down to C. When that parser came, in the form of C++,
"Oh this is the perfect language. We're never going to add
anything again." But then they added multiple inheritance, then
templates, namespaces, exception handling. They
kept adding these things because they found
that the language was deficient, yet they
never wanted to admit that they need another language.
``Such incredible rigor, yet such openness.''
So do we want HP as a whole to use
nothing but Eiffel? No. Eiffel has this great loophole. It's this wonderful software
engineering language with such incredible rigor, yet it has this amazing loophole in
it -- the external clause.
You can say that a feature of a Eiffel class is actually
implemented externally, so you can call out to any language you'd like from within
Eiffel. Therefore if we feel that Eiffel is inappropriate for
a certain task, no problem -- you simply call out into the language
that is appropriate. That is how we are using it today.
How does that work in your team?
Our team is the imaging team within CCD
(HP's Color LaserJet and Consumables
Part of our C-C++ culture is that you're building software like ROM.
You're building it to last. It's
going to be around for a thousand years.
The cold, harsh reality is that if your architecture lives intact for more that a year, you
have built something so phenomenal that it will go down in the history books.
``Everything is changing all the time.''
Everything is changing all the time, all the parameters.
That is the greatest thing about software. It's a human event,
not a science. Science moves very slowly. How often does physics get a new set of axioms?
But we aren't dealing with
natural phenomena. We are dealing with a stream of consciousness.
The mentality in my team is: as an architect it is
my responsibility to make myself obsolete. If I have not made myself obsolete at the
end of a project, if I need to be around at the completion of a project to help the next
team along, then I have failed, radically failed.
Furthermore, everything I build I must build it to be replaced.
How do you do build something to be replaced?
Build it so that it is easily destructible. Build it so that an
engineer can come in and say, "Boy this thing is really old,
it's really archaic, we've got to get rid of it."
Eiffel as an insurance against job insecurity.
If you succeed, someone
can remove a component
and stick in another without any disruption to the rest of the system. So you need to
build your stuff such that it is totally expendable, and also such that you yourself are
expendable, because ultimately you are -- whether you like to think so or not.
The engineer is expendable?
There is no more job security, on either the employer or the employee
These days engineers are coming and going at an amazingly fast rate,
especially in areas like Silicon Valley.
I've heard stories from friends of mine who
have had headhunters come up and tap them on the shoulders in the parking lots
"Hey, I've got a great company just down the street and we will pay you twice what
you are getting now". As a company you need to protect yourself against
the effects of that. You cannot use the traditional approach, which
was to embed your documentation into your engineers or
into your external documents. The external documents will
become obsolete; the human document will leave.
The documentation has got to be in the code, it has to be expendable.
Eiffel supports this, because the documentation and the
interfaces are all in Design by Contract, and the system is structured
into clusters, every one of which is expendable.
``Eiffel: the ideal orchestration mechanism.''
Where in your engineering structure do you put Eiffel?
Eiffel shifts the focus away from CPU cycles to engineering cycles. C does
So you should use Eiffel
where those engineering cycles count. That is the majority of your software: contrary
to what many engineers think, most of your cycles are not CPU cycles. If you have
a large system -- say between two hundred and fifty thousand and a million lines of
code, which is very large for an embedded system -- there is usually some kind of
mechanical event that occurs due to some stimulus. The majority of the processing
activity usually takes place right after that mechanical event
For instance if you had a scanner where you scan the information and
than you do some kind of processing and than you ship it out to disk but the majority
of your code is really dealing with data management in orchestration -- and Eiffel
is an ideal orchestration mechanism.
That's 90% of our code.
What was your biggest challenge?
Getting a run-time into a legacy system that doesn't
play nice. Our legacy code is large, its memory management is rather complex.
Getting memory in the embedded world is never an easy task, it is a resource that is
like water in the desert. And so just finding memory for the run-time is going to be
Exception handling is also an interesting question.
``You make Eiffel a static library.''
Eiffel makes a few
assumptions. For instance, it assumes that there is an exception handling mechanism
available. It assumes that there is such a thing as longjmp and setjmp and these types
of mechanisms. They are not always present in the embedded world. It makes certain
assumptions about memory -- allocating and reclaiming it. These are hard
These are only a few assumptions, but we must meet them. Fortunately
we found an operating system that does: VxWorks. This gives
us exception handling and memory management, pretty much like
Then we had to figure out how to drop in the run-time.
And that was a difficult task, to figure out where to put it in, where to start it up,
where to initialize it.
You have to make the Eiffel runtime into a static library,
without a "root object", able to interact with
a multithreaded legacy application written in C.
``The Eiffel run-time allows you to specify all kinds of memory management schemes.''
Another requirement was that each thread had to have its
own garbage collector. We wanted a bunch
of different threads to use Eiffel: then if
there were only one garbage collector and one of them went
into garbage collection, all threads would have had to stop,
and that's bad.
Also, we needed to be able to start up and shut down garbage collectors
We found that the Eiffel run-time indeed allows you to
specify all sorts of different memory
allocation and reclamation schemes; you can tell it to allocate
very small but slow, or very big and fast.
Also crucial was memory reclamation. When a thread dies, with
its garbage collector, it is essential for that thread
to relinquish all of its memory for another thread to use.
Yet another requirement, for the use of Eiffel in concert with
a complex legacy system, was to make sure that all information
on the stack
we found that some of our code was jumping around using setjmp and longjmp; so
when they did a long jump, had that variable data been stored on the stack, it would
have gotten blown away by the longjmp.
No matter what our horrific things our legacy code might
do, the Eiffel stuff needed to be separate.
``ISE had a real slick solution for this stuff.''
It kind of fire-walled away into ROM bad things our legacy code would do.
Fortunately ISE had a real slick solution for this stuff. Each thread had its own private variables
and that is where the actual garbage collector went. Whenever you wanted to get the
garbage collector you just got it from the threads context. That worked out real great.
We were able to blow away garbage collectors at the drop of a hat.
Boy, it's real sweet!
Were the RAM requirements tough to meet?
We needed to stay between 50K and 70K.
Fortunately ISE Eiffel seems
to accommodate that just fine.
``ISE gave us a laundry list of things that could be kept or removed.''
Actually ISE gave us a really nice solution.
When we dealt with other run-time vendors they just said "Sure, we can do this, we
can get it down for you". What ISE did was that they gave us a laundry list of stuff
and they said: "here are the things that we can remove to meet your ROM
requirements. Go through the list, check off the stuff that you don't want".
It was like
a price list -- this is how much this thing costs and if we remove it this is how much
you'll save --, only with "cost" meaning number of bytes.
That helped us quickly determine just how
big this thing was going to be.
``You develop your stuff at home in your underwear eating
cheetos, bring it to work, and it just runs.''
One of the interesting side benefits of using Eiffel in the embedded world is that you
can develop your functionality independently of the embedded code.
ISE Eiffel is so portable between the different platforms that
you can develop
it on your PC at home in your underwear while you're eating cheetos
and then when you're ready you can go to work, plug the thing in,
and usually it just works because
you've tested it independently of the actual printer code. When
we brought it to the printer code we
might get one or two contract failures, but that was usually about it.
Most of the times it just worked the first time we plugged it in.
What about the contract failures?
``Thanks to the contracts we found bugs in the legacy code.
We found a chip defect thanks to Eiffel!''
They were very important! Rarely were they
due to the Eiffel code. Usually it was due to the legacy code interfacing with the
Eiffel code. What we often found was that we found bugs that we had no idea were
there -- strictly thanks to the Eiffel code.
We actually found a chip problem this way:
Eiffel found a floating-point bug on the chip we were using.
Everything was working fine on the simulator; usually when things
work on the simulator they work on the hardware, but in that
case when we moved to the hardware an assertion failed. In the end
we found it was a problem with a floating-point operation on
``Just having Eiffel code improved our existing legacy code.''
We also found, by putting Eiffel rescue clauses on the Eiffel side in
our external functions, that
if the C code failed because of some horrible thing, the Eiffel code could actually
recover for the C code. Just the very existence of Eiffel on our legacy code improved
the quality of our existing legacy code.
We had never really thought that was going to happen, nor did we know to what
extent it was going to happen, but it did happen twice.
``This was a powerful moment for our management.''
This floating-point precision problem in particular was really big. Potentially these
are million-dollar problems; look at the Intel Pentium bug. So it was a real powerful
moment for my management when that happened.
``Once written we barely touched the Eiffel stuff. We never had any problem with it.''
What lessons did you learn?
I spent ninety five percent of my time working on the C side, just getting the C side
prepared for Eiffel and getting the C code working correctly with Eiffel. Once we
got that all set up we never had any problems. We never had any problems with the
Eiffel code -- the stuff that we developed outside of the printer. And we barely ever
touched it. Once we wrote it we barely ever touched it.
Most of our time was spent just trying to get the C stuff, dealing with the average
problems of C -- overwriting an array boundary, writing some null values, all of the
things that fallible humans do.
So the lessons learned were not really the ones we were seeking. We were looking
for answers to: Could we use Eiffel for our RAM, ROM, speed
requirements? Could we get it into our cultural requirements?
But a lot of the more powerful lessons
were "Holy smokes, if we drop this in,
it actually heals our legacy code, it's
like putting balm on a wound!"
``We could do in two weeks what we were previously doing in months.''
It was also an eye opener. "Look how slow we're moving! We
built this Eiffel stuff in two weeks and it's taken us months
to get it to work in the legacy code. Come on!
Why is this? We should be moving as fast as we are on the Eiffel side".
That showed us that engineering clock cycles would vastly improve
if we could just get going.
Portability was the other great eye-opener -- developing the
Eiffel code at home while eating cheetos, then coming in
and dropping it in.
It's one hundred percent portable! It has the exact same
behavior on three platforms -- on Unix, on my PC and on the hardware.
legacy code isn't all that portable;
we can't take it off the hardware and put it
on my PC at home. But here I am taking Eiffel code and using it all over the place.
``An ideal system for medium to large scale embedded systems.''
So, yes, Eiffel is indeed an ideal system for medium to large scale
where your ROM requirements are somewhere below 300K.
Another good point. For C and C++, when your features grow, your code
grows with it. The curves are either the same of exponential.
You're eating up more and more ROM in order to accomplish
particular features. With Eiffel, because of its
powerful reuse mechanisms, your ROM requirements really don't go
up nearly as fast. So while your initial outlay in ROM might be
say 300K for an entire system, as your features grow it's a long term
investment because ROM requirements will grow much more
slowly as you add features.
What about RAM?
For the system that we are doing right now, which is really
sophisticated already, we're shooting at about 70K.
I would say that Eiffel is an ideal solution for medium-
to large-scale embedded
applications: because ROM size does not increase as quickly and because it takes
away all the trouble and pain and heartache that we go through just to make sure that
we're not overwriting array boundaries, accessing non-existent variables, de-allocating memory that we either never allocated, or forgetting to deallocate memory
-- all aspects of memory management.
``Microsoft Word overwites an array boundary and you have a GPF. We overwrite an array boundary and your printer gets damaged.''
This is very important to embedded people. Say
Microsoft Word overwrites an array boundary and you get a general protection fault.
Big deal -- you can shut the thing down and no one knows. Now say you override
an array boundary and you get a general protection fault on your printer: your five-
hundred page job just got blown away in the middle, you got to restart the whole
thing -- you might have gotten a paper jam, you might even have
damaged the engine.
C and C++ have the memory management problems and don't support large scale
software engineering, so you're up for all sorts of problems. Smalltalk has the
memory management but it really wasn't designed as a large scale software
engineering language so you can do some pretty amazing hacking with it. It doesn't
allow you to extend that one-ten engineer's good intentions as well as Eiffel does.
We didn't expect that using Eiffel improved our
legacy code just by the fact that it caught bugs that we had never seen before.
Any final thoughts?
There is an untapped market for Eiffel in embedded
and legacy systems. HP sees Eiffel as a major force in
large scale software
engineering if it is positioned correctly.
``They are using C, C++, Java. HP can use Eiffel and kick their butts.''
We know that we are ahead of our competitors in this. Most people
are still using C, C++, perhaps Java.
HP can use Eiffel and kick their butts.
Of related interest