Of course the *implementation* of the APIs using bytecode rather
than being native code is helpful for the cross platform aims,
...
ISTM that some things in the core APIs such as file IO and
math cannot be implemented in Java bytecode. If these features were in the
bytecode then there could be (in effect) simple function calls for them without
the need of an API.
I was saying that implementing some core APIs with
native code and not bytecode helped the cross platform aims. This is the exact
opposite of what you are saying. ISTM you are thinking that less native code in
the APIs means less code to port. The problem with that approach is that you
are shoving all of the porting complexity into the VM itself. Now the VM has to
know about file IO; now the VM has to know about all the different math
functions and so on.
It is an easier, simpler, more modular, and more
portable design if you keep the VM as simple as possible and move as much
hardware/OS dependent stuff into the core APIs as possible. This way you can
have one person or team work on porting the VM and another person or team work
on each of the non-portable APIs. This is similar to the overall design
philosophy of OOP: you want to break things down into smaller, independent
chunks. For example, all the OS specific file IO stuff is dealt with when
implementing the file IO APIs. All the hardware math stuff is dealt with
implementing the math APIs. In theory, if you are targeting two different OSes
that run on the same hardware then you will have to make changes to the file IO
API implementations because that is OS dependent but you may not need to make
significant changes to the math API implementations because that is hardware
dependent but OS independent.
By moving as much hardware/OS dependent stuff
as possible out of the VM and into the APIs you make it easier to port the VM.
This is a clever design. It also explains why the core Java APIs are such in
integral part of the Java language and why you need them to write any
non-trivial Java program. As soon as you want your program to interact with the
hardware or the OS, for example to write characters to the terminal or read a
file, then you have to use the core APIs because that is where Java puts most of
the hardware/OS dependent code. This explains why a Java program is "deaf,
dumb, and blind" without those APIs.
This could easily segue into
a much deeper discussion about how different programming languages handle
complexity. I believe there is an analog to Brewer's CAP theorem that pertains
to complexity in programming languages. There are three main areas where you
can shove complexity when creating a programming language:
- the
writing/porting of the language
- writing programs in the language
-
running programs written in the language
The total complexity is roughly
constant and all you can do is shove it around between these areas. One of the
Java design goals was to minimize the complexity of (1) which forced greater
complexity into (2) and (3). Both Perl and Flash took the opposite approach and
tried to minimize the complexity of (2) and (3) at the expense of the complexity
of (1).
For a long time Flash and client-side Java competed for the
browser animation and added functionality market. Java had all the advantages.
It was first to market by years; it was more more powerful; it was more stable.
It came built into the popular web browsers. Yet Flash cleaned up and is now
nearly ubiquitous while Java applets seem to be few and far between. I can have
Java turned off and hardly notice it.
This is because Flash was aimed at
developers and end users at the expense of the language developers. For
example, here is a board game designer who used Flash to make the prototypes for his game.
He used Flash because it makes the design process very easy. I cannot imagine
someone using Java for something like that. Likewise, Flash makes it very easy
for designers to create "pleasing" experiences for end users (when compared with
Java. I'm not a fan of Flash on the web). The downside is that the code to
implement Flash is a bear. It's hard to port, it is buggy, and there are a lot
of security holes. Java was better than Flash in every way except the two ways
that were vital for success.
The code that implements the Perl language is
also a bear. It is hard to port and it is incredibly complicated. The trade
off is that the Perl language is very friendly to developers and users. For
example, I have some very complex, arcane Perl-4 code that was written before
Java was even released. It still runs fine with no changes to the source in the
latest 5.x versions of Perl. Languages such as Ruby and Java do not have nearly
this depth of backward compatibility. If code in those languages just sits
around for a number of years it always seems to need to be fixed in order to
work with the latest versions. I think this is mostly because the APIs keep
changing. By making the language easier to port (by moving complexity out of
the VM and into the APIs) the also increased the amount of complexity and
instability that developers have to deal with. I admit that these problems are
probably now less severe then they once were but that doesn't make those first
years any less brutal or frustrating.
Some of the above was based on my
personal experience. You have may have had very different experiences.
Nonetheless, I think the idea of shoving around complexity between the
implementation, the programmers, and the users is interesting and deserves
consideration even if your experience conflicts with some of the personal
experiences I used to explain the idea.
--- Our job is to remind
ourselves that there are more contexts than the one we’re in now — the one that
we think is reality.
-- Alan Kay [ Reply to This | Parent | # ]
|