The Demon Of Portability
Posted 20 Dec 2000 at 21:42 UTC by mrorganic 
There's an interesting debate here about the
relative merits/drawbacks of writing UI-independant code for the LyX
project. As such debates often do, the issue degenerated into advocacy
camps: some like widget-agnostic code, some don't; some like formal OO
methodologies (Model/View/Controller), some don't.
Ultimately, the question was not resolved so much as dropped. Were
this issue limited to the LyX project it would only be of passing
interest, but this exact problem devils many emerging GUI applications
in the Linux space because of the many toolkits in use. The two most
popular are GTK+/GNOME and QT/KDE, but there are others -- Motif is
still popular, FLTK has its fans, and XForms is still around. Mozilla
has introduced yet another variable with its XUL interface, allowing
programmers to use the browser as a platform for GUI code.
Many developers (including myself) view this situation with a very
jaundiced eye. Application developers often shy away from Linux (and
other *nixes) because they cannot depend on a standard system API being
present (like WIN32 or the Mac toolbox). And Users tend to be very
vocal about their GUI of choice -- they tend to get soggy and hard to
light if the application does not integrate well into the GUI. So if I
as a developer choose GTK+ as the basis for my application, I am sure
to get flamed by at least 50% of the user community for not using QT.
Worse yet, interoperation with other applications is sure to be painful
because GNOME folks use CORBA while KDE folks use DCOP, which are
(naturally) incompatible. And I'm not even getting into the
difficulties of providing services under different window-managers
(which often interpret right-clicks and middle-clicks differently,
or treat focus in a strange way).
One approach many have tried is to try and write GUI-independant code --
that is, code which abstracts the functional underpinnings away from
the GUI "frosting". Mozilla actually reinvented the entire GUI itself
(XUL). The success of these various projects is decidedly mixed --
they tend towards "lowest common denominator" feature-sets, and
stability often suffers due to the complexity of the code.
The problem here I think is one of background: Unix developers are
constitutionally incapable of consensus. It doesn't surprise me that
there was no consensus on a common GUI API -- over the thirty years
Unix has been around, there was no consensus on something as
fundamental as a filesystem or C library! (Or thread library, or
driver model, or initialization method, or ABI, or printing API,
or.... But I digress.) As a longtime Unix hacker, I've always
considered portability to be a Good Thing, but lately I've begun to
wonder if that's really true. Theory tells me that writing portable
code should lead to better code, but experience has shown decisively
otherwise: native apps are easier to write, maintain, and extend. They
are also, not coincidentally, more stable.
In the Linux world at least, the boat has sailed. There is no way to
mandate a common GUI API at this late stage of the game (even assuming
that a common API could be agreed upon). We must continue writing
applications that sometimes work and sometimes don't, that can't
communicate efficiently with each other, and that have to re-invent the
wheel over and over again.
As a developer I can only wonder why we inflict this kind of pain on
ourselves.
Who's inflicting what on whom? What would you suggest as the
alternative?
As a user, I will not "flame" you because you chose Gtk instead of Qt or
vice versa. The beauty of X is that all these widget sets can run side
by side. If your application is useful to me, I'll run it, even if you
invent your own widget library. I'm sure there are some users out there
for whom tight coupling to their desktop of choice (GNOME, KDE, or
whatever) is important, and who care about having a common theme and
Bonobo component embedding between all their apps, but it's definitely
an exaggeration to say that 50% of your user base will complain because
you chose the "wrong" widget set. Don't let the vocal minority sway
your impression of the world.
So, what's your point, exactly? Would you take away freedom of choice
and force KDE developers to work on GNOME instead (or vice versa)? (Who
gets to decide which one wins?) Would you have us drop this whole "free
operating system" nightmare and go to work writing Windows software,
since Windows is clearly better because it doesn't offer all these
confusing choices?
Now, the developers of competing platforms could work to enable
interoperability. This is difficult because part of the reason they're
in competition in the first place is that they have fundamentally
different models of how software should be built. Nevertheless, there
is some work going on to make sure that basic operations remain
compatible. You're always free to lend your support to those efforts,
of course.
Choice is part and parcel of freedom. Without choice, freedom is an
illusion ("you can have any color you want, as long as it's black"). If
we want free software, we must embrace the fact that we will be faced
with choices. Over time, if the burden of choice exceeds the benefits
of diversity, the community will pick something and move on (leaving
only a few screaming zealots behind...). Perhaps this will happen to
free GUI desktop environments in the future, but this isn't a process
that will happen because you want it to (nor should it).
Meanwhile, you're left with the free person's burden: you must choose
among the available alternatives, weighing the respective benefits of a
framework you like, features you enjoy, and a user base who will prefer
your product.
I totally agree with egnor. Having different choices (of GUI toolkits
or whatever) is a good thing: freedom implies choice; if you don't like
GTK+ you can shift to Qt, or create your own solution: in the propietary
software world, they don't give you such a chance.
On the other hand, if we left aside philosophycal considerations and
focus on programming practice, I think that abstracting away the
presentation layer of an application is the right thing to do, even if
you don't plan to provide multiple interfaces to your application. The
design is cleaner and far more elegant this way and, in my experience,
the maintainability of the code increases. Using this approach in my own
projects, i've been able, for instance, to provide CLI, curses and GTK+
front-ends to the same core functionality, maximising the reuse of code.
Just my 2 cents...
And I agree..., posted 21 Dec 2000 at 01:08 UTC by DrCode »
(Journeyer)
... with jao's agreement with egnor. Encapsulating the GUI interface is a good thing.
But, when you finally decide on a toolkit, my suggestion, as a long-time KDE user and C++ coder, is to use GTK. It's already ported to X and Win32. And although it's in C, I've found it very easy to use in C++ code: Represent a GUI component with a class; pass an instance as the 'data' to signal handlers; and use static methods as the signal handlers (so they have access to the instance's data). Plus, it's completely free, both in the 'free beer' and 'free speech' sense, with very readable source code. If you need it on another platform, like Mac or BeOS, it shouldn't be an impossible project to port GTK.
I'm sure QT is an excellent toolkit, probably even easier to use, judging by the quality of KDE 2. But I believe there are licensing costs if you want to use it with Win32.
There are more (too many?) portable GUI toolkits than mentioned here.
See
http://www.atai.org/guitool/
for a complete list, showing the supported platforms.
Quiet a few may be sufficient for the GUI of a word processor or
document processor, if you are willing to avoid using nifty features
unique to a platform.
I think you are right. 'Portable', apps are hard to write, hard to
maintain, and do nothing to improve the quality of the code. They often
reduce it in fact! This is because most people take the #ifdef approach
to portability which naturaly leads to ugly code.
The 'theory' that portable apps (system wise) are better stems from the
implicit assumption that the path to portability is through removing
non-standard problem areas and focusing on well understood standard
APIs. It should be immediately clear that adding long conditional code
paths immediately jacks up the complexity and kills testability.
IMHO portability among widget set (code that is widget set agnostic)
should be reserved for applications that desperately need to do that for
some reason (and even then, Java is a legitimate response) - the
alternative is often alot of effort
expended, and worthwhile shortcuts and features are ignored because they
are not portable. In this case, building a reliable non-GUI core
component. is often very hard, - and efficiently interfacing them is
also tricky. Choosing to focus on the right components to be non-GUI
will speed development and result in fewer layers of abstraction (ie
simpler more robust code).
As far as widget sets go, IMHO the two major ones should work really
hard to be largely seemless as far as the user goes - I hope the effort
of building seperate implementations will result in APIs that better
reflect their language segments rather than something like the hack that
is MFC/OWL.
For System APIs the answer is clear - say NO to non-SUS and non-C99
environments. Write code that conforms to those APIs and punish those
systems without by creating a compatibility layer if necessary. That is
the only way we as developers can force these standards to be adopted
quickly.
Concentrate on writing a stable and useful base system, with a
refined API.
Encourage users/programmers to write GUIs in the toolkit of their
choice.
This seems to have worked fairly well for things like MP3 players
and CD-burner software. It would be a lot more difficult for something
like a wordprocesser, though.
mrorganic wrote:
The problem here I think is one of background: Unix developers are
constitutionally incapable of consensus. It doesn't surprise me that
there was no consensus on a common GUI API -- over the thirty years Unix
has been around, there was no consensus on something as fundamental as a
filesystem or C library!
Claiming that this is a unix problem is to hide from reality. This
kind of problem exist everywhere where people have the means to say and
decide what they want (like countries with democracy). Of course the
windows world don't have this problem, as the dark side decides
for everyone what to do. In a similar manner, a dictator may rule a
country much
better than a democracy due to "consensus" being achieved.
Consensus prevents development. Given that you mock every sheep
into one single way of thinking and designing, you won't get as much
inventions and new ways of doing things. Yes you get similarly behaving
programs, but the dark side has proven this point as well if I was
to tell.
As you say, this is inflicted on ourselves. We choose to do this,
this is not something someone else have done to us. "You're all
different" (Life of Brian - Monty Python). Very often, having a
multitude of options better suits a large crowd since different people
have different needs, philosophies and needs. That's why we stay away
from the dark side, in the light sunshine of options.
One of the things that I've observed about it is that portability does
and with 100% accuracy, always favor languages rather than
environments, toolkits & libraries. Take for example: C, C++,
Bash, Sed, AWK, Perl and other languages. They seem to have one thing
in common
in terms of portability and that is they can easily be ported to other
platforms. One good reason why languages have this advantage is because
of this simple thing: they're basically symbol processors. They operate
on the lowest common denominator. Moreover, they play nicely with
tokens and grammars which is basically found on all platforms.
I for one is an advocate of pushing the envelope of a language, or even
the creation of new languages, rather than adding feature upon feature
on top of existing environments, toolkits and libraries simply because
languages are much better to handle. On the other hand, environments
and toolkits like <insert name here> will surely take the path of
greater resistance when portability becomes a requirement. Plus,
environments, toolkits and libraries depend on the operating system
services which make it even harder for programmers to port.
Bottomline here is that you have a good point about toolkit portability
as they tend to be effective only on a subset of platforms.
I'm busy rewriting rCalc in
C++, and I've found that the OO way of designing programs goes a long
way to help you make applications portable.
rCalc is a calculator, and the program is split into a GUI and a
calculation engine. The GUI calls the calculation engine all the time,
so the GUI can be chopped and changed -- as Dacta said,
I'll probably try and find a KDE developer to port the GUI.
Here is where the problems start: GNOME isn't just a GUI. I've been
using several of the low-level APIs to handle, for example,
internationalisation and persistant storage. Since I'm using OO,
however, I can write simple, abstract classes, for example ProfileReader
and ProfileWriter, which the calculation engine can use to load and save
data to disk. I then derive classes like GnomeProfileReader and
GnomeProfileWriter which are instantiated from the GNOME GUI and passed
to the calculation engine. Presumably KDE has a similar facility for
storing persistant configuration data, so whoever writes the KDE GUI can
also make classes like KdeProfileReader and KdeProfileWriter - the
calculation engine is unchanged.
This moves the portability issues into the Makefile, leaving lots of
lovely yummy #ifdef-free code.
I am probably not the only one to have noticed this, but
badger's comment made me think about this again.
About two years ago, Windows people were telling me how horrible and
chaotic an environment I had, with GTK+ apps, Athena, Motif and apps
using other widget sets were shown at the same time on my screen.
They said that the unified widget set of Win32 made all their
applications look and behave in similar ways, which was a Good Thing.
Then I showed them FreeAmp (before x11amp/XMMS became popular), and how
nifty of an interface it had, with its shaped windows and all. They
dismissed it as a bad GUI which was not very intuitive and was difficult
to navigate.
Now, I do not use Windows PC regularly, but recently I went to one
co-worker PC to listen to some music, a high-end Dell machine running
Windows 2000, and I couldn't help but notice how much the very "modern"
Sonique MP3 player looked a freakin' lot like my FreeAmp of many years
ago. That same FreeAmp Windows people dismissed.
And it wouldn't stop there. I'd say that at least half of its
applications are using non-Win32-standard widgets, some in minor ways
(newer Microsoft applications for example) and others in more major ways
(Winamp, Sonique, and others).
Now I'd love to corner one Win32 bigot: he'd have to admit one of two
things. Either,
- Linux lead the way to the future, did the "innovation" and Windows
only followed later on, or
- Windows is joining Linux to GUI hell.
I don't know if I might survive such a discussion, either from me dying
of laughter or from receiving schrapnel of Win32 bigot exploding from
the paradox. ;-)
dirtyrat: What you describe has common grounds with
what XPLC is about, except
that with XPLC, it can either be decided in the Makefile or at
runtime, by the user or administrator. Isn't that great? :-)
Thank you for englightement, badger, and showing
us the only true way.
Now I know that FreeAmp, a copy of WinAmp, was innovative. And it
continues to innovate. On my Fujitsu Laptop it cannot produce a decent
sound under Linux staying way ahead of WinAmp under Windows which
actually produces a sound I can listen to without a headache.
I agree that Unix has a history of continuing innovation. X-
Windows, for example, belongs straight to Guiness book for being
the most bloated and unusable GUI on the planet. 10+ years and still
counting. We shouldn't forget about X-lib, the most masochistic GUI
library in the Universe. And when people thought that you can't produce
even bigger crap X-Windows programmers gave us Motif. Let's not dismiss
important innovation in "how to make the most unusable copy&paste
operations" department and "we know no one makes this 3-button mouses
any more but we came up with this innovative idea of pressing both
mouse buttons to simulate the third. After 10 years of practice we
found this to be real easy. It's time to innovate again". I've heard
that they added scalable fonts to X-Windows lately. Woo-hoo!
Now die laughing. Please.
LyX and GUI-I, posted 22 Dec 2000 at 00:29 UTC by movement »
(Master)
I've been working on the Qt/KDE frontend to LyX, and in fact started
the thread mrorganic refers to.
First, it did not de-generate into "advocacy" issues. I can't
recall a single point where someone said "you should use X toolkit
because it's better than Y". mrorganic seems to badly
mis-understand Matthias' point - not that "Qt roolz", but that the best
thing for LyX is to concentrate on a straight port, rather than head
for some kind of GUI independence. I can understand where he's coming
from, but the fact remains that a separation of the frontend code can
only be a good thing for the health of LyX's source code. I think this
is definitely a good decision.
Second, I find it quite odd that mrorganic seems to
equate a GUI-I design with instability and LCD designs. I suggest he
actually takes a look at the code in, say, a year's time, and compare it
with the non GUI-I code, and ask himself which is more complex. I suspect
he will find the new code a lot more readable and sane than the old.
I should point out that LyX has *not* implemented anything approaching
XUL, and it never will. Such a thing is a huge undertaking, as is
evidenced by the current unusable status of Mozilla.
And I really must take issue with mrorganic's
claim that (and I quote) "Theory tells me that writing portable code
should lead to better code, but experience has shown decisively
otherwise". I would be very interested for him to give an example where
non-portability has had a beneficial effect on a project's source code.
egnor: I agree completely.
atai: most portable GUI toolkits do have a severe
LCD problem (as I mentioned, LyX isn't doing that). Apart from the
Mac issue, I can't think of a good reason to not use either Gtk+ or Qt.
jgg: your argument makes no sense. You are saying that
portability has no benefit because people attempt to go about it in ugly
ways (such as liberal #ifdefness) ? Sure, and comments are pointless
because people write stupid comments ...
And yet at the same time, you advocate targetting towards standardised
platforms. No-one ever said that compatibility with 1982 UNIX was a good
idea.
Dacta: I hope you are aware LyX isn't a word processor
;)
kjk: I had hoped trolls of your low calibre weren't
around here.
egnor has said everything I want to say about choice and
diversity. In terms of LyX, the new approach is a hugely good idea, if
only because it cleans up the code. A separation of Model and View/
Controller is always a good idea in GUI application code, and in LyX's
case, GUI Independence is only a few small steps further.
To movement:
You (and many others) seem to miss the point I'm making entirely. The
question is only peripherally about "freedom" -- the point is stability
and maintainability. The poster-child for the failure of the cross-
platform model has to be Mozilla (there's an example for you!): the
development time and bug-count are exponentially larger than they would
have been had Mozilla targeted a single platform API. AbiWord (as much
as I like and respect those guys) is another example where stability
has suffered due to cross-platform GUI support.
As software becomes more and more mission-critical, it becomes less and
less portable: most embedded software tends to be written very close to
the hardware, and even software for critical environments (as eg
medical monitoring software or air-traffic control software) tends to
be *extremely* non-portable. I'm not saying this is a good thing
(necessarily), just that it is necessary for stability.
Note that I'm not saying that *all* portable software is unstable --
Berkeley DB is a good example of portable software that is also very
stable. But when you throw GUIs and widget toolkits into the equation,
things go to hell very quickly.
The "theory" I'm familiar with is that writing portable code makes
for more robust software because it makes you more aware of your
assumptions and gets you think more clearly about how exactly you're
doing things. For example, if you're writing endian-independent code
it's harder to make off-by-one errors because you're thinking harder
about where each byte goes and in a sense trying the code from two
different directions at once.
This is a distinct thing from API portability, and I think that's
where the confusion comes from. Of course the principle
applies somewhat, helping with design as you're aware of more than one
way things
can be done. But unlike the endianness example where you can just
rewrite things in a (slightly longer) way that works everywhere,
supporting multiple APIs means implementing the same functionality
multiple times. That makes for a lot more work.
If, as has been suggested, you factor things cleanly and use OO
principles (rather than, say, #ifdef forests) you can at least
localize the additional complexity in an interface. But (particularly
until that interface is stable) it doesn't reduce the complexity of
testing, and "works for me" doesn't go so far. Crystalspace is a good
example, where despite good modular design, only a couple of the
supported platforms work on any given day.
The title wasn't meant to be perjorative. Cruft of course depends on
what you've decided is worth supporting and interests differ.There's
always a tradoff between supporting more platforms and simplifying your
implementation.
Xlib, posted 25 Dec 2000 at 17:50 UTC by sneakums »
(Journeyer)
Xlib is not a GUI library. It is a fairly direct C binding to the X
protocol with some nice utilities thrown in. Expecting anything else
will lead to pain and disappointment.
The big mistake people always seem to make when writing portable
programs is that they don't put in the portability at the right
level.
It seems to be impossible to make a portable user interface layer. In
every program I've ever seen that tried this, you ended up with a
lowest-common-denominator ugly interface that looked okay on, at best,
one of the supported platforms. On all other platforms, it looked
basically like it looked on its "good" platform. All the Windows
programs now being ported to Linux via winelib will look like Windows
apps no matter what, Mozilla looks equally ugly and non-native on all
platforms, and Java... well, the closest they come to "Native widgets"
is having Windows-looking buttons on Windows and Motif-looking buttons
on Unix. Likewise with Tcl/Tk. That's not portability, and it
certainly doesn't result in well-tuned, easy-to-use programs.
Internet Explorer is an example of how efficiently you can program when
you're writing platform-specific code. Microsoft produced (and
continues to produce) IE very fast and it's actually very stable,
at least when compared to any version of Netscape. Pity it crashes the
whole OS when it dies, though.
Netscape, until the Mozilla project, used to have totally duplicated
(and, irrelevantly to this discussion, also very bad) code for the UI on
Mac, Windows, and various forms of Unix. But at least it looked native
-- Mozilla has much less UI-specific code, and now the UI is visibly
non-native slower on all platforms.
The correct place for abstraction is between the "functional" layer
(which often can be completely portable, as long as the underlying
system is mostly POSIX and ANSI C/C++) and the "interface" layer (which
should be system-dependent if you want a UI that users actually like).
The nice thing is, in most programs the interface layer is the easy
part. Look at ghostview, gv, kgv, and the Gnome equivalent whose name I
don't know. All of them use ghostscript, unchanged, as the
functionality part, and write their own UI around it. It would be
pointless to try to merge all four programs into the same source,
because they've already been factored into their smallest functional
components. If you tried to abstract them at a different level, you
wouldn't be able to take advantage of xaw, Qt, or GTK widgets like you
should. IMHO, ghostscript, gv, and kgv are at least 90% not
duplicated code. They contain the code that's necessary to do what you
want, using the native widget set.
In my opinion, tasks like mail reading, network access, html rendering,
file management, image manipulation, and so on should all be in nice,
portable libraries or subprograms. If you do this, it becomes almost
trivial to write the user interface parts -- that is, except for the
time-consuming usability testing and tweaking, steps which almost
everyone using a "portable widget set" skip anyway.
As for writing a word processor in a widget set-independent way, you're
basically out of luck -- almost all of the "hard" stuff in writing a WP
is the UI tweaking. It matters very much what happens which menu items
appear when you click on the File or Help menus, and users of different
widget sets expect different things. Therefore, there needs to be a lot
of different code for each widget set, or you'll never achieve
ease-of-use. That said, standard (HTML?) renderers, standard file
access routines, and standard network libraries across all the UI ports
will definitely make it easier.
Sorry about the long rant. I've worked on several "portable UI"
projects before, I'm still waiting for a good Unix web browser, and the
ever-increasing number of HTTP client implementations on my system is
starting to get upsetting. I've written at least two of them myself...
apenwarr: I agree
portability at the right level is vital. Most
of the examples you present make sense (although, it
is well-acknowledged that the finest version of MS IE
is on a Mac platform - how do you explain
that ?).
The system you describe is pretty much what we are
planning for LyX. I think it might even be possible
to link the frontend at run-time, though I'm no expert
on dynamic libraries etc.
I've heard nothing but good things about Gecko. In what
way does this not satisfy your requirement for a decent
browser component ?
gecko and MSIE, posted 29 Dec 2000 at 08:27 UTC by apenwarr »
(Master)
movement: As for MSIE/Mac, I think it's widely agreed that the
most
standards-compliant version of IE is the Mac version. (It still
crashes all the time and doesn't render pages the same way as IE/Windows
or Netscape, so "highest quality" depends on your point of view.)
That's probably just because they rewrote it from scratch more recently
so it's newer. Interestingly for this discussion, Microsoft didn't
port IE to the Mac -- they rewrote it. And they did it with a
rather small team of developers, really fast.
As for Gecko: it's only problem might be that it's drowning in
the rest of the Mozilla project. It lacks documentation, and it's
apparently a lot of work to extract or build separately from all the
stuff I don't want. It's not particularly
extensible except perhaps with Javascript or by hacking the source.
(Look at Konqueror to see what people want to extend their HTML
widget to do... I guess they figured it was easier to write a new one
from scratch.)
Galeon, last I checked, wasn't a good enough UI to really be
useable, though I agree it's way faster than Mozilla and the renderer
works just as well, so it has a lot of potential.
Also, it's completely impossible to use native widgets in Gecko, and if
you look at the Mozilla mailing lists and documents, that was a design
goal -- to make it easier on the web designer. That makes sense, but
you
get the same ugly, user-unfriendly buttons, checkboxes, and radio
buttons on every platform, and they don't look right anywhere.
They also don't hold a candle to the same widgets in any of Qt, GTK,
Mac, or Windows, which all have had a lot more thought put into them.
(FWIW, the Mozilla widgets have improved dramatically in recent months,
but it's the tweaking that makes the difference, and it will take
many more months to even begin to approach the quality control in GTK
widgets, let alone Mac ones.)
Gee, I'm usually a big portability geek, because I often see people
doing obviously silly things like assuming the size of 'int' or writing
their own mouse code instead of using gpm, and that sort of thing can be
easily fixed. Big, complex UI stuff is hard to do portably, though, so
I tend to advocate against it.
Microsoft always makes a great portability counterexample, though I
guess assuming the size of 'int' backfired on them too :)