Applications and the Difficulties of Portability?
insane_coder asks: "I'm a software developer who writes a lot of freeware utilities in C/C++ which are all cross platform and work well. Lately some of my users have been pestering me to stop wasting precious development time supporting minority OSs like Linux, and get more work done for the majority — the Windows users. Now all of my utilities are simple tools that perform various operations on files such as compression or rearranging. I've also made a few frontends for them using the excellent Qt library to allow the user to select a file and process using a simple GUI. In the dozens of applications I wrote, most of them several thousand lines long, I haven't written a single conditional for any particular OS. When I release, I just compile each app for all the OSs I have access to and post them on my website. I barely expend any effort at all to achieve portability. So the question I have to ask is: Why do the masses perceive portability as something that requires effort and a waste of time?"
"Most applications don't do anything fancy or need to talk to devices and therefor there is no need to do anything special other than compile them on a particular OS to run on that OS. So why are there so many simple apps using native APIs to do simple things like file reading instead of the standard ones? Why are we projecting an image that one must go out of their way or switch to a different language in order to achieve portability?"
For the most part, portability isn't hard. You can write pretty much all the functionality of your software without getting into platform-specific issues. Generally, the higher the level of abstraction a languages is at (assembly C Python), the easier it gets. Of course, you do have to use standard APIs and avoid platform-specific ones (win32, GNU extensions, etc.) Things that have caused trouble for me in the past:
...
- Sockets (BSD sockets vs. Winsock's almost-compatible variant); this is not a problem in most higher level languages
- GUIs (there isn't really a standard; perhaps wxWidgets?)
- Threads (POSIX threads vs. whatever Windows has)
- Processes (fork, AFAIK, really doesn't exist on Windows)
If I need any functionality that isn't readily portable, I usually target POSIX or BSD, which makes my code portable to many *nix variants, and Windows using Cygwin.
Of course, there are also a whole bunch of cross-platform libraries out there, like glib, the APR, SDL, Qt,
Please correct me if I got my facts wrong.
Have you taken a look at Qt recently? If I'm understanding your example correctly, that's fairly trivial in the Qt 4.x series as well. You can even customize them with CSS-like stylesheets.
Remember RFC 873!
Caveat: If your app is command-line, then this isn't really an issue. (Well, it still sort-of is, in that DOS CLI apps have different mechanisms for help than Unix ones, but we'll ignore those details.)
The reason cross-platform is hard is because GUIs behave very differently from each other. To be a "correct" Mac OS program, you must support:
1) AppleScript, at least the bare minimum actions.
2) The Services menu. Many ported apps don't have it.
3) The integrated spell checker. Most ported apps don't have it. Including biggies like Microsoft Office. (Needless-to-say, Firefox also doesn't support the integrated spell checker.)
4) Verb dialog boxes. That is, no "yes/no" questions in dialogs, they must all be "Save" "Don't Save" (or similar.) In addition, the location of Ok and Cancel are different in different OSes.
5) Drag&Drop, another simple feature the majority of ported apps get wrong. (Note: this includes drag&drop text editing as well as dragging snippets to the desktop.)
6) Mac-like edit boxes. Here's an example ported apps almost always get wrong: if your cursor is at the bottom line, but in the middle of the text, and you hit the down arrow the cursor should move to the end of the bottom line. On Windows, it should do nothing. On Linux... well I have no clue if Linux has any standards for arrow behavior in edit boxes. (Firefox gets this wrong also, as do many, many apps.)
7) Standard Mac menu shortcuts. This is pretty easy since other OSes ripped-off most of Apple's shortcuts anyway.
8) Being responsive to sleep, hibernate and shut down requests from the OS. Every time I see OS X telling me that shutdown was cancelled because of some mis-behaving app I want to scream.
9) Not relying on any absolute paths other than those defined by the OS. Lot of apps get this wrong.
10) Using Apple's color picker, font picker, "Special Characters" picker, etc instead of your own. Many apps get this wrong.
I'm probably missing items on this list. In addition, Windows has items on its list different from the Macintosh list. (For instance, coping with Active Directory, having an installer.)
I can guarantee that your cross-platform framework gets at most half of these things right. The Java VM gets basically none of them right. Firefox gets like 3 of them right. The reason you think cross-platform development is easy is one or more of the following:
1) You don't bother to QA your product on Mac/Windows/whatever. (This is the most likely.)
2) Your programs have trivial GUIs and/or you don't give a whit about the quality of the GUI.
3) Your programs are CLIs and have no GUI at all. (Note that if this is the case, they're still probably wrong on DOS, which is quite different from Unix CLIs.)
Tell you what, the instant I see a single ported app to Mac OS X that actually looks and behaves like an OS X app, I'll eat my words and agree with you. But I don't think that'll happen.
Comment of the year
I think you sent that as "HTML formatted" -- which gave me one big line of unreadable-ness. I haven't actually read it yet, I'll respond in a minute. Here's how I think it's supposed to look:
Basically, some people will say things like "Portability issues only happpen on Windows because of the use of Windows specific API.... and Linux somehow magically escapes this problem."
I'm sure you are already aware that it is not true, because your code is portable and uses readily available libraries that do not vary in version, or in any major way at all from OS to OS.
A buch of other people will say "All, code should be portable, because there is no reason for it to not be portable."
And, I'm sure that from your post, this is the reasoning behind your question.
So, here is a list of reasons that might help formulate an understanding of why some code is not portable... (bear in mind that a lot of my code is portable too, as that is usually indicative of good software practice)
* Less portable code makes heavy use of API that is already written and tested inside the OS.
* Less portable code can therefore be less expensive and quicker to produce. Depending on the circumstance this can be a long term and/or short term benefit.
* Less portable code can be made to execute faster than portable code
* Less portable code can be made to take advantage of hardware features that are only exposed through a specific API
* Typically the most popular OS in the world is easier to program for by most programmers, thereby allowing everyone that is hired to get up to speed on the project more quickly. (Not a concern for a team of one)
* Typically large projects need to make every advantage in efficiency that is readily available. This might or might not be dependant on the OS
* Anything that has to do a lot of work with filesystems will need operating system dependant code to be written. There are faster file operation system calls for each specific OS.
* Less portable code can be made smaller in size, by depending on libraries that are only available on a target OS. (As long as they are actually there!!!)
For example in Windows you can take advantage of a bunch of API to change system settings like IIS settings, and smtp settings.
In Linux you have to write code to manually change text files. Of course API are better here because then there is less chance messing up the format of the text file. And your code will work in the next version of the OS too. Your code will not work in the next version if you change the config files manually. In your case, you don't care because you are just writing little free utilities. In bigger enterprise level applications you need to care about things like this. There are many examples of needing to use API where-ever possible. More experience with bigger applications is the best way to get to this knowledge.
Also, one final note. C is getting to be an old language now, and it is sad that any code written in C is not portable. Things that have been around that long, have workaround after workaround to make them keep from breaking. It almost requires effort to write C code that is not portable nowadays. Bad C code is still prevelant though. This is mostly due to the #define conditional that was included to make C a lasting language. It worked. Now let's be done with it.
Moving forward, I would suggest a language that makes use of garbage collection as your next choice. Also, one with clean syntax and no workarounds already in place would be a good plan. These criterea make for a langauge that is more difficult to write stupid code in. If you ever have to maintain code, then these are good considerations.
Here are some examples (in no specific oreder)
Java, C#, PHP
Here is a bad example
C++
Don't thank God, thank a doctor!
The POSIX subsystem is used by nothing but Services for Unix, and SfU applications cannot use native Win32 functions.
In many languages, notably including both C and C++, line endings are always "\n". Even on Windows. All you have to do to make your application portable to Windows is make sure you open text files in text mode, and not in binary mode. The standard library will then make sure to change line endings as necessary if they are not externally represented the same.
It's Posix-compliant at the most minimal level. When Microsoft designed the subsystem, it had one goal: be able to check off the "Posix compliant" item on the government purchasing checklist. It did not want Posix apps developed, because that would be against Microsoft's business interests, but it needed that compliance to technically qualify for government contracts. So it implemented the absolute minimum it had to to get the minimal certification and no more. And minimal Posix compliance is minimal indeed, being aimed at embedded devices.
Might it be this one: Rapid Development by Steve McConnell?
I remember that story quite vividly as well: "When doing market research, we realized that mediocre people didn't want a real C++ compiler, they just wanted C++ on the box and *.cpp file extensions so they could bill themselves out ($$$) as C++ programmers. We then spent the next 5 years fixing all of our dork-isms in the C++ compiler to bring it up to standards, but that didn't matter because we had already crushed our competition by making flashy-promises and code wizards and being first to market with a non-compliant compiler." (or something to that effect).
--Robert