Write Portable Code
Simon P. Chappell writes "Much as a certain large software company located in the North-West of the United States of America might wish otherwise, there are many different operating systems and platforms in use in the world today. Software these days needs to able to operate in a disparate environment, either by communicating with these other platforms or by running on them or, increasingly, doing both. The Information Systems industry is making good progress with the communication half of the problem (even if a lot of it seems to involve large amounts of XML), but it is still struggling with the issues inherent with writing portable code. Brian Hook's contribution to all of this is Write Portable Code , which according to it's subtitle is an introduction to developing software for multiple platforms." Read on for the rest of Simon's review.
Write Portable Code
author
Brian Hook
pages
248 (14 page index)
publisher
No Starch Press
rating
8/10
reviewer
Simon P. Chappell
ISBN
1593270569
summary
I recommend this book to anyone working with portable code.
This is a book for computer programmers who write software designed to run on multiple platforms. It's also for programmers who suspect that their software may need to run on different platforms. This brings the book onto the radar for free and open source software authors, as they seek to create software that does not trap their end users into using specific operating systems. The Structure
There is a good progression shown in the eighteen chapters of the book. The first couple of chapters introduce the reader to portability concepts and then to some of the specific portability features of ANSI C and C++ that are used throughout the rest of the book.
The middle chapters of the book, cover individual portability topics. Some of these topics are the obvious ones, like Floating Point numbers, Networking, Operating System, File System and Dynamic Libraries. Other topics are less intuitively associated with portability, but when you read the chapter, it's inclusion is both obvious and necessary. These subjects include Source Code Management, Compilers, Scalability and Data. There is more to portability than many of us might suspect.
The last two chapters look at some alternative ways of getting portability. Scripting languages are discussed and the pros and cons of each ones portability is weighed. Lastly the use of cross-platform libraries and toolkits is addressed. Quite apropos given that the book's author is also the author of a cross platform library.
As an example of the thoughtful approach taken in this book, lets' take a look at the chapter on scripting languages. It's about the shortest chapter in the book, but representative of the approach that Mr. Hook brings to his work. This chapter takes a very honest look at the portability and cross-platform aspects of using scripting languages. There are advantages and disadvantages to the use of scripting languages. The advantages include everything that is a disadvantage of low-level languages like C/C++. Scripting languages do not require you to worry about about memory allocation, bindings, System API calls or any of the other bugbears of a low-level language programmer's life. The disadvantages of scripting languages naturally include performance, given their interpreted natures, a general lack of tools, such as development environments or IDEs and their tendency to sit high above the operating system with a corresponding detachment from low-level facilities and services of that same operating system. Mr. Hook's choice of scripting languages to consider was interesting. I expected Ruby and Python; both popular and capable in their own right. The inclusion of JavaScript/ECMAScript was also not too unexpected, now that standalone versions are bubbling up and becoming available. The real surprise, albeit a pleasant one, was the inclusion of Lua; a scripting language designed for platform portability and which seems to have managed to fully mature without making a blip on most geeks radar screens.
I like that Mr. Hook has experience writing portable software. This matched with his authorship of the Portable Open Source Harness (POSH) portability library and his contributions to the Simple Audio Library (SAL) gives a great deal of credence to his writing.
This is a solid "doing" book. Mr. Hook is under no illusion that he's writing an introduction to programming. This book has a consistent purpose to take experienced programmers and fully equip them to deal with portability and it does not deviate from this in the slightest.
The layout of the book is first rate, with clear typography, comfortable spacing, clear diagrams and tables and nicely highlighted callouts. I did not notice any obvious typos or glitches in the book. While the look of a book is not the author's fault if it is below par, a well presented book can enhance the reading and learning experience.
The examples are as realistic as possible. While some of the examples to teach principles might be simpler, they are typically backed up with examples from either the POSH or SAL projects, showing real world portability coding. The level of C/C++ required to understand the examples is higher than many books that I've read. That's not to say that the code seems obfuscated, but it's code that is taking into account aspects of the real world and is, by necessity, not simple. A further positive quality of the code examples is that they're very well explained; well enough that an inexperienced programmer with determination could follow them and come to an understanding.
Appendix B contains a summary of all of the portability rules presented through the book. There are twenty rules and each is reprised with a small explanation/reminder of it's application. An example: Rule 4 - "Never read or write structures monolithically from or to memory. Always read and write structures one element at a time, so that endian, alignment, and size differences are factored out."
If you're looking for more of a fluffy "about" book, then this is not it. This is not a complaint, rather I offer it as something to consider, before you buy what you might otherwise think is a beginner's book.
I must reiterate the non-trivial C/C++ example code the book contains. This book is for serious programmers and is not afraid to role up it's sleeves and cut real code.
This is a very well written and very readable book. There are many aspects to the subject matter of portability and Mr. Hook addresses more of them than many of us had previously suspected existed and addresses them with firm authority. I recommend this book to anyone working with portable code."
You can purchase Write Portable Code from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
This is a book for computer programmers who write software designed to run on multiple platforms. It's also for programmers who suspect that their software may need to run on different platforms. This brings the book onto the radar for free and open source software authors, as they seek to create software that does not trap their end users into using specific operating systems. The Structure
There is a good progression shown in the eighteen chapters of the book. The first couple of chapters introduce the reader to portability concepts and then to some of the specific portability features of ANSI C and C++ that are used throughout the rest of the book.
The middle chapters of the book, cover individual portability topics. Some of these topics are the obvious ones, like Floating Point numbers, Networking, Operating System, File System and Dynamic Libraries. Other topics are less intuitively associated with portability, but when you read the chapter, it's inclusion is both obvious and necessary. These subjects include Source Code Management, Compilers, Scalability and Data. There is more to portability than many of us might suspect.
The last two chapters look at some alternative ways of getting portability. Scripting languages are discussed and the pros and cons of each ones portability is weighed. Lastly the use of cross-platform libraries and toolkits is addressed. Quite apropos given that the book's author is also the author of a cross platform library.
As an example of the thoughtful approach taken in this book, lets' take a look at the chapter on scripting languages. It's about the shortest chapter in the book, but representative of the approach that Mr. Hook brings to his work. This chapter takes a very honest look at the portability and cross-platform aspects of using scripting languages. There are advantages and disadvantages to the use of scripting languages. The advantages include everything that is a disadvantage of low-level languages like C/C++. Scripting languages do not require you to worry about about memory allocation, bindings, System API calls or any of the other bugbears of a low-level language programmer's life. The disadvantages of scripting languages naturally include performance, given their interpreted natures, a general lack of tools, such as development environments or IDEs and their tendency to sit high above the operating system with a corresponding detachment from low-level facilities and services of that same operating system. Mr. Hook's choice of scripting languages to consider was interesting. I expected Ruby and Python; both popular and capable in their own right. The inclusion of JavaScript/ECMAScript was also not too unexpected, now that standalone versions are bubbling up and becoming available. The real surprise, albeit a pleasant one, was the inclusion of Lua; a scripting language designed for platform portability and which seems to have managed to fully mature without making a blip on most geeks radar screens.
I like that Mr. Hook has experience writing portable software. This matched with his authorship of the Portable Open Source Harness (POSH) portability library and his contributions to the Simple Audio Library (SAL) gives a great deal of credence to his writing.
This is a solid "doing" book. Mr. Hook is under no illusion that he's writing an introduction to programming. This book has a consistent purpose to take experienced programmers and fully equip them to deal with portability and it does not deviate from this in the slightest.
The layout of the book is first rate, with clear typography, comfortable spacing, clear diagrams and tables and nicely highlighted callouts. I did not notice any obvious typos or glitches in the book. While the look of a book is not the author's fault if it is below par, a well presented book can enhance the reading and learning experience.
The examples are as realistic as possible. While some of the examples to teach principles might be simpler, they are typically backed up with examples from either the POSH or SAL projects, showing real world portability coding. The level of C/C++ required to understand the examples is higher than many books that I've read. That's not to say that the code seems obfuscated, but it's code that is taking into account aspects of the real world and is, by necessity, not simple. A further positive quality of the code examples is that they're very well explained; well enough that an inexperienced programmer with determination could follow them and come to an understanding.
Appendix B contains a summary of all of the portability rules presented through the book. There are twenty rules and each is reprised with a small explanation/reminder of it's application. An example: Rule 4 - "Never read or write structures monolithically from or to memory. Always read and write structures one element at a time, so that endian, alignment, and size differences are factored out."
If you're looking for more of a fluffy "about" book, then this is not it. This is not a complaint, rather I offer it as something to consider, before you buy what you might otherwise think is a beginner's book.
I must reiterate the non-trivial C/C++ example code the book contains. This book is for serious programmers and is not afraid to role up it's sleeves and cut real code.
This is a very well written and very readable book. There are many aspects to the subject matter of portability and Mr. Hook addresses more of them than many of us had previously suspected existed and addresses them with firm authority. I recommend this book to anyone working with portable code."
You can purchase Write Portable Code from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Truly portable code is like flipping someone the bird.
No matter what country (OS) you're working in, everyone understands it!
Thank the ghods for the USB memory keyfob!
moderation suggestions:
+1 funny -1 offtop +1 informative -1 flamebait
Hey, just write whatever it is in Java. You know, "write once, run anywhere". Simple!!!
Yes, this is a joke.
And only use '0's. I've found using '1's just leads to too many problems.
and this is why web applications are becoming so popular...it's much easier to make something written in PHP and distributed through the web available to everyone than to try to port something in C++ across a bunch of platforms. imho this trend towards AJAX and more web applications is a good thing and makes it easier on developers trying to deal with clients on multiple platforms. i don't want to have to deal with porting applications (although cross-browser compatibilities offer their own complications).
What? Are you telling me that the OS I've been developing won't run on Windows, Linux, and OS X?
Whad` up wit` dat, fool?
Yeah, total flamebait. If your only solution to writing cross-platform code is by writing everything for a runtime environment, you have a thing or two to learn, there, fella.
1. #include
2. Learn to love the ANSI standadrd library
3. Learn that open,read,write,close are available on all systems.
4. #include for htonl/htons
5. Profit
Cross platform as long as it's Windows or *nix. How about zSeries, iSeries, HP NonStop, etc.
How can I write portable versions of Mac OS X apps when the Cocoa API doesn't exist outside of Mac OS X (don't tell me about YellowBox or what-have-you) and the language Objective C isn't supported outside of Mac OS X (Apple is killing off Cocoa's Java support)? Oh, and the Carbon API doesn't exist outside of Mac OS X either (but at least it uses a widely supported language). You mentioned a software company in the Northwest US, but what about the one in Cupertino? Apps written to their platform are no more portable than Windows apps.
Besides that, apps that aren't able to take advantave of the underlying platform's unique features aren't sellable. Mac users in particular want apps that take advantage of the unique features of Mac OS X (and no, they don't consider some unix app to be a real "Mac" app, and rightly so). That means Cocoa or Carbon, and neither api is supported outside of Mac OS X.
-- "I never gave these stories much credence." - HAL 9000
"It was horrible! There were 1's and 0's everywhere! And I think I saw a 2!"
the preceding comment is my own and in no way reflects the opinion of the Joint Chiefs of Staff
I'm willing to bet that (unless you're is some really niche market) it is totally un-profitable to write software for anything other than Windows. The amount of effort you spend on making it portable, is not worth the extra chump-change you get.
I write simulations with GUI's in C++ exclusively and I develop in both Linux and XP (depends on the customer as to the final platform, but I code on both depening on where I am). Its easy to do c++ cross-platform. The only difference is I type "make" on the Linux box and "nmake" on the Windows box :P
hint: use standard C++ calls, don't get locked in to vendor-specific functions, use cross-platform libraries for the rest (opengl, xerces, etc.)
-everphilski-
"as a certain large software company located in the North-West of the United States of America might wish otherwise, there are many different operating systems and platforms in use in the world today. "
If his first sentence isn't trolling I don't know what is. Why is it ok to do it against MS, but nobody else?
You do it against MS, you make the front page, against apple you get flamed.
I did RTFA but haven't RTFB. I appears it is oriented toward non-UI intensive modules. Java, as others mentioned, handles the UI stuff quite well. The GNU build utilities help a lot if it's a *NIX system, but most true portability problems require more OS's.
yeah, but it's too slow (anectodatal evidence that invoking an assembly language routine "runs just as fast as c" is not proof ... c'mon java fans : think! )
Name me a program that runs under java. I mean that everybody knows about.
That's right, there are none.
I got my first job and started digging into some code that was written for portability, it all seemed so obfuscated.
I was like, "Why are they #defining all their data types to something else? And what's with all the crazy compiler directives?" It seemed like they were going out of their way to make the code less readable.
Once I figured out that it was all there so that the code could be recompiled for different platforms, it all clicked together. It's really cool, and I'm pissed that I got out of college not knowing this stuff. It should be a required course, IMHO.
"If you haven't ported your code, it isn't portable."
Sticking to the libraries and (subsets of) languages that are really portable helps, too, like this book appears to cover, but if you just start off on a small mix of platforms, it becomes usually quite trivial to port to others. My Ostiary program runs on (at least) Linux, *BSD, OSX, Solaris, HP-UX, AIX, Tru64, IRIX, and Cygwin. I've written commercial code that runs on all of those plus Windows, NetWare, and OpenVMS, though that requires a few more #ifdefs.
PHEM - party like it's 1997-2003!
are done w/ J2SE using SWT as the front end. Looks like a native app, runs super fast since it relies on native widgets, and portability issues are largely mitigated for me.
Is this the same Brian Hook that previously worked at id software??
Come on, we have to know.
Java doesn't run everywhere: For instance, there is no Java JVM for a Palm. C/C++ programs that started elsewhere have been ported to Palm, on occasion.
It's a bit of an extreme case, I admit, but...
'Sensible' is a curse word.
let me guess. There must be a chapter that describes the operation of autoconf and automake and tell you how to check that HP-UX98/version 2.3.45 has a broken strfchok() function that doesn't accept a second argument of 0.
These systems must die. POSIX should be the only supported target for young programmers. HP-UX87 and SunOS 0.x can RIP. Their admins should upgrade to a newer OS if they want to run new programs.
Help deprecate those beasts! Don't write portable code for ancient systems.
As an open source developer who is currently in the pre-beta testing stage with my main open-source application, one of the issues that come to mind is the issue with testing. It is fairly easy to write portable code (and fairly impossible to retroactively make non-portable code portable). The problem is testing.
In order to test a given program, the program has to be tested on any and all supported architechures and platforms for the program in question. This requires a large number of compters to perform testing on. Distro Watch has a large number of Linux distributions; it is not practical to test a program on all of them. What is done, usually, is for professional software vendors to say "This program is for RHEL 3; if you want to run it on any other distribution of Linux, we will not support it".
As just one example, after writing my application on RHEL 3 (OK, Centos 3.6), I couldn't get it to compile on FreeBSD because FreeBSD uses "-pthread" instead of "-lpthread" to indicate that an application uses the pthread libraries.
As another example, I went to some effort to have the application generate no warnings when compiled on GCC 3.2.3; however, the application generates a number of warnings when compiled with GCC 4.0.
As another example, the Loki games no longer run on Fedord Core 3; even though the people at Loki went to a lot of effort to make their games as portable as possible, things in Linux changed so that older binaries no longer run; I had to create special chroot() environments to run older binaries in FC3; I had a Slackware 8.1 and a RedHat6.2 chroot() environment for running older browsers for my cross-browser compatibility testing (something Slashdot hasn't done; The new "standards compliant" Slashdot breaks on a number of older browsers which rendered the old site just fine)
The point being that, while portable code minimizes the development expenses of an application, it does nothing to lower testing costs.
Then device drivers and operating systems were going to let us abstract away the details of the underlying implementation of the hardware, letting us write portable code. But not all O/S versions are compatible; there are glibc issues under Linux, and so on.
Then JAVA was going to be completely portable to all operating systems. But not all Java virtual machines are identical, and different version of Java came out, and things diverged.
All of these things made life more portable, to some degree. All of them still require boostrapping a system that understands the underlying hardware and deals with it efficiently; then abstracts all that hardware specific efficiency away again.
Portability is *hard*: in some sense, it's the enemy of efficiency. You need to abstract away all those nice hardware specifics that make the hardware work, and replace them with a theoretical construct that caters to the lowest common denominator that you're willing to support.
What's worse, as soon as someone makes a different design decision, or an improvement, or something that isn't universally adopted all at once, you have multiple versions -- divergent standards which aren't completely compatible. It happened with UNIX; it's happening with Linux (to a lesser extent, because code can merge again after a fork), and it happened with C and Java.
What can the developer do? Just our best; true universal portability is a Holy Grail that we'll never attain, because the day we do, someone will invent a radical new system that doesn't quite fit our abstraction model...
Amen, brother.
.ini files, or CStrings, or what have you. It was all the non-portable things they did without even knowing it--and the fact that the non-portable stuff was salted and peppered evenly throughout the whole project instead of concentrated in a few well-defined modules--that got to me.
I've been involved in way too many projects where people said, "Oh, yeah, we're doing all our development on Windows but it's no big deal. We aren't going to use anything non-portable."
Then, when the time came to port it... it was utterly intertwingled with Windows-specific cruft, half of which crept in because nobody even knew they were doing it. If they'd ever tried even once to port it, they could have caught this stuff as it happened.
I don't mind a conscious decision to use
And it didn't help that everything was compiled with permissive compiler options regarding C/C++ conformance, and a low warning level.
"How to Do Nothing," kids activities, back in print!
I've written production code in C, C++, Objective-C, Lisp, Pascal, many different scripting languages, and Java. Bar none, if you want to write something portable, Java is the language to use. It has the incredibly complete and mature libraries, performance is excellent, tool support with IDE's and app servers and source repositories is fabulous, and it is designed to be cross platform! Games, huge transactional systems, office apps, and utilities are all appropriate types of applications to build on Java. I've started to do scripting on FreeBSD with Java. I'll admit, it's hard to write a useful bit of Java that is less than about 10 lines of code, particularly for text processing. But that is probably the only place it is lacking. The one other place one might consider using something else is in Dynamic Client-Side Web Apps (AJAX stuff). Other than that, I always groan when people talk about using other languages for cross-platform development.
Helping with organizational effectiveness is our job.
Isn't an OS just a kind of runtime environment? After all, it's just one level of abstraction among many levels of abstraction. A Java Virtual Machine is just one more level of abstraction.
This is my sig. There are many like it, but this one is mine.
Java, web, etc. (other people have said web apps)
Not all code can simply run above the system. That's like saying that you're going to write the most portible operating system ever, in perl!
1) Objective-C is supported wherever gcc is. Get a klew.
2) With the GNUstep api, you can write code which targets Cocoa but is portable to other platforms. You may have to rebuild your NIBs in Gorm, however; but if you wrote a platform-agnostic back end this is a cosmetic issue.
3) If you're using Carbon, your interests really are Mac only.
N4st0r, trixx0r h0bb1tz0rz! Th3y st0l3 0ur pr3c10uzz!
If the task is well defined, a small, tightly defined app tied very closely to the target API has a better chance of performing well with fewer bugs as you can spend the portability-effort in testing.
I abstract math and models to generic C++. I tie the rest as tightly as possible to the target API and focus on being fast and bug free. In my career so far, the only code I have ever ported for business reasons ($$) has been mathmatical algorithm related.
YMMV.
..don't panic
When I made the decision to move to Linux, I started looking around for a cross-platform language. I was thinking about Java but there was an article on Slashdot about a Sun programmer who thought Java was not a good fit with their environment. One of the languages he suggested was Python. It has worked well for me.
It may take a performance hit because it is interpreted but for the stuff I write that isn't usually a problem. It is relatively easy to distribute applications. I just burn a CD with python and the application. I write in a Linux environment and distribute to a Windows environment. I'm glad I chose Python because I get a lot more work done that if I were coding in Java.
I write portable code, I'm writing on Windows, deploying to an AMD Solaris box and the target is SPARC. I've also done this same "magic" trick on AS/400 and OS/360...
Now me I just use the tool designed for the job of being platform portable, rather than trying to invent new standard headers (STL anyone?) that address a fraction of the problem.
Want to do sound on multiple platforms? Graphics? Business Process? Then use Java, its what it was designed to do. And to all those muppets who shout "its not possible"... the deploy has just finished and within 30 seconds its running on two different platforms.
An Eye for an Eye will make the whole world blind - Gandhi
C++ also has some very nicely organized ways you can write portable code. For example, data serialization - if I care about a piece of code being portable, all of my "structures" that may need to be shared are classes with the functions "serialize" and "deserialize", and all of the member variables/structures are classes with such functions (down to the most simple members, which are just wrappers around basic types; you can even wrap vectors and maps so that arrays of any kind are dealt with automatically). Each class's serialize function simply calls the serialize function on all of its members that need to be preserved; only the most basic types actually do any IO themselves.
The net effect is that no matter how you change your code, or even if you template it over a range of types, everything always gets written out and read back in properly without having to resort to constantly changing special case read/write functions or having to know what is in every structure and how to write it. It keeps it very simple indeed. You could have a structure nested twenty levels deep containing arrays (vectors) and associative arrays (maps), and go in and change a dozen datatypes at different levels, and not have to modify a single piece of reading/writing code.
He's just being nice so my real father won't freeze him in carbonite and sell him for spice.
Most of the code portability issues are solved in Java. By using Java, your code will run 90% of the boxes. Of course, Java is not perfect. And even if the portability is good, it is not perfect: there was some minor bugs when our sowftare was runned on OSX. However, it was extremely easy to fix it. Also Java is some way limited so doesn't fit the bill for some applications. OTOH, Classpath.org is going well and there is plenty of good free JVMs. Almost for any box. If you take the limitations in consideration, you can write code that will run on 99% of the boxes. You could do the same in C but it would be painful and much more limited (no GUI, no DB, ...). Also, most issues with L10N and I18N are already solved with Java.
Million Dollar Screenshot
1. If writing for both UNIX and Windows - and/or possibly other systems, do the development on UNIX. The reason for this is simply that if you develop on Windows, you will all the time be pushed towards using non-portable features; the development toys, I mean tools, are made that way. Also, the portable parts of the C libs were made on UNIX with that system in mind.
2. Stick to POSIX. The POSIX standard convers almost all the functionality needed for the internals of any application.
3. Separate the GUI from the business end of the application. Use IPC to communicate between the parts.
4. Avoid threads. Threads are the source of some of the hardest errors to debug; plus threads are NOT the same kind of fish on all platform, even when they are called 'POSIC threads'.
but'cept that
1) It runs too slow to compete with a C/C++/Objective C application.
2) It looks different on different systems.
3) It takes forever to start up.
4) The GUI feels icky and looks creepy and is slow and non-native.
5) Sun holds Java hostage
As one example, consider Windows Vista and DirectX vs. OpenGL. Windows essentially is saying that if you want hardware accelerated video, it's going to be DirectX only (on Windows) through a complete 'nerfing' of OpenGL support.
In Soviet Russia, us are belong to all your base.
An oldies but still goodies ;-)
:P
http://tinyurl.com/9umok
Duke rulez
"Flipping the bird" is a colloquialism for making this gesture.
My team's been writing 100% portable C code since 1991 or so. We took the same approach that Apache has done since version 2, i.e. build a distinct portability library and remove all non-portable code from the application itself.
It's amazing anyone would actually write non-portable code except through ignorance. As a programmer, I still run code written in 1991-2 (though it's been marginalised by newer work), and we have made some quite complex products (web servers, code generators) that run on anything that has standard C libraries and BSD-style TCP/IP, including OS/2, OpenVMS, and of course all Unix and Windows boxes.
The alternative option is to use a VM. Since we write fast system software that's not an option.
A wise person taught me this over 20 years ago: life is too short to throw out code just because some platform changed. Portability is one of those skills that lets a normal programmer like me accumulate enough quality code over time to become a master programmer.
My blog
I write code for a Windows app for a living and feel the need to point out that even just limited to Windows, our code has to be aware of the different Windows versions. The 9x family in particular comes up short compared to NT/2K/XP, not fully supporting many GDI calls (which is what my code mainly uses.)
Save yourself $11.88 by buying the book here: Write Portable Code: An Introduction to Developing Software for Multiple Platforms. And if you use the "secret" A9.com discount, you can save an extra 1.57%!
Apache Portable Runtime.
td
hard core geek-ware
If it's GUI you're after, you can use the wxWindows libraries (http://www.wxwindows.org./ GUI for: Windows, WindowsCE, GTK, Motif, Carbon, and Cocoa. It also supports C++, Java, python, and perl.
If wxWindows is not your style for the Mac, just use C++. Objective-C and C++ can be merged in a single binary (AKA Objective-C++). Write all your heavy lifting in C++. Write all your views (model-view-controller, anyone?) in Cocoa.
....I just burn it to a CD and take it with me anywhere! :-)
Coder's Stone: The programming language quick ref for iPad
That's right, you heard me. Don't write portable code.
Use portable libraries and languages; re-factor your working code to be portable; make high-level choices that support portability (e.g. don't lock yourself in to proprietary solutions), but don't write portable code.
Why? Because premature portability, like premature optimization is a red herring that steals your attention from the only two things that will ever matter: correctness and maintainability. Write correct code. Write verifiably correct code. Write maintainable code. Do these things and you are done. Then, port it to another platform or ten and optimize the hell out of it. Don't do these things up-front, as they buy you nothing on the first pass, and doing them later will give you the chance to re-consider the structure of your system which you should do at least twice before your first release anyway.
That said, do not snub portability unduely. If you have the choice of trivially supporting or not supporting portability-enhacing features (e.g. in your choice of a configure/build system), there's no reason not to be portable. Just don't let it set priorities for your project from day one.
Sort of...
But, if you write C++ for Windows or Linux or whatever, the OS can hand the machine code directly to the processor.
If you write C# or Java, there is a middle man in there. The OS has to load this whole runtime environment, which takes up a big memory footprint and system resources, and then interprets your code, and then based on that tells the processor what to do.
So, every level of abstraction you add in there becomes more and more costly in terms of system resources. Yeah, desktop systems are getting beefier, but what about compiling code for embedded systems and stuff like that? Sometimes efficiency is a big consideration.
...obviously needs improvement, or the reviewer wouldn't be such a horrible writer. What the hell was samzenpus smoking to let this tripe make the front page?
Media that can be recorded and distributed can be recorded and distributed.
-kfg
It'd be nice if I could say that years later, I understood what it was all for, and now I use it all the time, but I can't. I still have no clue. I just write in python, but I sure wish someone had explained it to me (or that I had looked for myself). It'd be nice if at least one class of one course had discussed this and potential issues that may arise.
Hmmmm, IBM and PalmSource might disagree with you there.
But you're correct in general. Not every platform you'll want to port code to will have a JVM. And those that do will not have the right JVM
It's a little immature, but groovy will provide you java cross-scripting with more script-like capabilities and syntactic sugar.
Hey, I'm just your average shit and piss factory.
How do you manage the makefiles for both gnu make and nmake.exe? I've tried writing makefiles that would run under both, but the intersection of the two programs' compatible features is almost empty. Do you just write separate makefiles for each one?
Oh comon - you want portable code, just work with Java and you are good to go! *duck*
Horns are really just a broken halo.
Enjoy reading the windows.h did yea? :-)
Coder's Stone: The programming language quick ref for iPad
In all honesty I'm not the one who manages those... but basically the makefiles are broken into parts and it looks for the section appropriate for the operating system, exports the appropriate compiler / linker options, and your good to go.
-everphilski-
Portable my ass.
I have an application compiled for Windows 2.0 that still runs on Windows XP 64.
Wake me up when Linux does not fuck-up ABIs and annoy professionals with every new sub-sub-subversion of their ridiculously bloated macrokernel.
Despite the crudity of the parent poster's statements, he is essentially correct. Linux/GCC have regularlly changed the ABI for seemingly no reason at all. All that says to us programmers is that either the coders are changing the ABI as a feel good session (See? It looks puuuurrdy!) or they didn't take the time to get it right the first five times.
I have to switch between Linux and Windows (Linux has the AVR tools, Windows supports the drivers for our Vector Network Analyzer). I've written most of my (non-avr) code in Python. I've been able to move my testing code and GUI interface code effortlessly between the two environments.
And yes, python has been released for PalmOS. So there.
It's not wasting time, I'm educating myself.
Then run it in mame. It runs on more systems than I've even seen. It'll even run on digital camera's.
I said "think", not "rationalize". Ad-homiem attacks aren't going to prove any point you're trying to make.
While your solution works, I'll admit that the whole serialization thing is one of the nicer things about Java. Obviously there are other pitfalls with the language, but serialization is one of the things done "well" in most cases. I only wish there was something like that for C++, or the standard libraries at the least, with perhaps a class you could extend with your own class wherein you serialize your own primitives, or something.
I dunno, rambling. But Serialization is a real PITA sometimes.
For instance, there is no Java JVM for a Palm.
There isn't? What will I do?
Dude. Java is everywhere. It's in tiny little cards and in the latest ARM processors. You can't run. You can't hide. Java will find your OS, and you will be assimilated. Submit to the collective!
Javascript + Nintendo DSi = DSiCade
Write on the bare silicon, with a microscope and an electron beam.
Compilers are for feebs who can't read schmatics!
Portability is for indecisive cowards!
sigs, as if you care.
"alot" is not a word. Learn English before posting.
Now, why hadn't I seen that before? Thanks.
;)
Not that my device is listed as supported though...
'Sensible' is a curse word.
If you write C# or Java, there is a middle man in there. The OS has to load this whole runtime environment, which takes up a big memory footprint and system resources, and then interprets your code, and then based on that tells the processor what to do.
;-) (I'm only half joking, too. Java is basically an OS platform. Moving it down isn't that big of a step.)
That's precisely why the Java Runtime should be the OS.
BTW, Java might be interpreted, or it may be JITted, it may be run in a mix of the two, or it may be outright pre-compiled. Depends on the runtime.
And I'd just like to say that the mods are a bunch of pricks for modding 955301 down. Remember the modding guidelines? Mod UP, not down. If you don't like it, leave it alone.
Javascript + Nintendo DSi = DSiCade
I had to take a mandatory graduate level course CS 533 Developing portable software, taught by Dr. Mooney, who was known around school as "that portability guy".
The class went thru umpteen strategies to write portable code & culminated in a portability project, where you wrote a "Quiz Program" in C, that ran on Solaris, Windows & the Mac with minimum code changes.
All code changes had to be confided to the stdio.h & other header libraries. I see these days he has added Java to the mix.
My own experience has been that it has very limited utility in real-life ie. corporate IT. All the jobs I held since I graduated did not require an ounce of thinking portable. They were all about writing proprietary code to be run off the web, and for some 10 years, Java was the only option until C# came along. So I practised portability by default, since that was the nature of my employment in the industry. But I can see how this might be useful for somebody doing systems level programming (assuming there are still such jobs in the IT industry in the US, of course...)
And a RISC box for catching SIGBUS issues.
Stuff like this -
3.243F6A8885A308D313
Eclipse is written in Java.
One interesting method for cross-platform code I've been tinkering with is using GNUStep libraries to cross-compile apps between OS X, Windows, and Linux.
.LIB libraries on Windows.
Seems to work reasonably well as long as you stick with Foundation Kit or Application Kit. However some weirdness is enoucntered when trying to do fancy things like use
Writing C++ and having the OS talk directly to the processor is partly to blame for instable systems. Low-level access requires high-level knowledge -- one byte out of place and someone's mechanical lung stops working.
Operating systems 20 years ago used much less memory than they do today. That doesn't mean that modern OS's aren't as good, just as having a virtual machine isn't necessarily bad. The concept of abstraction layers is a good one, even though they usually have a cost. Like anything else, the cost has to be weighed against other factors (efficiency being one, but also portability, security, time-to-market, and robustness).
Embedded systems may be an exception in a lot of cases. However, there is embedded Java (J2ME), and resources are relatively cheap (and getting cheaper). It's probably often cheaper to use Java and a bit more hardware than designing against a proprietary system to skimp on the hardware costs. Economies of scale, and all that.
This is my sig. There are many like it, but this one is mine.
You forgot reflection. Reflection is the key to the awesome serialization, and is useful for all kinds of cool and interesting stuff. :-)
Javascript + Nintendo DSi = DSiCade
Ever heard of 'Java - write once, debug everywhere' expression ?
It does not refer to the bugs in JVM (at least to a lesser degree),
it refers to the fact that JVM abstraction purposefully hides all
host platform details INCLUDING ITS LIMITS.
Sure thing it's not that important for running HelloWorld, but it
is essential if your application pushes system to the limit. Like
say it happens in real life.
lua is usually the first choice for an embedded scripting language, because it's so minimal. it's reasonably powerful and easy to sandbox. it would be very suprising if lua wasn't included.
according to it's subtitle --> according to its subtitle
Much as a certain large software company located in the North-West of the United States of America might wish otherwise
Can we have one story without flame-bait? Was that comment even necessary for the story? The story is about compact software. The first thing I think of when I think of bloated software is KDE and Gnome. Windows is bloated as well but damn...there was no reason to throw that in there unless you wear blinders and are clueless about the whole picture.
Much as a certain large software company located in the North-West of the United States of America might wish otherwise, there are many different operating systems and platforms in use in the world today. As a matter of that it's been like that since "ancient times" when there were bunches of unixes, and the reason unix didn't prevail was supposedly that people preffered coding for one OS, instead of 12 unix variants. I don't think this has changed. Of course above reasoning was taken from an article to promote the linux standard base, which I'm against anyway :)
Though, I will admit that reflection is one of the things I like about C#. Still, the whole idea of using RTTI to defer what should be a compile-time decision to run-time just leaves a bad taste in my mouth.
You could've hired me.
Note: I am a C++ programmer. I didn't read the book, just the review here. Apologies in advance if anyone takes offense.
> The first couple of chapters introduce the reader to portability concepts
> and then to some of the specific portability features of ANSI C and C++
> that are used throughout the rest of the book.
I think enough software is written in languages other than C and C++ that any serious author should put C or C++ in the title when the book is C or C++ specific.
It's not wrong that the author or publisher chose to call the book "Write Portable Code" instead of "Write Portable Code in ANSI C". But it does make me question if the author's knowledge is limited by a single-language bias.
> The last two chapters look at some alternative ways of getting portability.
> Scripting languages are discussed and the pros and cons of each ones
> portability is weighed. Lastly the use of cross-platform libraries and
> toolkits is addressed.
Given that scripting is limited to one chapter, wouldn't it have been better to refer the reader to other works with more detail and value, and only give a paragraph or so? Particularly since the book is not trying to be about portable code in general, but portability in ANSI C, and discusses nothing (AFAIK) about higher-level compiled languages.
The book's about C. Why clutter it with a chapter on Ruby, Python, and JavaScript/ECMAScript and say nothing about Java, Lisp, SmallTalk, etc? Writing a chapter on scripting languages strikes me as gratuitous filler.
And any non-trivial cross-platform C application is likely to use some sort of cross-platform toolkit. So why only a chapter?
> An example: Rule 4 - "Never read or write structures monolithically from or
> to memory. Always read and write structures one element at a time, so that
> endian, alignment, and size differences are factored out."
Writing structures one element at a time is a -minimum- required for portability. It doesn't completely address byte-order issues, variable internal data representations, or data element size issues. It just ensures that structure packing and alignment issues that might change based on compiler flags are covered. But change the compiler or platform and all these issues are still there even if you write the data elements singly. They are all unspecified or incompletely specified in ANSI C.
It's better to design a complete data representation format, including embedded version information, or just use a higher level data store engine.
My concern is that many of the other rules in the book might be similarly too "low-level" and incompletely specified. Rather than teaching inherently better, more portable coding techniques, they might just be teaching how to work around the low-level nature of C.
Amiga Anywhere was supposed to create that environment that java wasn't quite able to. You could write a piece of software and have it run on all platforms (PC, Mac, *nix, palm, etc.) but never really went anywhere due to setbacks and poor company management. In the end, I think they just ended up using it to make software for slot machines. :-/
DEAD DEAD DEAD DELETE ME
I know you're kidding, but unfortunately there are a lot of responses here which indicate that Java is the end-all and be-all of portable programming.
I'm sorry folks. Such people have never done real cross-platform programming. Java simply isn't an option on MANY platforms. If all you do is x86 platforms, and perhaps some Motorola workstation-class platforms, hey, you're fine.
But that's not the real world.
The real world includes MIPS, ARM and other processors. What's more, the embedded world makes up most of the usage of CPU's. Java is not an option in most cases, unless you go out and pay one of the few small shops that will port it a bunch of money. And that assumes your system have the footprint and horsepower to run it.
I see outfits where the programmers have never programmed on a non-x86 system in their life suddenly wake up to this fact. It would be funny if it wasn't so sad.
Now, granted the GNU folks are coming up with their Open Source version, and it appears to be coming along fine. But it's not quite there yet.
Also, keep in mind that it won't run on many platforms, simply because of size limitations. All the world isn't your dual-core 3 GHz x86 with 4 GB of RAM.
And I'm sorry, but the Java claims that it is as fast as C code just aren't true. Don't believe me? Try doing some benchmarks on 100 MHz small-RAM systems. If you're lucky enough to get it to fit, you'll see that things are just dog slow.
Most programmers and students today are just too used to working with the supercomputer type of CPU's that the modern desktop is like, and aren't used to dealing with small-footprint type of systems which make up most of the world
gotta... ...ugh... ...carry... ...all... *pant* ...that... *wheeze* ... run time type information ...around. Whew!
:-)
;-)
And yet, Java programs tend to compile to smaller files than native code, and also take a far shorter period of time. Even on the largest projects, I can compile Java code inside of ten minutes. It can take days to compile a C program of comperable size. And once it's in bytecode, it's only a short hop for the JVM to compile it to native code. Works pretty darn well.
Still, the whole idea of using RTTI to defer what should be a compile-time decision to run-time just leaves a bad taste in my mouth.
Not sure what you mean by this. Pretty much all code with direct references are properly checked at compile time. Obviously the run-time has to be a bit smarter when you dynamically load things via reflection, but that's very much a feature, not a bug.
Besides, you gotta love the ability to build a self-organizing program scheme in 20-30 lines of Java code. Doing the same thing in C++ is a PITA, and would only serve to confuse the heck out of the developer debugging the app and the OS trying to run it. I can just see it now, "Program X has 3,102 DLLs loaded."
Javascript + Nintendo DSi = DSiCade
Sun makes the Java install process on FreeBSD so complex that I've given up. Therefore any Java program instantly cannot run on my computers. So far I haven't seen any loss either. Java is mostly used for long running server processes (where JVM start up time is irrelevant and the JIT compiler can speed things to just as fast as C++), so I don't need it anyway.
I find that cross platform C++ is not hard if your code is properly modular. Libraries like QT or wxWidgets take care of most issues these days anyway.
> For example, data serialization - if I care about a piece of
> code being portable, all of my "structures" that may need to
> be shared are classes with the functions "serialize" and
> "deserialize", and all of the member variables/structures are
> classes with such functions (down to the most simple members,
> which are just wrappers around basic types; you can even wrap
> vectors and maps so that arrays of any kind are dealt with
> automatically). Each class's serialize function simply calls
> the serialize function on all of its members that need to be
> preserved; only the most basic types actually do any IO themselves.
Wow, all that work, and here all along I've just been using Data::Dumper for this sort of thing. (Granted, if you have lexical closures this doesn't preserve their lexical context, but I don't think that would work with your C++ serialization system either.)
Cut that out, or I will ship you to Norilsk in a box.
Now where did I put that interpreter again? Ah! Here it is! *oof*. Geez, that's getting heavier every year.
Not sure what you mean by this. Pretty much all code with direct references are properly checked at compile time.
I refer to the trend I've seen where types are checked at run-time out of laziness instead of using plain old polymorphism.
Besides, you gotta love the ability to build a self-organizing program scheme in 20-30 lines of Java code. Doing the same thing in C++ is a PITA
Well, yeah. Anytime you have to shoehorn in your own pseudo-reflection mechanism, it's a pain. But, reflection is one of those things that cane be *so* abused, it isn't funny.
Then again, I spent a lot of time in the embedded world, where you do as much at compile time as you can to avoid spending the time, code, and memory, to do it at run-time. Footprint matters. (Though, sometimes clever interpretation at runtime can help you trade space for time, and that's handy, but you're still making a trade.)
You could've hired me.
A-freakin'-men. The way that some metaprogramming systems I've seen abuse RTTI by handling all the members by name lookup make me wonder why the even bothered with a dynamic language in the first place. RTTI is basically a substitute for a solid metaprogramming model and a well-thought-out standard library.
Now where did I put that interpreter again? Ah! Here it is! *oof*. Geez, that's getting heavier every year.
;-)
The interpreter is small. So is the JIT. That's why those are the options usually offered on cell phones and other embedded devices. It's the highly optimized, mixed-mode execution model that gets us such a massive chunk of translation. It is fast, though.
I refer to the trend I've seen where types are checked at run-time out of laziness instead of using plain old polymorphism.
You mean like this: "if(object instanceof MyObject) DoSomthing();"?
There are a lot of good reasons to do that. However, I do agree that some programmers abuse it. If they'd just create an Interface, they could stop with the "if" statements.
Then again, I spent a lot of time in the embedded world, where you do as much at compile time as you can to avoid spending the time, code, and memory, to do it at run-time. Footprint matters.
Ah, different worlds. Java's most popular platform (business logic) requires maintainability and architectural clarity above all else. So plugging code at odd times can make a lot of sense. In the embedded world, stripping your Java code down is one of the first things you do. And I say this as a previous winner of the Java 4K Coding Contest.
Javascript + Nintendo DSi = DSiCade
For once, realize that not all of the worlds problems are caused by Microsoft.
That's true. Microsoft is only responsible for 98% of all problems. The other 2% can be blamed on SCO.
Speaking of cross-platform programming, I've been wanting to write up an application under C#/mono. I compiled mono and MonoDevelop, only to find that MonoDevelop has no integrated form (GUI) designer. The only option, so far as I can tell, is to use the stand-alone Glade designer and import the .xml file into the project through the C# Glade bindings (which doesn't work anyway, due to some API changes, apparently).
I did some Google-ing, and found some (slightly dated) information stating the MonoDevelop team had no plans of including Glade, opting instead to write their own designer. That's a noble goal and all, but isn't there a way to wrap Glade in the meantime so you can replace it with the custom one when the time comes?
Out of curiosity, has any progress been made on this front? Even if they had to fork Glade to pound it into MonoDevelop, it would seem to be a reasonably stable and mature starting point.
I ask because I really don't have time for all of the box_pack_start/show_widget trial and error world of pain I remember from using Gtk+ in C. Any insights? Other recommended IDEs? Should this be an AskSlashdot?
Exactly. It's as if they learn RTTI before they learn polymorphism. Though, if one were pedantic, one could argue that the vtable is as indicative of type as anything else.
In the embedded world, stripping your Java code down is one of the first things you do.
I dunno. I've never managed to get Java as fast and lean as I'dve liked it to be, and others insist that it can be. And don't get me started on RMI.
The kind of things I drool over are the Turing-completness of the C++ template mechanism, but that just goes back to wanting to get the compiler to figure out as much as possible for me.
You could've hired me.
I love how Anonymous Cowards like to slander and ridicule Slashdot, fully forgetting the fact that Slashdot is a free community service provided at a cost to those providing it, with little to no recompense. I also love how they attack the entire community for something one person writes in an article. It makes me feel all warm and fuzzy inside watching them make fools of themselves in their ignorance. Keep posting cowards, because THAT's how I make myself "feel bigger".
"For once, realize that not all of the worlds problems are caused by Microsoft."
You know, you are right, the rest of them are caused by people who complain about free services.
No conformist ever made history.
But I couldn't find the right wording.
Another point I think is important is that porting can help you find bugs. Try compiling your code on some weird compiler and system instead of your favorite. Usuallly (for nontrivial programs) you'll get a different set of warnings, and sometimes you'll luck out and the thing will crash. Then you get to look at your program and find that error, which probably would have come up only after users started to bang on it.
If you can use #ifdef to avoid a bug, you haven't found it yet.
Raise your children as if you were teaching them to raise your grandchildren, because you are.
Java boys just don't get.
p reasheet etc are all
... or perl ... or ruby ... or any other high level language.
Right now: how many java apps are running on your machine? Zero.
Your browser/emailclient/shell/imageviewer/sshclient/s
written in C/C++/or/Objective C?
Why? Because it runs faster than java
Bottom Line: speed wins, java loses.
(whaps idiot over the head) Now do you get it?
The second module deals with all the user interface stuff and nothing else. Any event handling is done in this module and nowhere else. That way, the rest of your code doesn't need to worry about what type of execution model is being used. It'll just work as you would expect. If there is no user interface, you don't need this module.
To make the UI truly portable is hard. No specific capability is guaranteed. eg: GUIs don't guarantee a text console, and text consoles don't guarantee a GUI. My advice would be to split the module into two sub-modules. The first sub-module handles what you want to do, but contains nothing specific on how. For example, it might be filled with commands for selecting fonts, drawing lines, etc. However, it would not contain any calls to an underlying system. It should assume some abstract, theoretical, idealized user interface.
The second sub-module (which may be a third-party library and not something you need to program at all) would then convert these commands into actual interface calls. If you're writing this yourself, I'd suggest starting with interfaces that are already fairly portable (eg: Qt, Gtk+, Ascii Art Library) where possible. If you can't, then you'll need to write alternative versions for different types of interface. But at least it's all in one place and squished down to the routine level, not entire screens.
The third sub-module (again, third-party if available) would do the same as above but for file I/O. Again, the upper levels should make no assumptions at all. "Anything is possible in the next half hour", as Gerry Anderson would say. The lower levels then convert the "ideal" into what the system can actually do. Here, there are at least some standards. Use them. But then write special case code for platforms that can do better. Portable need not mean sub-optimal, it merely means sub-optimal (but guaranteed to work) until tuned.
The fourth would do the same for networking. There is absolutely no reason why an application should know if you're using sockets, MPI message passing, IPv4, IPv6, DECNet or a guy waving two flags. At the application level, data comes in and goes out. The other end should be of no consequence, and the method of getting there should matter even less. High level networking should be abstract connections, using some sort of token to identify which connection is being referred to. There needs to be a middle layer here, to turn the abstract connection into a real networking protocol. The lowest level then handles the network calls required.
You need the three layers, because you've two levels of abstraction (the network protocol and the network hardware) and therefore you need two levels of reification to turn the abstract into something usable. As network protocols can work over multiple mechanisms, the protocols are resolved first and the mechanisms second.
Coding styles for ALL abstract components AND the first module should emphasize portability. There should be nothing system-specific there, so you should be able to use the absolutely vanilla ANSI specification of a language (where one exists). For C, if you want to cover ancient or obscure systems as well, you should duplicate all function declarations and external declarations, using a #ifdef to distinguish between ANSI C and K&R. There are probably other languages you need to support multiple variants of, just keep the areas where you need to have compile-time or interpret-time selection kept to a minimum.
The low-level routines are only going to work on a limited range of systems, no matter what. Therefore, anything valid for that subset is fair
It's a small world and it smells funny; I'd buy another if it wasn't for the money; Take back what I paid (SoM)
Write the code using your favorite language.
Sell your client a Mobile Code Container aka laptop.
This book simply contains everything the author knows about writing portable code.
Patrick Doyle
I mod down every jackass who puts his moderation policy in his sig. Oh, wait a sec....
Because you're a fucktard, fucktard.
I think all the proponents of Java kind of missed the point here. Not everything has or even NEEDS the level of horsepower that Java requires- and just adding more muscle isn't always in the chips.
And even then, saying "Java" will run everywhere, is really a mis-concept. It'll run most everywhere where there is a least common denominator. I can tell you that while it makes it easier for Oddlabs to make Tribal Trouble for three platforms simultaneously, Java doesn't make it cross-platform- you can't take it and run it on say a Solaris box (though I suspect they could MAKE a Solaris iteration of the game easily enough...) or on an embedded machine using Java, say like the Ignite platform.
Java makes some things "easier" to make cross-platform, but again, it's like anything else- cross-platform is more of a philosophy than a feature set of a language or toolset. And it's definitely NOT the panacea that the proponents in this thread make it out to be- I should know, I do Java development amongst other things. If you can't make a C++ program at least 40% faster than your best Java code, you might want to re-work the C++ code. This is not to say that it's a bad idea or anything; it's just that people keep trying to jam it into problem sets that it's ill suited for.
I am not merely a "consumer" or a "taxpayer". I am a Citizen of the State of Texas
Serialization is not a good way to manage persistent data structures, because it ties your data structures to internal details of your program structure (i.e. your class structure). Change your program structure, and suddenly you can't read old data files any more, because your serialize/deserialize methods no longer match up with what data you previously wrote.
Program structure and (persistent) data structures should be kept carefully separated for this reason.
In any case, serialization does nothing for code portability.
I ported a DOS character-based windowing library called C-Scape to the Amiga and OS/2 in 1990 or so. Worked pretty well. I never figured out why that kind of thing wasn't used more.
The revolution will NOT be televised.
When perl gets within an order of magnitude the performance of C++, let me know. When perl gets generic programming, let me know. When perl does full polymorphism, let me know. When perl gets anywhere near the bazillion libraries used in C/C++ (yes, perl has a lot. No, they're nowhere close to the amount C/C++ has), let me know. In fact, when perl does essentially anything of what people use C++ for, let me know (for example, when you think you can get it to do much of anything ITK does for developers anywhere even remotely close to its performance - start reading at "Generic Programming", continue through "Smart Pointers", and don't stop until you get the point).
Perl is a great language, and has many widespread uses. It is not anywhere close to a C++ replacement. Period.
He's just being nice so my real father won't freeze him in carbonite and sell him for spice.
Some things really should be considered from the start - which you seem to agree with. Others can probably wait, so I don't think you're totally out of line either. Reading of a book like this is probably a good way for people to make reasonable decisions as to which things really should be done up front. I just wish everyone would at least consider portability up front even if they don't plan to do it. Plans change.
It's really cool, and I'm pissed that I got out of college not knowing this stuff. It should be a required course, IMHO.
/pet idiom xyz/, we better make it Required!". Then you end up with lots of little "required" classes with important-sounding names ("Software Engineering, For Engineers"!), and in 2 years when the original prof moves on, they don't even teach that, any more.
Gawd, no.
I've seen this too many times. Somebody says "hey, students graduate not knowing
There's no way you can teach every student everything you want to. At some point, the responsibility is on the student to learn -- you're at college, you're paying $X thousand a credit, it's not their job to spoon-feed you everything. College teaches you *how* *to* *learn*, more than a certain set of skills; otherwise it'd just be a trade school.
If you write large programs with other people, you'll figure this stuff out. What, you got a CS degree and never wrote a large program with other people? (Do you think any English majors graduate without having read a long book?)
I'm writing a FOSS app to help with an online fan project at the moment.
I chose XUL, because essentially the only user requirement for installation is that they have Firefox or another Mozilla suite program.
XUL will run on any box Firefox will run on. And that means about 99% of the boxen out there.
May the Maths Be with you!
portable code is a pipe dream, a search for the fountain of youth or holy grail.
and I should know... I'm running Mozilla on AmigaOS and the tables render a little funny.
-pyrrho
Exactly. More than that, a "portability layer" is just a handy term for a specific example of modular programming, which is good practice as a general principle anyway. If your code is constructed from carefully separated subsystems with well-planned interfaces and a layered structure internally, portability pretty much becomes the default, because it's little more than "adapting the stuff in the bottom layer".
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
I dunno what you mean by "turing-compleness", but the Generics mechanism in 1.5 is probably what you're looking for: compile-time type-safety. Before when using collections you were always casting back-and-forth from collections, but now you can let the compiler ensure what you're doing.
Still not 100% efficient, as they made it a compiler-trick, and thus it's still doing type-checking at runtime (why they implemented it this way (even though it preserves backwards-compatability with existing bytecode, which isn't a good enough reason IMO) is beyond me, as the speed improvement would have been worth it).
This can be true even if you never plan to switch compilers, OSes, or architectures in production - I've seen errors which will silently corrupt your memory on one platform but segfault (and thus give you a nice stack trace to work from) on another.
But really, how much of your code is so ephemeral that it'll be thrown away before the next compiler, OS, or architecture you want to run it on comes around? I've seen programmers scream that "This new compiler version breaks my program!", then waste time wading through their standards-incompliant code that could have been correct if it had been tested on multiple compilers from day one. I've seen "optimizations" that were written based on profiling on only one system and become hard-to-refactor "pessimizations" on newer systems. I've seen programs stuck on slow and expensive hardware because nobody wanted to worry about endianness issues until competing fast and cheap hardware made those worries necessary.
For someone writing popular open source code, portability is even more important for testing. The number of people who want to use your code will almost certainly be greater than the number of people who want to use your code and your operating system. It's nice to get bug reports and patches from the whole former set rather than just the latter.
Look here
Those kinds of things are possible because the C++ template metalanguage is Turing Complete.
Of course, the syntax gets real ugly real fast, because, I think, the template metalanguage is Turinc Complete by accident, and not design, but it's amazing what you can do.
I haven't looked at Java Genrics closely enough to know if they have the same expressive power, but I suspect they don't.
You could've hired me.
You have no idea what you're talking about.
Should me some JVMs which are available for Broadcom's 64-bit processors. That I can buy, right now. According to MIPS, they have Java. Guess what? There are a lot of MIPS CPUs out there which can't run Java, without paying to have it ported.
Show me some JVMs which are available for Atmel's 32-bit processors.
You can't.
For someone who doesn't know what he's talking about, you have a big mouth.
hmmmm... let's see:
an order of magnitude the performance of C++: this depends. If we're talking about regular expression-based parsing and general string manipulation, perl5 is already there. Hard math? 3- and 4-d matrix manipulations? not yet. Maybe perl7, who knows?
generic programming: perl5 has this, sort of. lots of stuff can be done in compile time. perl6 has generic types, I think even pugs have them already, but I don't recall exactly.
bazilion libraries? here, actually, this is one of the things the world (including c++) could learn from the perl community. really. including c and c++-written libraries that you can call from inside your perl programs.
I am still reading about this ITK thingie, so I won't comment, but looks good for starters.
Mind you, I work with C++ myself. But I don't think it's a perfect language (nor I am saying you said that), and I think each tool has its trade (but, seriously, I loathe Java).
It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
I get that the template is missing from the first line, but there are other stuff missing and I don't know what they are. care to repeat, please?
It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
My rule is that if a piece of code has #ifdef WIN32 or similar in it, then it is not portable code. I classify code with platform #ifdef's as non-portable code that has been implemented on select platforms. To ensure rules aren't broken, I don't allow code that is classified as 'portable' to even have visibility of header-files that are platform specific (like windows.h). Access to all platform dependencies is accomplished through either pure virtual base class interfaces or where the internal representation is hidden. For example:
// non-virtual interface functions for object go here
.cpp file for each platform (like Win32FileObject.cpp). In this manner, the abstraction class header files do not need to include the platform-specific header files, thus preventing the rest of the application from even seeing the platform specific headers. In this manner, it becomes impossible to accidentally use non-portable platform functions or types. It also serves to completely isolate the code that must be changed for the system to work on the next platform.
class FileObjectInternalData;
class FileObject
{
public:
private:
class FileObjectInternalData *mData;
}
The internal platform-specific data is hidden in a class that is simply pre-declared in the header, then actually defined in the
Ultimatley, the goal is to implement as much as possible in the portable code. My rule is that if it can be implemented in a portable manner, I don't increase the size of the platform-specific interface abtractions. Things like big-endian and little-endian can be dealt with completely portably with functions like this:
inline unsigned PutValue32(void *buffer, unsigned value)
{
unsigned char *bufptr = (unsigned char *)buffer;
*bufptr++ = (unsigned char)(value >> 24);
*bufptr++ = (unsigned char)((value >> 16) & 0xff);
*bufptr++ = (unsigned char)((value >> 8) & 0xff);
*bufptr = (unsigned char)(value & 0xff);
return(value);
}
inline unsigned GetValue32(const void *buffer)
{
const unsigned char *bufptr = (const unsigned char *)buffer;
return((*bufptr 24) | (*(bufptr + 1) 16) | (*(bufptr + 2) 8) | *(bufptr + 3));
}
Which serve to portabily write and read 32-bit values in a big/little endian neutral way. Thus not increasing the size of the platform-specific abstracted interface.
The true goal in creating portable code is NOT in making code that can run on a lot of different platforms, but rather in writing code that can easily be ported to another platform. There is a big difference between the two. The secret to the latter is to strictly isolate dependencies and to minimalize their size as much as possible.
Yeah, desktop systems are getting beefier, but what about compiling code for embedded systems and stuff like that?
Why would you be writing cross-platform code for an embedded envirionment? If you are targetting an embedded envirionment, then you aren't even planning on going cross-platform.
I mostly agree, but you have to take into consideration that Microsoft's tendency to support ancient ABI's for windows 2.0 applications greatly increases the complexity of their product. In fact, it is often cited as the very reason for windows's relative instability (and linux's stability). So perhaps it's better this way.
Let's be honest, what percentage of projects are actually ported to other architectures? My guess is that it is a very very low number-- like 10%.
These days, the fashion is to scrap everything as legacy and do total re-writes using new tools and practices. Somehow, I don't think that will change.
Today's gleamming cutting edge J2EE project is tomorrow's crufty legacy that no one understands.
Pieterh already answered you on this, but I'll put in my 2 cents too.
I too write cross platform code, between Windows, Linux, and OSX. For each OS, I have a "shell" program, along with a "gcross" (graphics cross-platform) class, which standardizes the graphics. The shell calls an "app" class, which in turn uses the "gcross" class for the GUI. My app class contains all the code for the application. I've written many graphic intense programs in this, and they run as quickly as any other equivalent program, even faster in many cases. (My fractal program runs faster then most others I've found)
So for whatever system I'm currently programming on, I only need to copy my "app.c" and "app.h" files, as well as any other custom files and recompile with the different shell programs.
"That's so plausible, I can't believe it!" - Leela
Windows took a good 10 years until Windows 95 came out and Windows became the big deal it is today. Java has been out since 1995 -- so it is 2005 -- and I am beginning to think that Java is finally getting to the point where Swing has enough features (clipboard support, images where you can directly set the pixels, hardware graphics acceleration) that it is usable for serious applications. There is a ton of docs on Java/Swing on the Web. People used to talk about Internet time and how fast things moved in the industry, but it really takes a long, long time for many software products to mature.
Now Swing still has some rough edges -- why does a Files Open dialog take 3-10 seconds to come up on first activation, why does expanding a window cover up the Start bar on Windows (I guess there are some look-and-feel options).
But I was able to get an x-ray image viewer program developed under Windows to run under Solaris and Debian Linux without much fuss. I think Mr. Gates should be afraid, very afraid. Maybe not this year, or the year after, but there will be a time when you won't have to make a platform dependent GUI.
I didn't see anyone mention this. The last 3 projects I have worked on were done in such a way that they compiled (most of the code) and ran (lots of unit tests) on Linux and Windows. It also consisted of a build environment where builds and tests were continuously run on Windows and Linux (recently also Linux on AMD64) and both "release" and "debug" builds.
There were a non trivial number of bugs found on Linux and not on Windows or Windows and not on Linux or on 64 bit and not on 32 bit or visa versa by doing the automated tests that undoubtedly would have bitten us in the most inappropriate times.
It also opens up the skill set and tools. If a set of engineers are more comfortable on Linux and another on Windows, you get a much better cross-pollenation of skills. For example, most of the app runs on Linux and so we can use "valgrind" (a totally awesome tool for mem checks instigated by my hero Julian Seward). Other Win32 weenies like to use other tools for mem checks. So you end up getting the best of both worlds. Finding bugs sooner means lower development costs.
The most recent project is a heavily threaded network client with about 100,000 lines of C++. When we got the product limping along I decided to run valgrind for a mem leak check and to my utter surprise was not able to find ANY (unintentional) memory leaks. Admitedly, the team is a seasoned group of engineers who have a combined 100+ years of job experience, but I was still impressed.
There is nothing platform dependent about the language, of course. However, the adherence to the standards of the many compilers out there varies greatly.
When there are problems, they usually center around the compiler lacking support for some aspect of templates.
> there is no Java JVM for a Palm I have seen at least 3 different JVMs for the Palm. Peace.
is there a way to make reflection work on non-public fields and methods and if not how do degbuggers and serialisation do it?
note: i'm known as plugwash most places but i screwd up registering that here somehow in the past and now can't register
reflection is addictive though because unlike interfaces etc it doesn't require the classes to be designed for it.
u ll);
look at the following code for instance. by using reflection i can make it use any method of the objects to do the conversion to strings thus making it very generic.
public static String[] objectArrayToStringArray(Object[] in,Method conversionmethod) throws InvocationTargetException,IllegalAccessException {
int l = in.length;
String [] out = new String [l];
for (int i=0;il;i++) {
out[i] = (String)conversionmethod.invoke(in[i],(Object[])n
}
return out;
}
you could generalise this further to make it go from an array of any object to an array of any object (and i might do that if i found a reason to do so).
note: i'm known as plugwash most places but i screwd up registering that here somehow in the past and now can't register
How to 'best' write portable code depends ...
... you'll probably need ... to go with your new
If you are going to have as many end-users
as Oracle has for it's RDBMS/tools, then you go to the
hard core tools. You spend a lot of time with C/C++,
OS abstraction layers (e.g. the Adaptive Communication
Environment - ACE - wrappers), GUI abstraction layers (e.g.
WxWindows) and so on (and so on).
Yes, this *WILL* take 2x-3x-4x-5x longer to
develop/write the (commercial?) code. Hard-core,
portable, small/fast, commercial-grade code is *NOT*
easy. But it can be portable *EVERYWHERE* (from
Windows to *nix to HP NonStop to zSeries to Apple
to whatever). The speed/footprint benefits will
quickly swamp the additional development
time/investment/cost. Just ask Oracle. If it
really matters, sweat the details. Do the C/C++.
If you are doing some MIS/IT utility
program, perhaps for just one company's internal
use, then *please* don't fight the MIS/IT
department - no matter how whacky. If those MIS/IT
guys are all JAVA heads - whip it up in JAVA. If
like COBOL - whip it up in COBOL. If they
prefer PHP for most new stuff, then use PHP. At least
somebody else will be able your stuff once you find
greener pastures. Whatever. Yawn.
If you get to do your own thing, on a rich server,
then rapid-app-dev (RAD) with Python/WxPython -- and tune by
replacing performance critical bits with hand-optimized
C/C++ (but, as needed, drag in OS abstraction/portability
layers, GUI abstraction/portability layers, etc.).
Once you dip a toe into the hard core C/C++ stuff,
portability always costs. Lets face it. C/C++ is the
modern (source-level) 'portable' (macro) assembler.
If you're in impoverished parts of the
embedded space (e.g. not embedded WinCE/*Nix), then you
might have to skip past scripting in python. While
the python VM is about 1/5 the size of the latest
JVM (just at start up!), Python might not be
available. Bummer. If so, you end up going
directly to C/C++ (and often ANSI C is a better
bet with low-end embedded tool chains).
I'll not say anything about portable web server
(side) programming. That is sort of an oxymoron. You
typically decide what web/app servers you'll choose
to support/run. The portabilitiy challenge
is more common across browsers. Lets just
say hail w3c. Bad Microsoft. No wonder AJAX
is all the rage. AJAX is portable!
If you just want to expand your mind,
and free your inner-programmer, then you do
Haskell (or O'Caml) or even Scheme. Once you
finish binding unification into Haskell
combinators
a (nother) real job
PhD. If the lambda calculus rubs you the
wrong way, then try the imperative
elegance of Ruby or Lua.
I think we've already gone too far in our pursuit of portable code.
Look at Java threading. You have to use synchronization to protect your thread against being preempted, while yielding to protect all the other threads in case you never are.
That's because the underlying process and thread models used by different OS can't be abstracted away in single model. So you end up with very little thread behavior that you can count on.
Cross-platform code will always be more complex and less satisfying than targeting a particular platform.
Well, no, but it does require the class to expose a method that does the right thing. That isn't much different from the class implementing the right interface.
Where reflection comes in handy is when you have a plain old data struct, with data members, and you want to automagically generate a UI to fill in the struct members. For example, if you have a struct that holds all the possible command line arguments for a program, with a bit of work, you can automagically generate a command line parser to fill it in within the limits of the types your automagic routine understands.
You could've hired me.
Yes, there is. See the javadoc for SecurityManager. Basically, you write your own SecurityManager that permits you to do that, then activate it and you are done. However, there's a catch. You can do that only once. As most big frameworks (J2EE app servers, OSGI frameworks, etc.) usually do that on startup, you can't.
On a side note, generic programming in C++ is very much a joke. I mean, you cannot even define constraints on template arguments, and have to resort to dirty tricks with delayed instantiation - WTF?
The problem with C++ libs is that very few of them adhere to the C++ philosophy, and thus play well with STL and boost. Most are, at best, "C with classes". Quite a few are essentially Java redone in C++ (Qt being the most prominent example). Generic programming, full-scale use of templates, STL-compatible iterators? A rare sight, unfortunately.Anyway, if you know a decent cross-platform GUI toolkit written in and for proper C++, please do tell (gtkmm comes close, but it's not really cross-platform enough, and some design decisions, such as ustring, are questionable). I've been looking for that for ages, and got desperate enough that I might well start writing one myself.
Don't count on it. Albeit Perl6 is a very dynamic language, it has the potential to type-strong every single variable. Better and better tools appear every day: have you ever seen pyrex and psyco? I am not the greatest python fan either (*), but a psyco-like thing will "take over" more and more languages, especially potentially type-strong ones like perl6. And perl6 has compile-time generic types (templates) and compile-type syntax modifications (macros).
(*) I worked with it already, and I admit python code is normally very readable, but OTOH I prefer the conciseness (and possibility of expressing SIMD, when applicable) of
@a >>+<<= @b
to the supposed clarity of the equivalent for-loop in python. DISCLAIMER: this is just a matter of (personal) taste. I am not trolling.
It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
you should have done something in the line of (one specialization for each special case):
template <class T> void foo<T>::bar() {
T var = random();
do_something(var);
}
template <> void foo<uint8_t>::bar() {
uint8_t var = (random() << 32);
var |= random();
do_something(var);
}
It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
Where reflection comes in handy is when you have a plain old data struct, with data members, and you want to automagically generate a UI to fill in the struct members.
:-)
That's one use (though you probably want to use the bean libraries for that). There are a few other good ones:
1. Since Java didn't implement variable arguments until recently, reflection could be used to dynamically call a method with an unknown number of arguments. An example of this is JHDL which looks at a static array to get the number of wires to pass to the constructor, then uses any additional ints or Strings as configuration parameters.
2. Somewhat related to serialization, reflection is perfect for creating Object databases by dynamically saving field values to disk, and reloading the state.
3. Reflection can be used to take a multidimensional array and quicky flatten it for storage on disk, or redimensionalize it after you pull the flat array from disk. This only works because an array of any dimension can be cast to an Object (and vica-versa) allowing you to have only one method for any size array.
Javascript + Nintendo DSi = DSiCade
My advice? Use high-level languages and libraries. If your tools don't expose platform differences to you, there's no way you can make your code non-portable. As a bonus, you can also get garbage collection (which automagically gets rid of memory leaks), automatic allocation (no more buffer overruns), and structured composition of code (no more injection vulnerabilities). Also, the more high-level your language is, the less code you write, thus the fewer bugs you introduce and the more productive you get.
...
Of course, there are a few gotchas. Sometimes, you may actually want to do things at a lower level than the creators of your libraires thought you would. If your language is flexible enough, you shouldn't really have a problem getting at the lower levels (especially if the libraries you use are open source). It could also be that the language of your choice is too slow for a certain task (although there's nothing that makes high-level langauages necessarily slow). Fear not! Many high-level languages can interface with C code, so you can probably write parts in C, or even assembly if you need to. This can also solve the flexibility problem. For the rest, it's mostly a matter of seeing through the myths and picking the right language.
Some examples? OCaml, Common Lisp, Ruby, Scheme (with appropriate extensions), heck, even Java and C#, Perl, Python,
Please correct me if I got my facts wrong.
If you must write in C, use the Apache Portable Runtime.
Evolution is a fact. Darwinism is a joke.
Well, no, but it does require the class to expose a method that does the right thing. That isn't much different from the class implementing the right interface.
its not if its your code thats constructing the instances but its not always. Quite a few java libraries return arrays of objects and if you wan't to fill a combo box with that information you are going to have to convert it to strings. The tostring method might do what you wan't but it might not.
note: i'm known as plugwash most places but i screwd up registering that here somehow in the past and now can't register
I didn't say reflection wasn't useful -- it certainly is (as are C# Attributes, for that matter, which generalize the concept of metadata about types and objects being available at run as well as compile time).
But, I've seen it used way too often to take something that's been upcast to a base type, and selectively downcast it back into a type of interest, when the upcast is what's really wrong (and Java must have contributed to this, what with "generic" libraries returning Objects that then needed to be downcase, before Generics were added to the language).
The "smell" test for me is to see if the code that takes advantage of reflection, or other metadata about types and objects, can handle any values for the information it gets (or at least a large class of them), or just a few finite ones: i.e. a poorly coded open-coded case statement on type.
In general, what's missing in C++ has neen the ability for the compiler to pass knowledge it has about types and objects to the code it has compiled. C# fixes that, and Java does this by design (though far too often than necessary). Though, with C#, the separation between syntax and type has been become a bit to fuzzy for my liking: the use of foreach over an iterator is one example: the foreach syntax should be defined as a language extention as part of the definition of the iterator base class type -- Think Mary 2, if you want to look at languages with dynamic syntax.
You could've hired me.
... but that doesn't make the strongest case.
But see... Mozilla on AmigaOS... complaining the tables render "a little funny"... that's still...
anyway... cheers.
-pyrrho
There are many ways to Rome and there are many ways to get portable code. But when it comes to write full featured portable applications there isn't a better alternative than wyoGuide/wxWidgets (http://wyoguide.sf.net/, http://www.wxwidgets.org/).
Well show me how you do a simple (in unix) operation
to create a pipe , fork, redirect pipe to stdin/out then do
an exec in the child process , then have the parent do
a wait() & read/write on the child in win32? Go on , whats
the problem, its trivial isn't it?